📄 transport.c
字号:
/* re-initialize the mutex so that we avoid any races with * early/late IRQs from previous commands */ init_MUTEX_LOCKED(&(us->ip_waitq)); /* COMMAND STAGE */ /* let's send the command via the control pipe */ result = usb_stor_control_msg(us, usb_sndctrlpipe(us->pusb_dev,0), US_CBI_ADSC, USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0, us->ifnum, srb->cmnd, srb->cmd_len); /* check the return code for the command */ US_DEBUGP("Call to usb_stor_control_msg() returned %d\n", result); if (result < 0) { /* Reset flag for status notification */ atomic_set(us->ip_wanted, 0); /* if the command was aborted, indicate that */ if (result == -ENOENT) return USB_STOR_TRANSPORT_ABORTED; /* STALL must be cleared when they are detected */ if (result == -EPIPE) { US_DEBUGP("-- Stall on control pipe. Clearing\n"); result = usb_stor_clear_halt(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev, 0)); US_DEBUGP("-- usb_stor_clear_halt() returns %d\n", result); return USB_STOR_TRANSPORT_FAILED; } /* Uh oh... serious problem here */ return USB_STOR_TRANSPORT_ERROR; } /* DATA STAGE */ /* transfer the data payload for this command, if one exists*/ if (usb_stor_transfer_length(srb)) { usb_stor_transfer(srb, us); US_DEBUGP("CBI data stage result is 0x%x\n", srb->result); /* if it was aborted, we need to indicate that */ if (srb->result == USB_STOR_TRANSPORT_ABORTED) { return USB_STOR_TRANSPORT_ABORTED; } } /* STATUS STAGE */ /* go to sleep until we get this interrupt */ US_DEBUGP("Current value of ip_waitq is: %d\n", atomic_read(&us->ip_waitq.count)); down(&(us->ip_waitq)); /* if we were woken up by an abort instead of the actual interrupt */ if (atomic_read(us->ip_wanted)) { US_DEBUGP("Did not get interrupt on CBI\n"); atomic_set(us->ip_wanted, 0); return USB_STOR_TRANSPORT_ABORTED; } US_DEBUGP("Got interrupt data (0x%x, 0x%x)\n", us->irqdata[0], us->irqdata[1]); /* UFI gives us ASC and ASCQ, like a request sense * * REQUEST_SENSE and INQUIRY don't affect the sense data on UFI * devices, so we ignore the information for those commands. Note * that this means we could be ignoring a real error on these * commands, but that can't be helped. */ if (us->subclass == US_SC_UFI) { if (srb->cmnd[0] == REQUEST_SENSE || srb->cmnd[0] == INQUIRY) return USB_STOR_TRANSPORT_GOOD; else if (((unsigned char*)us->irq_urb->transfer_buffer)[0]) return USB_STOR_TRANSPORT_FAILED; else return USB_STOR_TRANSPORT_GOOD; } /* If not UFI, we interpret the data as a result code * The first byte should always be a 0x0 * The second byte & 0x0F should be 0x0 for good, otherwise error */ if (us->irqdata[0]) { US_DEBUGP("CBI IRQ data showed reserved bType %d\n", us->irqdata[0]); return USB_STOR_TRANSPORT_ERROR; } switch (us->irqdata[1] & 0x0F) { case 0x00: return USB_STOR_TRANSPORT_GOOD; case 0x01: return USB_STOR_TRANSPORT_FAILED; default: return USB_STOR_TRANSPORT_ERROR; } /* we should never get here, but if we do, we're in trouble */ return USB_STOR_TRANSPORT_ERROR;}/* * Control/Bulk transport */int usb_stor_CB_transport(Scsi_Cmnd *srb, struct us_data *us){ int result; /* COMMAND STAGE */ /* let's send the command via the control pipe */ result = usb_stor_control_msg(us, usb_sndctrlpipe(us->pusb_dev,0), US_CBI_ADSC, USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0, us->ifnum, srb->cmnd, srb->cmd_len); /* check the return code for the command */ US_DEBUGP("Call to usb_stor_control_msg() returned %d\n", result); if (result < 0) { /* if the command was aborted, indicate that */ if (result == -ENOENT) return USB_STOR_TRANSPORT_ABORTED; /* a stall is a fatal condition from the device */ if (result == -EPIPE) { US_DEBUGP("-- Stall on control pipe. Clearing\n"); result = usb_stor_clear_halt(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev, 0)); US_DEBUGP("-- usb_stor_clear_halt() returns %d\n", result); return USB_STOR_TRANSPORT_FAILED; } /* Uh oh... serious problem here */ return USB_STOR_TRANSPORT_ERROR; } /* DATA STAGE */ /* transfer the data payload for this command, if one exists*/ if (usb_stor_transfer_length(srb)) { usb_stor_transfer(srb, us); US_DEBUGP("CB data stage result is 0x%x\n", srb->result); /* if it was aborted, we need to indicate that */ if (srb->result == USB_STOR_TRANSPORT_ABORTED) return USB_STOR_TRANSPORT_ABORTED; } /* STATUS STAGE */ /* NOTE: CB does not have a status stage. Silly, I know. So * we have to catch this at a higher level. */ return USB_STOR_TRANSPORT_GOOD;}/* * Bulk only transport *//* Determine what the maximum LUN supported is */int usb_stor_Bulk_max_lun(struct us_data *us){ unsigned char data; int result; int pipe; /* issue the command */ pipe = usb_rcvctrlpipe(us->pusb_dev, 0); result = usb_control_msg(us->pusb_dev, pipe, US_BULK_GET_MAX_LUN, USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0, us->ifnum, &data, sizeof(data), HZ); US_DEBUGP("GetMaxLUN command result is %d, data is %d\n", result, data); /* if we have a successful request, return the result */ if (result == 1) return data; /* if we get a STALL, clear the stall */ if (result == -EPIPE) { US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); usb_stor_clear_halt(us->pusb_dev, pipe); } /* return the default -- no LUNs */ return 0;}int usb_stor_Bulk_reset(struct us_data *us);int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us){ struct bulk_cb_wrap bcb; struct bulk_cs_wrap bcs; int result; int pipe; int partial; /* if the device was removed, then we're already reset */ if (!us->pusb_dev) return SUCCESS; /* set up the command wrapper */ bcb.Signature = cpu_to_le32(US_BULK_CB_SIGN); bcb.DataTransferLength = cpu_to_le32(usb_stor_transfer_length(srb)); bcb.Flags = srb->sc_data_direction == SCSI_DATA_READ ? 1 << 7 : 0; bcb.Tag = srb->serial_number; bcb.Lun = srb->cmnd[1] >> 5; if (us->flags & US_FL_SCM_MULT_TARG) bcb.Lun |= srb->target << 4; bcb.Length = srb->cmd_len; /* construct the pipe handle */ pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out); /* copy the command payload */ memset(bcb.CDB, 0, sizeof(bcb.CDB)); memcpy(bcb.CDB, srb->cmnd, bcb.Length); /* send it to out endpoint */ US_DEBUGP("Bulk command S 0x%x T 0x%x Trg %d LUN %d L %d F %d CL %d\n", le32_to_cpu(bcb.Signature), bcb.Tag, (bcb.Lun >> 4), (bcb.Lun & 0x0F), bcb.DataTransferLength, bcb.Flags, bcb.Length); result = usb_stor_bulk_msg(us, &bcb, pipe, US_BULK_CB_WRAP_LEN, &partial); US_DEBUGP("Bulk command transfer result=%d\n", result); /* if the command was aborted, indicate that */ if (result == -ENOENT) return USB_STOR_TRANSPORT_ABORTED; /* if we stall, we need to clear it before we go on */ if (result == -EPIPE) { US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); usb_stor_clear_halt(us->pusb_dev, pipe); } else if (result) { /* unknown error -- we've got a problem */ return USB_STOR_TRANSPORT_ERROR; } /* if the command transfered well, then we go to the data stage */ if (result == 0) { /* send/receive data payload, if there is any */ if (bcb.DataTransferLength) { usb_stor_transfer(srb, us); US_DEBUGP("Bulk data transfer result 0x%x\n", srb->result); /* if it was aborted, we need to indicate that */ if (srb->result == USB_STOR_TRANSPORT_ABORTED) return USB_STOR_TRANSPORT_ABORTED; } } /* See flow chart on pg 15 of the Bulk Only Transport spec for * an explanation of how this code works. */ /* construct the pipe handle */ pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in); /* get CSW for device status */ US_DEBUGP("Attempting to get CSW...\n"); result = usb_stor_bulk_msg(us, &bcs, pipe, US_BULK_CS_WRAP_LEN, &partial); /* if the command was aborted, indicate that */ if (result == -ENOENT) return USB_STOR_TRANSPORT_ABORTED; /* did the attempt to read the CSW fail? */ if (result == -EPIPE) { US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); usb_stor_clear_halt(us->pusb_dev, pipe); /* get the status again */ US_DEBUGP("Attempting to get CSW (2nd try)...\n"); result = usb_stor_bulk_msg(us, &bcs, pipe, US_BULK_CS_WRAP_LEN, &partial); /* if the command was aborted, indicate that */ if (result == -ENOENT) return USB_STOR_TRANSPORT_ABORTED; /* if it fails again, we need a reset and return an error*/ if (result == -EPIPE) { US_DEBUGP("clearing halt for pipe 0x%x\n", pipe); usb_stor_clear_halt(us->pusb_dev, pipe); return USB_STOR_TRANSPORT_ERROR; } } /* if we still have a failure at this point, we're in trouble */ US_DEBUGP("Bulk status result = %d\n", result); if (result) { return USB_STOR_TRANSPORT_ERROR; } /* check bulk status */ US_DEBUGP("Bulk status Sig 0x%x T 0x%x R %d Stat 0x%x\n", le32_to_cpu(bcs.Signature), bcs.Tag, bcs.Residue, bcs.Status); if (bcs.Signature != cpu_to_le32(US_BULK_CS_SIGN) ||#if !defined(CONFIG_USB_UHCI124) && !defined(CONFIG_USB_UHCI124_MODULE) bcs.Tag != bcb.Tag || #else ((bcs.Tag != bcb.Tag) && !(us->flags & US_FL_QUIRKS_TAG)) ||#endif bcs.Status > US_BULK_STAT_PHASE || partial != 13) { US_DEBUGP("Bulk logical error\n"); return USB_STOR_TRANSPORT_ERROR; } /* based on the status code, we report good or bad */ switch (bcs.Status) { case US_BULK_STAT_OK: /* command good -- note that data could be short */ return USB_STOR_TRANSPORT_GOOD; case US_BULK_STAT_FAIL: /* command failed */ return USB_STOR_TRANSPORT_FAILED; case US_BULK_STAT_PHASE: /* phase error -- note that a transport reset will be * invoked by the invoke_transport() function */ return USB_STOR_TRANSPORT_ERROR; } /* we should never get here, but if we do, we're in trouble */ return USB_STOR_TRANSPORT_ERROR;}/*********************************************************************** * Reset routines ***********************************************************************//* This issues a CB[I] Reset to the device in question */int usb_stor_CB_reset(struct us_data *us){ unsigned char cmd[12]; int result; US_DEBUGP("CB_reset() called\n"); /* if the device was removed, then we're already reset */ if (!us->pusb_dev) return SUCCESS; memset(cmd, 0xFF, sizeof(cmd)); cmd[0] = SEND_DIAGNOSTIC; cmd[1] = 4; result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0), US_CBI_ADSC, USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0, us->ifnum, cmd, sizeof(cmd), HZ*5); if (result < 0) { US_DEBUGP("CB[I] soft reset failed %d\n", result); return FAILED; } /* long wait for reset */ set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(HZ*6); set_current_state(TASK_RUNNING); US_DEBUGP("CB_reset: clearing endpoint halt\n"); usb_stor_clear_halt(us->pusb_dev, usb_rcvbulkpipe(us->pusb_dev, us->ep_in)); usb_stor_clear_halt(us->pusb_dev, usb_rcvbulkpipe(us->pusb_dev, us->ep_out)); US_DEBUGP("CB_reset done\n"); /* return a result code based on the result of the control message */ return SUCCESS;}/* This issues a Bulk-only Reset to the device in question, including * clearing the subsequent endpoint halts that may occur. */int usb_stor_Bulk_reset(struct us_data *us){ int result; US_DEBUGP("Bulk reset requested\n"); /* if the device was removed, then we're already reset */ if (!us->pusb_dev) return SUCCESS; result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0), US_BULK_RESET_REQUEST, USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0, us->ifnum, NULL, 0, HZ*5); if (result < 0) { US_DEBUGP("Bulk soft reset failed %d\n", result); return FAILED; } /* long wait for reset */ set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(HZ*6); set_current_state(TASK_RUNNING); usb_stor_clear_halt(us->pusb_dev, usb_rcvbulkpipe(us->pusb_dev, us->ep_in)); usb_stor_clear_halt(us->pusb_dev, usb_sndbulkpipe(us->pusb_dev, us->ep_out)); US_DEBUGP("Bulk soft reset completed\n"); return SUCCESS;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -