/* First stage of disconnect processing: stop all commands and remove * the host */ static void quiesce_and_remove_host(struct rtsx_dev *dev) { struct Scsi_Host *host = rtsx_to_host(dev); struct rtsx_chip *chip = dev->chip; /* Prevent new transfers, stop the current command, and * interrupt a SCSI-scan or device-reset delay */ mutex_lock(&dev->dev_mutex); scsi_lock(host); rtsx_set_stat(chip, RTSX_STAT_DISCONNECT); scsi_unlock(host); mutex_unlock(&dev->dev_mutex); wake_up(&dev->delay_wait); wait_for_completion(&dev->scanning_done); /* Wait some time to let other threads exist */ wait_timeout(100); /* queuecommand won't accept any new commands and the control * thread won't execute a previously-queued command. If there * is such a command pending, complete it with an error. */ mutex_lock(&dev->dev_mutex); if (chip->srb) { chip->srb->result = DID_NO_CONNECT << 16; scsi_lock(host); chip->srb->scsi_done(dev->chip->srb); chip->srb = NULL; scsi_unlock(host); } mutex_unlock(&dev->dev_mutex); /* Now we own no commands so it's safe to remove the SCSI host */ scsi_remove_host(host); }
/* This is always called with scsi_lock(srb->host) held */ static int device_reset(struct scsi_cmnd *srb) { struct us_data *us = host_to_us(srb->device->host); int result; US_DEBUGP("%s called\n", __FUNCTION__); if (us->sm_state != US_STATE_IDLE) { printk(KERN_ERR USB_STORAGE "Error in %s: " "invalid state %d\n", __FUNCTION__, us->sm_state); return FAILED; } /* set the state and release the lock */ us->sm_state = US_STATE_RESETTING; scsi_unlock(us_to_host(us)); /* lock the device pointers and do the reset */ down(&(us->dev_semaphore)); if (test_bit(US_FLIDX_DISCONNECTING, &us->flags)) { result = FAILED; US_DEBUGP("No reset during disconnect\n"); } else result = us->transport_reset(us); up(&(us->dev_semaphore)); /* lock access to the state and clear it */ scsi_lock(us_to_host(us)); us->sm_state = US_STATE_IDLE; return result; }
static void quiesce_and_remove_host(struct us_data *us) { struct Scsi_Host *host = us_to_host(us); //--------------------------- pr_info("17 quiesce and remove host\n"); /* If the device is really gone, cut short reset delays */ if (us->pusb_dev->state == USB_STATE_NOTATTACHED) { set_bit(US_FLIDX_DISCONNECTING, &us->dflags); wake_up(&us->delay_wait); } /* Prevent SCSI scanning (if it hasn't started yet) * or wait for the SCSI-scanning routine to stop. */ cancel_delayed_work_sync(&us->scan_dwork); /* Balance autopm calls if scanning was cancelled */ if (test_bit(US_FLIDX_SCAN_PENDING, &us->dflags)) usb_autopm_put_interface_no_suspend(us->pusb_intf); /* Removing the host will perform an orderly shutdown: caches * synchronized, disks spun down, etc. */ scsi_remove_host(host); /* Prevent any new commands from being accepted and cut short * reset delays. */ scsi_lock(host); set_bit(US_FLIDX_DISCONNECTING, &us->dflags); scsi_unlock(host); wake_up(&us->delay_wait); }
/* Command timeout and abort */ static int command_abort(struct scsi_cmnd *srb) { struct us_data *us = host_to_us(srb->device->host); US_DEBUGP("%s called\n", __FUNCTION__); /* us->srb together with the TIMED_OUT, RESETTING, and ABORTING * bits are protected by the host lock. */ scsi_lock(us_to_host(us)); /* Is this command still active? */ if (us->srb != srb) { scsi_unlock(us_to_host(us)); US_DEBUGP ("-- nothing to abort\n"); return FAILED; } /* Set the TIMED_OUT bit. Also set the ABORTING bit, but only if * a device reset isn't already in progress (to avoid interfering * with the reset). Note that we must retain the host lock while * calling usb_stor_stop_transport(); otherwise it might interfere * with an auto-reset that begins as soon as we release the lock. */ set_bit(US_FLIDX_TIMED_OUT, &us->flags); if (!test_bit(US_FLIDX_RESETTING, &us->flags)) { set_bit(US_FLIDX_ABORTING, &us->flags); usb_stor_stop_transport(us); } scsi_unlock(us_to_host(us)); /* Wait for the aborted command to finish */ wait_for_completion(&us->notify); return SUCCESS; }
/* Command timeout and abort */ static int command_abort(struct scsi_cmnd *srb) { struct Scsi_Host *host = srb->device->host; struct rtsx_dev *dev = host_to_rtsx(host); struct rtsx_chip *chip = dev->chip; dev_info(&dev->pci->dev, "%s called\n", __func__); scsi_lock(host); /* Is this command still active? */ if (chip->srb != srb) { scsi_unlock(host); dev_info(&dev->pci->dev, "-- nothing to abort\n"); return FAILED; } rtsx_set_stat(chip, RTSX_STAT_ABORT); scsi_unlock(host); /* Wait for the aborted command to finish */ wait_for_completion(&dev->notify); return SUCCESS; }
static int command_abort(struct scsi_cmnd *srb) { struct Scsi_Host *host = srb->device->host; struct rtsx_dev *dev = host_to_rtsx(host); struct rtsx_chip *chip = dev->chip; printk(KERN_INFO "%s called\n", __FUNCTION__); scsi_lock(host); if (chip->srb != srb) { scsi_unlock(host); printk(KERN_INFO "-- nothing to abort\n"); return FAILED; } rtsx_set_stat(chip, RTSX_STAT_ABORT); scsi_unlock(host); wait_for_completion(&dev->notify); return SUCCESS; }
/* Report a driver-initiated bus reset to the SCSI layer. * Calling this for a SCSI-initiated reset is unnecessary but harmless. * The caller must not own the SCSI host lock. */ void usb_stor_report_bus_reset(struct us_data *us) { struct Scsi_Host *host = us_to_host(us); scsi_lock(host); scsi_report_bus_reset(host, 0); scsi_unlock(host); }
/* This is the common part of the device reset code. * * It's handy that every transport mechanism uses the control endpoint for * resets. * * Basically, we send a reset with a 20-second timeout, so we don't get * jammed attempting to do the reset. */ static int usb_stor_reset_common(struct us_data *us, u8 request, u8 requesttype, u16 value, u16 index, void *data, u16 size) { int result; int result2; int rc = FAILED; /* Let the SCSI layer know we are doing a reset, set the * RESETTING bit, and clear the ABORTING bit so that the reset * may proceed. */ scsi_lock(us_to_host(us)); usb_stor_report_device_reset(us); set_bit(US_FLIDX_RESETTING, &us->flags); clear_bit(US_FLIDX_ABORTING, &us->flags); scsi_unlock(us_to_host(us)); /* A 20-second timeout may seem rather long, but a LaCie * StudioDrive USB2 device takes 16+ seconds to get going * following a powerup or USB attach event. */ result = usb_stor_control_msg(us, us->send_ctrl_pipe, request, requesttype, value, index, data, size, 20*HZ); if (result < 0) { US_DEBUGP("Soft reset failed: %d\n", result); goto Done; } /* Give the device some time to recover from the reset, * but don't delay disconnect processing. */ wait_event_interruptible_timeout(us->delay_wait, test_bit(US_FLIDX_DISCONNECTING, &us->flags), HZ*6); if (test_bit(US_FLIDX_DISCONNECTING, &us->flags)) { US_DEBUGP("Reset interrupted by disconnect\n"); goto Done; } US_DEBUGP("Soft reset: clearing bulk-in endpoint halt\n"); result = usb_stor_clear_halt(us, us->recv_bulk_pipe); US_DEBUGP("Soft reset: clearing bulk-out endpoint halt\n"); result2 = usb_stor_clear_halt(us, us->send_bulk_pipe); /* return a result code based on the result of the control message */ if (result < 0 || result2 < 0) { US_DEBUGP("Soft reset failed\n"); goto Done; } US_DEBUGP("Soft reset done\n"); rc = SUCCESS; Done: clear_bit(US_FLIDX_RESETTING, &us->flags); return rc; }
/* This is always called with scsi_lock(srb->host) held */ static int bus_reset(struct scsi_cmnd *srb) { struct us_data *us = host_to_us(srb->device->host); int result; US_DEBUGP("%s called\n", __FUNCTION__); if (us->sm_state != US_STATE_IDLE) { printk(KERN_ERR USB_STORAGE "Error in %s: " "invalid state %d\n", __FUNCTION__, us->sm_state); return FAILED; } /* set the state and release the lock */ us->sm_state = US_STATE_RESETTING; scsi_unlock(us_to_host(us)); /* The USB subsystem doesn't handle synchronisation between * a device's several drivers. Therefore we reset only devices * with just one interface, which we of course own. */ down(&(us->dev_semaphore)); if (test_bit(US_FLIDX_DISCONNECTING, &us->flags)) { result = -EIO; US_DEBUGP("No reset during disconnect\n"); } else if (us->pusb_dev->actconfig->desc.bNumInterfaces != 1) { result = -EBUSY; US_DEBUGP("Refusing to reset a multi-interface device\n"); } else { /* * The lock can be taken when khubd is executing scsi_scan() * at the very tail of our ->probe routine. * If a device fails there, it has to be replugged. */ result = usb_reset_device_trylock(us->pusb_dev); US_DEBUGP("usb_reset_device returns %d\n", result); } up(&(us->dev_semaphore)); /* lock access to the state and clear it */ scsi_lock(us_to_host(us)); us->sm_state = US_STATE_IDLE; /* We must return succes, or else the device is offlined forever */ if (result < 0) { printk(KERN_NOTICE USB_STORAGE "Bus reset ended with %d\n", result); } return SUCCESS; }
/* This is always called with scsi_lock(srb->host) held */ static int command_abort(struct scsi_cmnd *srb ) { struct us_data *us = host_to_us(srb->device->host); US_DEBUGP("%s called\n", __FUNCTION__); /* Is this command still active? */ if (us->srb != srb) { US_DEBUGP ("-- nothing to abort\n"); return FAILED; } /* Normally the current state is RUNNING. If the control thread * hasn't even started processing this command, the state will be * IDLE. Anything else is a bug. */ if (us->sm_state != US_STATE_RUNNING && us->sm_state != US_STATE_IDLE) { printk(KERN_ERR USB_STORAGE "Error in %s: " "invalid state %d\n", __FUNCTION__, us->sm_state); return FAILED; } /* Set state to ABORTING and set the ABORTING bit, but only if * a device reset isn't already in progress (to avoid interfering * with the reset). To prevent races with auto-reset, we must * stop any ongoing USB transfers while still holding the host * lock. */ us->sm_state = US_STATE_ABORTING; if (!test_bit(US_FLIDX_RESETTING, &us->flags)) { set_bit(US_FLIDX_ABORTING, &us->flags); usb_stor_stop_transport(us); } scsi_unlock(us_to_host(us)); /* Wait for the aborted command to finish */ wait_for_completion(&us->notify); /* Reacquire the lock and allow USB transfers to resume */ scsi_lock(us_to_host(us)); clear_bit(US_FLIDX_ABORTING, &us->flags); return SUCCESS; }
static void quiesce_and_remove_host(struct rts51x_chip *chip) { struct rts51x_usb *rts51x = chip->usb; struct Scsi_Host *host = rts51x_to_host(chip); if (rts51x->pusb_dev->state == USB_STATE_NOTATTACHED) set_bit(FLIDX_DISCONNECTING, &rts51x->dflags); #ifdef SCSI_SCAN_DELAY set_bit(FLIDX_DONT_SCAN, &rts51x->dflags); wake_up(&rts51x->delay_wait); wait_for_completion(&rts51x->scanning_done); #endif scsi_remove_host(host); scsi_lock(host); set_bit(FLIDX_DISCONNECTING, &rts51x->dflags); scsi_unlock(host); #ifdef SCSI_SCAN_DELAY wake_up(&rts51x->delay_wait); #endif }
/* Invoke the transport and basic error-handling/recovery methods * * This is used by the protocol layers to actually send the message to * the device and receive the response. */ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us) { int need_auto_sense; int result; /* send the command to the transport layer */ scsi_set_resid(srb, 0); result = us->transport(srb, us); /* if the command gets aborted by the higher layers, we need to * short-circuit all other processing */ if (test_bit(US_FLIDX_TIMED_OUT, &us->dflags)) { US_DEBUGP("-- command was aborted\n"); srb->result = DID_ABORT << 16; goto Handle_Errors; } /* if there is a transport error, reset and don't auto-sense */ if (result == USB_STOR_TRANSPORT_ERROR) { US_DEBUGP("-- transport indicates error, resetting\n"); srb->result = DID_ERROR << 16; goto Handle_Errors; } /* if the transport provided its own sense data, don't auto-sense */ if (result == USB_STOR_TRANSPORT_NO_SENSE) { srb->result = SAM_STAT_CHECK_CONDITION; last_sector_hacks(us, srb); return; } srb->result = SAM_STAT_GOOD; /* Determine if we need to auto-sense * * I normally don't use a flag like this, but it's almost impossible * to understand what's going on here if I don't. */ need_auto_sense = 0; /* * If we're running the CB transport, which is incapable * of determining status on its own, we will auto-sense * unless the operation involved a data-in transfer. Devices * can signal most data-in errors by stalling the bulk-in pipe. */ if ((us->protocol == USB_PR_CB || us->protocol == USB_PR_DPCM_USB) && srb->sc_data_direction != DMA_FROM_DEVICE) { US_DEBUGP("-- CB transport device requiring auto-sense\n"); need_auto_sense = 1; } /* * If we have a failure, we're going to do a REQUEST_SENSE * automatically. Note that we differentiate between a command * "failure" and an "error" in the transport mechanism. */ if (result == USB_STOR_TRANSPORT_FAILED) { US_DEBUGP("-- transport indicates command failure\n"); need_auto_sense = 1; } /* * Determine if this device is SAT by seeing if the * command executed successfully. Otherwise we'll have * to wait for at least one CHECK_CONDITION to determine * SANE_SENSE support */ if (unlikely((srb->cmnd[0] == ATA_16 || srb->cmnd[0] == ATA_12) && result == USB_STOR_TRANSPORT_GOOD && !(us->fflags & US_FL_SANE_SENSE) && !(us->fflags & US_FL_BAD_SENSE) && !(srb->cmnd[2] & 0x20))) { US_DEBUGP("-- SAT supported, increasing auto-sense\n"); us->fflags |= US_FL_SANE_SENSE; } /* * A short transfer on a command where we don't expect it * is unusual, but it doesn't mean we need to auto-sense. */ if ((scsi_get_resid(srb) > 0) && !((srb->cmnd[0] == REQUEST_SENSE) || (srb->cmnd[0] == INQUIRY) || (srb->cmnd[0] == MODE_SENSE) || (srb->cmnd[0] == LOG_SENSE) || (srb->cmnd[0] == MODE_SENSE_10))) { US_DEBUGP("-- unexpectedly short transfer\n"); } /* Now, if we need to do the auto-sense, let's do it */ if (need_auto_sense) { int temp_result; struct scsi_eh_save ses; int sense_size = US_SENSE_SIZE; struct scsi_sense_hdr sshdr; const u8 *scdd; u8 fm_ili; /* device supports and needs bigger sense buffer */ if (us->fflags & US_FL_SANE_SENSE) sense_size = ~0; Retry_Sense: US_DEBUGP("Issuing auto-REQUEST_SENSE\n"); scsi_eh_prep_cmnd(srb, &ses, NULL, 0, sense_size); /* FIXME: we must do the protocol translation here */ if (us->subclass == USB_SC_RBC || us->subclass == USB_SC_SCSI || us->subclass == USB_SC_CYP_ATACB) srb->cmd_len = 6; else srb->cmd_len = 12; /* issue the auto-sense command */ scsi_set_resid(srb, 0); temp_result = us->transport(us->srb, us); /* let's clean up right away */ scsi_eh_restore_cmnd(srb, &ses); if (test_bit(US_FLIDX_TIMED_OUT, &us->dflags)) { US_DEBUGP("-- auto-sense aborted\n"); srb->result = DID_ABORT << 16; /* If SANE_SENSE caused this problem, disable it */ if (sense_size != US_SENSE_SIZE) { us->fflags &= ~US_FL_SANE_SENSE; us->fflags |= US_FL_BAD_SENSE; } goto Handle_Errors; } /* Some devices claim to support larger sense but fail when * trying to request it. When a transport failure happens * using US_FS_SANE_SENSE, we always retry with a standard * (small) sense request. This fixes some USB GSM modems */ if (temp_result == USB_STOR_TRANSPORT_FAILED && sense_size != US_SENSE_SIZE) { US_DEBUGP("-- auto-sense failure, retry small sense\n"); sense_size = US_SENSE_SIZE; us->fflags &= ~US_FL_SANE_SENSE; us->fflags |= US_FL_BAD_SENSE; goto Retry_Sense; } /* Other failures */ if (temp_result != USB_STOR_TRANSPORT_GOOD) { US_DEBUGP("-- auto-sense failure\n"); /* we skip the reset if this happens to be a * multi-target device, since failure of an * auto-sense is perfectly valid */ srb->result = DID_ERROR << 16; if (!(us->fflags & US_FL_SCM_MULT_TARG)) goto Handle_Errors; return; } /* If the sense data returned is larger than 18-bytes then we * assume this device supports requesting more in the future. * The response code must be 70h through 73h inclusive. */ if (srb->sense_buffer[7] > (US_SENSE_SIZE - 8) && !(us->fflags & US_FL_SANE_SENSE) && !(us->fflags & US_FL_BAD_SENSE) && (srb->sense_buffer[0] & 0x7C) == 0x70) { US_DEBUGP("-- SANE_SENSE support enabled\n"); us->fflags |= US_FL_SANE_SENSE; /* Indicate to the user that we truncated their sense * because we didn't know it supported larger sense. */ US_DEBUGP("-- Sense data truncated to %i from %i\n", US_SENSE_SIZE, srb->sense_buffer[7] + 8); srb->sense_buffer[7] = (US_SENSE_SIZE - 8); } scsi_normalize_sense(srb->sense_buffer, SCSI_SENSE_BUFFERSIZE, &sshdr); US_DEBUGP("-- Result from auto-sense is %d\n", temp_result); US_DEBUGP("-- code: 0x%x, key: 0x%x, ASC: 0x%x, ASCQ: 0x%x\n", sshdr.response_code, sshdr.sense_key, sshdr.asc, sshdr.ascq); #ifdef CONFIG_USB_STORAGE_DEBUG usb_stor_show_sense(sshdr.sense_key, sshdr.asc, sshdr.ascq); #endif /* set the result so the higher layers expect this data */ srb->result = SAM_STAT_CHECK_CONDITION; scdd = scsi_sense_desc_find(srb->sense_buffer, SCSI_SENSE_BUFFERSIZE, 4); fm_ili = (scdd ? scdd[3] : srb->sense_buffer[2]) & 0xA0; /* We often get empty sense data. This could indicate that * everything worked or that there was an unspecified * problem. We have to decide which. */ if (sshdr.sense_key == 0 && sshdr.asc == 0 && sshdr.ascq == 0 && fm_ili == 0) { /* If things are really okay, then let's show that. * Zero out the sense buffer so the higher layers * won't realize we did an unsolicited auto-sense. */ if (result == USB_STOR_TRANSPORT_GOOD) { srb->result = SAM_STAT_GOOD; srb->sense_buffer[0] = 0x0; /* If there was a problem, report an unspecified * hardware error to prevent the higher layers from * entering an infinite retry loop. */ } else { srb->result = DID_ERROR << 16; if ((sshdr.response_code & 0x72) == 0x72) srb->sense_buffer[1] = HARDWARE_ERROR; else srb->sense_buffer[2] = HARDWARE_ERROR; } } } /* * Some devices don't work or return incorrect data the first * time they get a READ(10) command, or for the first READ(10) * after a media change. If the INITIAL_READ10 flag is set, * keep track of whether READ(10) commands succeed. If the * previous one succeeded and this one failed, set the REDO_READ10 * flag to force a retry. */ if (unlikely((us->fflags & US_FL_INITIAL_READ10) && srb->cmnd[0] == READ_10)) { if (srb->result == SAM_STAT_GOOD) { set_bit(US_FLIDX_READ10_WORKED, &us->dflags); } else if (test_bit(US_FLIDX_READ10_WORKED, &us->dflags)) { clear_bit(US_FLIDX_READ10_WORKED, &us->dflags); set_bit(US_FLIDX_REDO_READ10, &us->dflags); } /* * Next, if the REDO_READ10 flag is set, return a result * code that will cause the SCSI core to retry the READ(10) * command immediately. */ if (test_bit(US_FLIDX_REDO_READ10, &us->dflags)) { clear_bit(US_FLIDX_REDO_READ10, &us->dflags); srb->result = DID_IMM_RETRY << 16; srb->sense_buffer[0] = 0; } } /* Did we transfer less than the minimum amount required? */ if ((srb->result == SAM_STAT_GOOD || srb->sense_buffer[2] == 0) && scsi_bufflen(srb) - scsi_get_resid(srb) < srb->underflow) srb->result = DID_ERROR << 16; last_sector_hacks(us, srb); return; /* Error and abort processing: try to resynchronize with the device * by issuing a port reset. If that fails, try a class-specific * device reset. */ Handle_Errors: /* Set the RESETTING bit, and clear the ABORTING bit so that * the reset may proceed. */ scsi_lock(us_to_host(us)); set_bit(US_FLIDX_RESETTING, &us->dflags); clear_bit(US_FLIDX_ABORTING, &us->dflags); scsi_unlock(us_to_host(us)); /* We must release the device lock because the pre_reset routine * will want to acquire it. */ mutex_unlock(&us->dev_mutex); result = usb_stor_port_reset(us); mutex_lock(&us->dev_mutex); if (result < 0) { scsi_lock(us_to_host(us)); usb_stor_report_device_reset(us); scsi_unlock(us_to_host(us)); us->transport_reset(us); } clear_bit(US_FLIDX_RESETTING, &us->dflags); last_sector_hacks(us, srb); }
/* * ENE_stor_invoke_transport() */ void ENE_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us) { int result = 0; /* pr_info("transport --- ENE_stor_invoke_transport\n"); */ usb_stor_print_cmd(srb); /* send the command to the transport layer */ scsi_set_resid(srb, 0); if (!(us->MS_Status.Ready || us->SM_Status.Ready)) result = ENE_InitMedia(us); if (us->Power_IsResum == true) { result = ENE_InitMedia(us); us->Power_IsResum = false; } if (us->MS_Status.Ready) result = MS_SCSIIrp(us, srb); if (us->SM_Status.Ready) result = SM_SCSIIrp(us, srb); /* if the command gets aborted by the higher layers, we need to short-circuit all other processing */ if (test_bit(US_FLIDX_TIMED_OUT, &us->dflags)) { /* pr_info("-- command was aborted\n"); */ srb->result = DID_ABORT << 16; goto Handle_Errors; } /* if there is a transport error, reset and don't auto-sense */ if (result == USB_STOR_TRANSPORT_ERROR) { /* pr_info("-- transport indicates error, resetting\n"); */ srb->result = DID_ERROR << 16; goto Handle_Errors; } /* if the transport provided its own sense data, don't auto-sense */ if (result == USB_STOR_TRANSPORT_NO_SENSE) { srb->result = SAM_STAT_CHECK_CONDITION; return; } srb->result = SAM_STAT_GOOD; if (result == USB_STOR_TRANSPORT_FAILED) { /* pr_info("-- transport indicates command failure\n"); */ /* need_auto_sense = 1; */ BuildSenseBuffer(srb, us->SrbStatus); srb->result = SAM_STAT_CHECK_CONDITION; } /* Did we transfer less than the minimum amount required? */ if (srb->result == SAM_STAT_GOOD && scsi_bufflen(srb) - scsi_get_resid(srb) < srb->underflow) srb->result = (DID_ERROR << 16); /* v02 | (SUGGEST_RETRY << 24); */ return; Handle_Errors: scsi_lock(us_to_host(us)); set_bit(US_FLIDX_RESETTING, &us->dflags); clear_bit(US_FLIDX_ABORTING, &us->dflags); scsi_unlock(us_to_host(us)); mutex_unlock(&us->dev_mutex); result = usb_stor_port_reset(us); mutex_lock(&us->dev_mutex); if (result < 0) { scsi_lock(us_to_host(us)); usb_stor_report_device_reset(us); scsi_unlock(us_to_host(us)); us->transport_reset(us); } clear_bit(US_FLIDX_RESETTING, &us->dflags); }
/* * usb_stor_invoke_transport() */ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us) { int need_auto_sense; int result; /* pr_info("transport --- usb_stor_invoke_transport\n"); */ usb_stor_print_cmd(srb); /* send the command to the transport layer */ scsi_set_resid(srb, 0); result = us->transport(srb, us); /* usb_stor_Bulk_transport; */ /* if the command gets aborted by the higher layers, we need to short-circuit all other processing */ if (test_bit(US_FLIDX_TIMED_OUT, &us->dflags)) { /* pr_info("-- command was aborted\n"); */ srb->result = DID_ABORT << 16; goto Handle_Errors; } /* if there is a transport error, reset and don't auto-sense */ if (result == USB_STOR_TRANSPORT_ERROR) { /* pr_info("-- transport indicates error, resetting\n"); */ srb->result = DID_ERROR << 16; goto Handle_Errors; } /* if the transport provided its own sense data, don't auto-sense */ if (result == USB_STOR_TRANSPORT_NO_SENSE) { srb->result = SAM_STAT_CHECK_CONDITION; return; } srb->result = SAM_STAT_GOOD; /* Determine if we need to auto-sense */ need_auto_sense = 0; if ((us->protocol == USB_PR_CB || us->protocol == USB_PR_DPCM_USB) && srb->sc_data_direction != DMA_FROM_DEVICE) { /* pr_info("-- CB transport device requiring auto-sense\n"); */ need_auto_sense = 1; } if (result == USB_STOR_TRANSPORT_FAILED) { /* pr_info("-- transport indicates command failure\n"); */ need_auto_sense = 1; } /* Now, if we need to do the auto-sense, let's do it */ if (need_auto_sense) { int temp_result; struct scsi_eh_save ses; pr_info("Issuing auto-REQUEST_SENSE\n"); scsi_eh_prep_cmnd(srb, &ses, NULL, 0, US_SENSE_SIZE); /* we must do the protocol translation here */ if (us->subclass == USB_SC_RBC || us->subclass == USB_SC_SCSI || us->subclass == USB_SC_CYP_ATACB) { srb->cmd_len = 6; } else { srb->cmd_len = 12; } /* issue the auto-sense command */ scsi_set_resid(srb, 0); temp_result = us->transport(us->srb, us); /* let's clean up right away */ scsi_eh_restore_cmnd(srb, &ses); if (test_bit(US_FLIDX_TIMED_OUT, &us->dflags)) { /* pr_info("-- auto-sense aborted\n"); */ srb->result = DID_ABORT << 16; goto Handle_Errors; } if (temp_result != USB_STOR_TRANSPORT_GOOD) { /* pr_info("-- auto-sense failure\n"); */ srb->result = DID_ERROR << 16; if (!(us->fflags & US_FL_SCM_MULT_TARG)) goto Handle_Errors; return; } /* set the result so the higher layers expect this data */ srb->result = SAM_STAT_CHECK_CONDITION; if (result == USB_STOR_TRANSPORT_GOOD && (srb->sense_buffer[2] & 0xaf) == 0 && srb->sense_buffer[12] == 0 && srb->sense_buffer[13] == 0) { srb->result = SAM_STAT_GOOD; srb->sense_buffer[0] = 0x0; } } /* Did we transfer less than the minimum amount required? */ if (srb->result == SAM_STAT_GOOD && scsi_bufflen(srb) - scsi_get_resid(srb) < srb->underflow) srb->result = (DID_ERROR << 16); /* v02 | (SUGGEST_RETRY << 24); */ return; Handle_Errors: scsi_lock(us_to_host(us)); set_bit(US_FLIDX_RESETTING, &us->dflags); clear_bit(US_FLIDX_ABORTING, &us->dflags); scsi_unlock(us_to_host(us)); mutex_unlock(&us->dev_mutex); result = usb_stor_port_reset(us); mutex_lock(&us->dev_mutex); if (result < 0) { scsi_lock(us_to_host(us)); usb_stor_report_device_reset(us); scsi_unlock(us_to_host(us)); us->transport_reset(us); } clear_bit(US_FLIDX_RESETTING, &us->dflags); }
static int rtsx_control_thread(void *__dev) { struct rtsx_dev *dev = __dev; struct rtsx_chip *chip = dev->chip; struct Scsi_Host *host = rtsx_to_host(dev); for (;;) { if (wait_for_completion_interruptible(&dev->cmnd_ready)) break; /* lock the device pointers */ mutex_lock(&(dev->dev_mutex)); /* if the device has disconnected, we are free to exit */ if (rtsx_chk_stat(chip, RTSX_STAT_DISCONNECT)) { dev_info(&dev->pci->dev, "-- rtsx-control exiting\n"); mutex_unlock(&dev->dev_mutex); break; } /* lock access to the state */ scsi_lock(host); /* has the command aborted ? */ if (rtsx_chk_stat(chip, RTSX_STAT_ABORT)) { chip->srb->result = DID_ABORT << 16; goto SkipForAbort; } scsi_unlock(host); /* reject the command if the direction indicator * is UNKNOWN */ if (chip->srb->sc_data_direction == DMA_BIDIRECTIONAL) { dev_err(&dev->pci->dev, "UNKNOWN data direction\n"); chip->srb->result = DID_ERROR << 16; } /* reject if target != 0 or if LUN is higher than * the maximum known LUN */ else if (chip->srb->device->id) { dev_err(&dev->pci->dev, "Bad target number (%d:%d)\n", chip->srb->device->id, (u8)chip->srb->device->lun); chip->srb->result = DID_BAD_TARGET << 16; } else if (chip->srb->device->lun > chip->max_lun) { dev_err(&dev->pci->dev, "Bad LUN (%d:%d)\n", chip->srb->device->id, (u8)chip->srb->device->lun); chip->srb->result = DID_BAD_TARGET << 16; } /* we've got a command, let's do it! */ else { scsi_show_command(chip); rtsx_invoke_transport(chip->srb, chip); } /* lock access to the state */ scsi_lock(host); /* did the command already complete because of a disconnect? */ if (!chip->srb) ; /* nothing to do */ /* indicate that the command is done */ else if (chip->srb->result != DID_ABORT << 16) { chip->srb->scsi_done(chip->srb); } else { SkipForAbort: dev_err(&dev->pci->dev, "scsi command aborted\n"); } if (rtsx_chk_stat(chip, RTSX_STAT_ABORT)) { complete(&(dev->notify)); rtsx_set_stat(chip, RTSX_STAT_IDLE); } /* finished working on this command */ chip->srb = NULL; scsi_unlock(host); /* unlock the device pointers */ mutex_unlock(&dev->dev_mutex); } /* for (;;) */ /* notify the exit routine that we're actually exiting now * * complete()/wait_for_completion() is similar to up()/down(), * except that complete() is safe in the case where the structure * is getting deleted in a parallel mode of execution (i.e. just * after the down() -- that's necessary for the thread-shutdown * case. * * complete_and_exit() goes even further than this -- it is safe in * the case that the thread of the caller is going away (not just * the structure) -- this is necessary for the module-remove case. * This is important in preemption kernels, which transfer the flow * of execution immediately upon a complete(). */ complete_and_exit(&dev->control_exit, 0); }
/* Invoke the transport and basic error-handling/recovery methods * * This is used by the protocol layers to actually send the message to * the device and receive the response. */ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us) { int need_auto_sense; int result; /* send the command to the transport layer */ scsi_set_resid(srb, 0); result = us->transport(srb, us); /* if the command gets aborted by the higher layers, we need to * short-circuit all other processing */ if (test_bit(US_FLIDX_TIMED_OUT, &us->dflags)) { US_DEBUGP("-- command was aborted\n"); srb->result = DID_ABORT << 16; goto Handle_Errors; } /* if there is a transport error, reset and don't auto-sense */ if (result == USB_STOR_TRANSPORT_ERROR) { US_DEBUGP("-- transport indicates error, resetting\n"); srb->result = DID_ERROR << 16; goto Handle_Errors; } /* if the transport provided its own sense data, don't auto-sense */ if (result == USB_STOR_TRANSPORT_NO_SENSE) { srb->result = SAM_STAT_CHECK_CONDITION; last_sector_hacks(us, srb); return; } srb->result = SAM_STAT_GOOD; /* Determine if we need to auto-sense * * I normally don't use a flag like this, but it's almost impossible * to understand what's going on here if I don't. */ need_auto_sense = 0; /* * If we're running the CB transport, which is incapable * of determining status on its own, we will auto-sense * unless the operation involved a data-in transfer. Devices * can signal most data-in errors by stalling the bulk-in pipe. */ if ((us->protocol == US_PR_CB || us->protocol == US_PR_DPCM_USB) && srb->sc_data_direction != DMA_FROM_DEVICE) { US_DEBUGP("-- CB transport device requiring auto-sense\n"); need_auto_sense = 1; } /* * If we have a failure, we're going to do a REQUEST_SENSE * automatically. Note that we differentiate between a command * "failure" and an "error" in the transport mechanism. */ if (result == USB_STOR_TRANSPORT_FAILED) { US_DEBUGP("-- transport indicates command failure\n"); need_auto_sense = 1; } /* * Determine if this device is SAT by seeing if the * command executed successfully. Otherwise we'll have * to wait for at least one CHECK_CONDITION to determine * SANE_SENSE support */ if ((srb->cmnd[0] == ATA_16 || srb->cmnd[0] == ATA_12) && result == USB_STOR_TRANSPORT_GOOD && !(us->fflags & US_FL_SANE_SENSE) && !(srb->cmnd[2] & 0x20)) { US_DEBUGP("-- SAT supported, increasing auto-sense\n"); us->fflags |= US_FL_SANE_SENSE; } /* * A short transfer on a command where we don't expect it * is unusual, but it doesn't mean we need to auto-sense. */ if ((scsi_get_resid(srb) > 0) && !((srb->cmnd[0] == REQUEST_SENSE) || (srb->cmnd[0] == INQUIRY) || (srb->cmnd[0] == MODE_SENSE) || (srb->cmnd[0] == LOG_SENSE) || (srb->cmnd[0] == MODE_SENSE_10))) { US_DEBUGP("-- unexpectedly short transfer\n"); } /* Now, if we need to do the auto-sense, let's do it */ if (need_auto_sense) { int temp_result; struct scsi_eh_save ses; int sense_size = US_SENSE_SIZE; /* device supports and needs bigger sense buffer */ if (us->fflags & US_FL_SANE_SENSE) sense_size = ~0; US_DEBUGP("Issuing auto-REQUEST_SENSE\n"); scsi_eh_prep_cmnd(srb, &ses, NULL, 0, sense_size); /* FIXME: we must do the protocol translation here */ if (us->subclass == US_SC_RBC || us->subclass == US_SC_SCSI || us->subclass == US_SC_CYP_ATACB) srb->cmd_len = 6; else srb->cmd_len = 12; /* issue the auto-sense command */ scsi_set_resid(srb, 0); temp_result = us->transport(us->srb, us); /* let's clean up right away */ scsi_eh_restore_cmnd(srb, &ses); if (test_bit(US_FLIDX_TIMED_OUT, &us->dflags)) { US_DEBUGP("-- auto-sense aborted\n"); srb->result = DID_ABORT << 16; goto Handle_Errors; } if (temp_result != USB_STOR_TRANSPORT_GOOD) { US_DEBUGP("-- auto-sense failure\n"); /* we skip the reset if this happens to be a * multi-target device, since failure of an * auto-sense is perfectly valid */ srb->result = DID_ERROR << 16; if (!(us->fflags & US_FL_SCM_MULT_TARG)) goto Handle_Errors; return; } /* If the sense data returned is larger than 18-bytes then we * assume this device supports requesting more in the future. * The response code must be 70h through 73h inclusive. */ if (srb->sense_buffer[7] > (US_SENSE_SIZE - 8) && !(us->fflags & US_FL_SANE_SENSE) && (srb->sense_buffer[0] & 0x7C) == 0x70) { US_DEBUGP("-- SANE_SENSE support enabled\n"); us->fflags |= US_FL_SANE_SENSE; /* Indicate to the user that we truncated their sense * because we didn't know it supported larger sense. */ US_DEBUGP("-- Sense data truncated to %i from %i\n", US_SENSE_SIZE, srb->sense_buffer[7] + 8); srb->sense_buffer[7] = (US_SENSE_SIZE - 8); } US_DEBUGP("-- Result from auto-sense is %d\n", temp_result); US_DEBUGP("-- code: 0x%x, key: 0x%x, ASC: 0x%x, ASCQ: 0x%x\n", srb->sense_buffer[0], srb->sense_buffer[2] & 0xf, srb->sense_buffer[12], srb->sense_buffer[13]); #ifdef CONFIG_USB_STORAGE_DEBUG usb_stor_show_sense( srb->sense_buffer[2] & 0xf, srb->sense_buffer[12], srb->sense_buffer[13]); #endif /* set the result so the higher layers expect this data */ srb->result = SAM_STAT_CHECK_CONDITION; /* If things are really okay, then let's show that. Zero * out the sense buffer so the higher layers won't realize * we did an unsolicited auto-sense. */ if (result == USB_STOR_TRANSPORT_GOOD && /* Filemark 0, ignore EOM, ILI 0, no sense */ (srb->sense_buffer[2] & 0xaf) == 0 && /* No ASC or ASCQ */ srb->sense_buffer[12] == 0 && srb->sense_buffer[13] == 0) { srb->result = SAM_STAT_GOOD; srb->sense_buffer[0] = 0x0; } } /* Did we transfer less than the minimum amount required? */ if ((srb->result == SAM_STAT_GOOD || srb->sense_buffer[2] == 0) && scsi_bufflen(srb) - scsi_get_resid(srb) < srb->underflow) srb->result = DID_ERROR << 16; last_sector_hacks(us, srb); return; /* Error and abort processing: try to resynchronize with the device * by issuing a port reset. If that fails, try a class-specific * device reset. */ Handle_Errors: /* Set the RESETTING bit, and clear the ABORTING bit so that * the reset may proceed. */ scsi_lock(us_to_host(us)); set_bit(US_FLIDX_RESETTING, &us->dflags); clear_bit(US_FLIDX_ABORTING, &us->dflags); scsi_unlock(us_to_host(us)); /* We must release the device lock because the pre_reset routine * will want to acquire it. */ mutex_unlock(&us->dev_mutex); result = usb_stor_port_reset(us); mutex_lock(&us->dev_mutex); if (result < 0) { scsi_lock(us_to_host(us)); usb_stor_report_device_reset(us); scsi_unlock(us_to_host(us)); us->transport_reset(us); } clear_bit(US_FLIDX_RESETTING, &us->dflags); last_sector_hacks(us, srb); }
static int rts51x_control_thread(void *__chip) { struct rts51x_chip *chip = (struct rts51x_chip *)__chip; struct Scsi_Host *host = rts51x_to_host(chip); for (;;) { if (wait_for_completion_interruptible(&chip->usb->cmnd_ready)) break; if (test_bit(FLIDX_DISCONNECTING, &chip->usb->dflags)) { RTS51X_DEBUGP("-- exiting from rts51x-control\n"); break; } mutex_lock(&(chip->usb->dev_mutex)); scsi_lock(host); if (chip->srb == NULL) { scsi_unlock(host); mutex_unlock(&chip->usb->dev_mutex); RTS51X_DEBUGP("-- exiting from control thread\n"); break; } if (test_bit(FLIDX_TIMED_OUT, &chip->usb->dflags)) { chip->srb->result = DID_ABORT << 16; goto SkipForAbort; } scsi_unlock(host); if (chip->srb->sc_data_direction == DMA_BIDIRECTIONAL) { RTS51X_DEBUGP("UNKNOWN data direction\n"); chip->srb->result = DID_ERROR << 16; } else if (chip->srb->device->id) { RTS51X_DEBUGP("Bad target number (%d:%d)\n", chip->srb->device->id, chip->srb->device->lun); chip->srb->result = DID_BAD_TARGET << 16; } else if (chip->srb->device->lun > chip->max_lun) { RTS51X_DEBUGP("Bad LUN (%d:%d)\n", chip->srb->device->id, chip->srb->device->lun); chip->srb->result = DID_BAD_TARGET << 16; } else { RTS51X_DEBUG(scsi_show_command(chip->srb)); rts51x_invoke_transport(chip->srb, chip); } scsi_lock(host); if (chip->srb->result != DID_ABORT << 16) chip->srb->scsi_done(chip->srb); else SkipForAbort : RTS51X_DEBUGP("scsi command aborted\n"); if (test_bit(FLIDX_TIMED_OUT, &chip->usb->dflags)) { complete(&(chip->usb->notify)); clear_bit(FLIDX_ABORTING, &chip->usb->dflags); clear_bit(FLIDX_TIMED_OUT, &chip->usb->dflags); } chip->srb = NULL; scsi_unlock(host); mutex_unlock(&chip->usb->dev_mutex); } complete(&chip->usb->control_exit); return 0; }
static int usb_stor_control_thread(void * __us) { struct us_data *us = (struct us_data *)__us; struct Scsi_Host *host = us_to_host(us); //--------------------------- pr_info("7 usb stor control thread\n"); for(;;) { //若有u盘拔插或者有命令才会awake,否则一直就在这睡觉觉 if (wait_for_completion_interruptible(&us->cmnd_ready)) break; //从此处wake /* */ mutex_lock(&(us->dev_mutex)); /*每当需要写us->srb时候就需要锁之 */ scsi_lock(host); if (us->srb == NULL) { scsi_unlock(host); mutex_unlock(&us->dev_mutex); US_DEBUGP("-- exiting\n"); break; } if (test_bit(US_FLIDX_TIMED_OUT, &us->dflags)) { us->srb->result = DID_ABORT << 16; goto SkipForAbort; } scsi_unlock(host); if (us->srb->sc_data_direction == DMA_BIDIRECTIONAL) { US_DEBUGP("UNKNOWN data direction\n"); us->srb->result = DID_ERROR << 16; } else if (us->srb->device->id && !(us->fflags & US_FL_SCM_MULT_TARG)) { US_DEBUGP("Bad target number (%d:%d)\n", us->srb->device->id, us->srb->device->lun); us->srb->result = DID_BAD_TARGET << 16; } else if (us->srb->device->lun > us->max_lun) { US_DEBUGP("Bad LUN (%d:%d)\n", us->srb->device->id, us->srb->device->lun); us->srb->result = DID_BAD_TARGET << 16; } else if ((us->srb->cmnd[0] == INQUIRY) && (us->fflags & US_FL_FIX_INQUIRY)) { unsigned char data_ptr[36] = { 0x00, 0x80, 0x02, 0x02, 0x1F, 0x00, 0x00, 0x00}; US_DEBUGP("Faking INQUIRY command\n"); fill_inquiry_response(us, data_ptr, 36); us->srb->result = SAM_STAT_GOOD; } else { US_DEBUG(usb_stor_show_command(us->srb)); us->proto_handler(us->srb, us); usb_mark_last_busy(us->pusb_dev); } scsi_lock(host); if (us->srb->result != DID_ABORT << 16) { US_DEBUGP("scsi cmd done, result=0x%x\n", us->srb->result); us->srb->scsi_done(us->srb); } else { SkipForAbort: US_DEBUGP("scsi command aborted\n"); } /* */ if (test_bit(US_FLIDX_TIMED_OUT, &us->dflags)) { complete(&(us->notify)); clear_bit(US_FLIDX_ABORTING, &us->dflags); clear_bit(US_FLIDX_TIMED_OUT, &us->dflags); } us->srb = NULL; scsi_unlock(host); / mutex_unlock(&us->dev_mutex); }
//----------------------------------------------------------- static int JorwayDoIo( CamKey Key, BYTE A, BYTE F, int Count, BYTE *Data, BYTE Mem, TranslatedIosb *iosb, int dmode, int Enhanced ) { char dev_name[7]; int IsDataCommand, scsiDevice; int xfer_data_length; int status; unsigned char *cmd; unsigned char cmdlen; int direction; unsigned int bytcnt; int reqbytcnt = 0; SenseData sense; char sensretlen; int online; int enhanced; CDBCamacDataCommand( DATAcommand ); CDBCamacNonDataCommand( NONDATAcommand ); if( MSGLVL(FUNCTION_NAME) ) printf( "%s()\n", J_ROUTINE_NAME ); //printf( "%s(iosb is %sNULL)\n", J_ROUTINE_NAME, (iosb)?"NOT ":"" ); // [2002.12.13] sprintf(dev_name, "GK%c%d%02d", Key.scsi_port, Key.scsi_address, Key.crate); if( (scsiDevice = get_scsi_device_number( dev_name, &enhanced, &online )) < 0 ) { if( MSGLVL(IMPORTANT) ) fprintf( stderr, "%s(): error -- no scsi device found for '%s'\n", J_ROUTINE_NAME, dev_name ); status = NO_DEVICE; goto JorwayDoIo_Exit; } if (!online && Key.slot != 30) return CamOFFLINE; if (!Enhanced) enhanced = 0; if( MSGLVL(DETAILS) ) printf( "%s(): device '%s' = '/dev/sg%d'\n", J_ROUTINE_NAME, dev_name, scsiDevice ); IsDataCommand = (F & 0x08) ? FALSE : TRUE; if( IsDataCommand ) { union { BYTE b[4]; unsigned int l; } transfer_len; DATAcommand.f = F; DATAcommand.bs = Mem == 24; DATAcommand.n = Key.slot; DATAcommand.m = JORWAYMODE(dmode, enhanced, Count > 1); DATAcommand.a = A; DATAcommand.sncx = 0; DATAcommand.scs = 0; reqbytcnt = transfer_len.l = Count * ((Mem == 24) ? 4 : 2); # if JORWAY_DISCONNECT # ifdef SG_BIG_BUFF DATAcommand.dd = transfer_len.l > SG_BIG_BUFF; # else DATAcommand.dd = transfer_len.l > 4096; # endif # else DATAcommand.dd = 0; # endif DATAcommand.crate = Key.crate; DATAcommand.sp = HIGHWAY_SERIAL; DATAcommand.transfer_len[0] = transfer_len.b[2]; // NB! order reversal DATAcommand.transfer_len[1] = transfer_len.b[1]; DATAcommand.transfer_len[2] = transfer_len.b[0]; cmd = (unsigned char *)&DATAcommand; cmdlen = sizeof(DATAcommand); direction = (F < 8) ? 1 : 2; } else { NONDATAcommand.bytes[1] = F; NONDATAcommand.bytes[2] = Key.slot; NONDATAcommand.bytes[3] = A; NONDATAcommand.bytes[4] = (HIGHWAY_SERIAL << 7) | Key.crate; cmd = (unsigned char *)&NONDATAcommand; cmdlen = sizeof(NONDATAcommand); direction = 0; } memset(&sense,0,sizeof(sense)); sensretlen=0; bytcnt=0; scsi_lock(scsiDevice,1); status = scsi_io( scsiDevice, direction, cmd, cmdlen, Data, reqbytcnt, (unsigned char *)&sense, sizeof(sense), &sensretlen, &bytcnt); scsi_lock(scsiDevice,0); status = JorwayTranslateIosb(reqbytcnt,&sense,sensretlen,bytcnt,status); if ( iosb ) *iosb = LastIosb; // [2002.12.11] JorwayDoIo_Exit: if( MSGLVL(DETAILS) ) { printf( "%s(): iosb->status [0x%x]\n", J_ROUTINE_NAME, iosb->status ); printf( "%s(): iosb->x [0x%x]\n", J_ROUTINE_NAME, iosb->x ); printf( "%s(): iosb->q [0x%x]\n", J_ROUTINE_NAME, iosb->q ); //printf( "%s(): iosb->bytcnt [%d]\n", J_ROUTINE_NAME, iosb->bytcnt); // [2002.12.11] } //printf("JorwayDoIo(iosb)::->> bytecount= %d\n", iosb->bytcnt); // [2002.12.13] return status; }
//仔细研读 static int usb_stor_control_thread(void * __us) { struct us_data *us = (struct us_data *)__us; struct Scsi_Host *host = us_to_host(us); //--------------------------- pr_info("7 usb stor control thread\n"); for(;;) { US_DEBUGP("*** thread sleeping.\n"); if (wait_for_completion_interruptible(&us->cmnd_ready)) break; US_DEBUGP("*** thread awakened.\n"); /* lock the device pointers */ mutex_lock(&(us->dev_mutex)); /* lock access to the state */ scsi_lock(host); /* When we are called with no command pending, we're done */ if (us->srb == NULL) { scsi_unlock(host); mutex_unlock(&us->dev_mutex); US_DEBUGP("-- exiting\n"); break; } /* has the command timed out *already* ? */ if (test_bit(US_FLIDX_TIMED_OUT, &us->dflags)) { us->srb->result = DID_ABORT << 16; goto SkipForAbort; } scsi_unlock(host); /* reject the command if the direction indicator * is UNKNOWN */ if (us->srb->sc_data_direction == DMA_BIDIRECTIONAL) { US_DEBUGP("UNKNOWN data direction\n"); us->srb->result = DID_ERROR << 16; } /* reject if target != 0 or if LUN is higher than * the maximum known LUN */ else if (us->srb->device->id && !(us->fflags & US_FL_SCM_MULT_TARG)) { US_DEBUGP("Bad target number (%d:%d)\n", us->srb->device->id, us->srb->device->lun); us->srb->result = DID_BAD_TARGET << 16; } else if (us->srb->device->lun > us->max_lun) { US_DEBUGP("Bad LUN (%d:%d)\n", us->srb->device->id, us->srb->device->lun); us->srb->result = DID_BAD_TARGET << 16; } /* Handle those devices which need us to fake * their inquiry data */ else if ((us->srb->cmnd[0] == INQUIRY) && (us->fflags & US_FL_FIX_INQUIRY)) { unsigned char data_ptr[36] = { 0x00, 0x80, 0x02, 0x02, 0x1F, 0x00, 0x00, 0x00}; US_DEBUGP("Faking INQUIRY command\n"); fill_inquiry_response(us, data_ptr, 36); us->srb->result = SAM_STAT_GOOD; } /* we've got a command, let's do it! */ else { US_DEBUG(usb_stor_show_command(us->srb)); us->proto_handler(us->srb, us); usb_mark_last_busy(us->pusb_dev); } /* lock access to the state */ scsi_lock(host); /* indicate that the command is done */ if (us->srb->result != DID_ABORT << 16) { US_DEBUGP("scsi cmd done, result=0x%x\n", us->srb->result); us->srb->scsi_done(us->srb); } else { SkipForAbort: US_DEBUGP("scsi command aborted\n"); } /* If an abort request was received we need to signal that * the abort has finished. The proper test for this is * the TIMED_OUT flag, not srb->result == DID_ABORT, because * the timeout might have occurred after the command had * already completed with a different result code. */ if (test_bit(US_FLIDX_TIMED_OUT, &us->dflags)) { complete(&(us->notify)); /* Allow USB transfers to resume */ clear_bit(US_FLIDX_ABORTING, &us->dflags); clear_bit(US_FLIDX_TIMED_OUT, &us->dflags); } /* finished working on this command */ us->srb = NULL; scsi_unlock(host); /* unlock the device pointers */ mutex_unlock(&us->dev_mutex); } /* for (;;) */ /* Wait until we are told to stop */ for (;;) { set_current_state(TASK_INTERRUPTIBLE); if (kthread_should_stop()) break; schedule(); } __set_current_state(TASK_RUNNING); return 0; }
//----------------------------------------------------------- static int Jorway73ADoIo( CamKey Key, BYTE A, BYTE F, int Count, BYTE *Data, BYTE Mem, TranslatedIosb *iosb, int dmode, int Enhanced ) { char dev_name[7]; int IsDataCommand, scsiDevice; int xfer_data_length; int status; unsigned char *cmd; unsigned char cmdlen; int direction; unsigned int bytcnt; int reqbytcnt = 0; J73ASenseData sense; char sensretlen; int online; int enhanced; struct { __u8 opcode; __u8 f : 5; __u8 lu : 3; __u8 n : 5; __u8 bs : 1; __u8 m : 2; __u8 a : 4; __u8 zero1 : 4; __u8 transfer_len; __u8 zero2; } NONDATAcommand = {1,0,0,0,0,0,0,0,0,0}; struct { __u8 opcode; __u8 f : 5; __u8 lu : 3; __u8 n : 5; __u8 bs : 1; __u8 m : 2; __u8 a : 4; __u8 zero1 : 4; __u8 transfer_len; __u8 zero2; } ShortDATAcommand = {1,0,0,0,0,0,0,0,0,0}; struct { __u8 opcode; __u8 zero1 : 5; __u8 lu : 3; __u8 f : 5; __u8 zero2 : 3; __u8 n : 5; __u8 bs : 1; __u8 m : 2; __u8 a : 4; __u8 zero3 : 4; __u8 zero4; __u8 transfer_len[3]; __u8 zero5; } LongDATAcommand = {0x21,0,0,0,0,0,0,0,0,0}; static char modes[4] = {2,2,3,1}; /* QStop, QIgnore, QRep, QScan */ static char singlemodes[4] = {0,2,3,1}; if( MSGLVL(FUNCTION_NAME) ) printf( "%s()\n", J_ROUTINE_NAME ); //printf( "%s(iosb is %sNULL)\n", J_ROUTINE_NAME, (iosb)?"NOT ":"" ); // [2002.12.13] sprintf(dev_name, "GK%c%d%02d", Key.scsi_port, Key.scsi_address, Key.crate); if( (scsiDevice = get_scsi_device_number( dev_name, &enhanced, &online )) < 0 ) { if( MSGLVL(IMPORTANT) ) fprintf( stderr, "%s(): error -- no scsi device found for '%s'\n", J_ROUTINE_NAME, dev_name ); status = NO_DEVICE; goto Jorway73ADoIo_Exit; } if (!online && Key.slot != 30) return CamOFFLINE; if (online && Key.slot == 30 && F == 1 && A == 0) { *(short *)Data = 0x30; return CamDONE_Q; } if( MSGLVL(DETAILS) ) printf( "%s(): device '%s' = '/dev/sg%d'\n", J_ROUTINE_NAME, dev_name, scsiDevice ); IsDataCommand = (F & 0x08) ? FALSE : TRUE; if( IsDataCommand ) { union { BYTE b[4]; unsigned int l; } transfer_len; reqbytcnt = transfer_len.l = Count * ((Mem == 24) ? 4 : 2); direction = (F < 8) ? 1 : 2; if (reqbytcnt < 256) { cmd = (char *)&ShortDATAcommand; cmdlen = sizeof(ShortDATAcommand); ShortDATAcommand.f = F; ShortDATAcommand.bs = Mem == 24; ShortDATAcommand.n = Key.slot; ShortDATAcommand.m = Count > 1 ? modes[dmode] : singlemodes[dmode]; ShortDATAcommand.a = A; ShortDATAcommand.transfer_len = transfer_len.l; } else { cmd = (char *)&LongDATAcommand; cmdlen = sizeof(LongDATAcommand); LongDATAcommand.f = F; LongDATAcommand.bs = Mem == 24; LongDATAcommand.n = Key.slot; LongDATAcommand.m = modes[dmode]; LongDATAcommand.a = A; LongDATAcommand.transfer_len[0] = transfer_len.b[2]; // NB! order reversal LongDATAcommand.transfer_len[1] = transfer_len.b[1]; LongDATAcommand.transfer_len[2] = transfer_len.b[0]; } } else { NONDATAcommand.f = F; NONDATAcommand.n = Key.slot; NONDATAcommand.a = A; cmd = (unsigned char *)&NONDATAcommand; cmdlen = sizeof(NONDATAcommand); direction = 0; } scsi_lock(scsiDevice,1); status = scsi_io( scsiDevice, direction, cmd, cmdlen, Data, reqbytcnt, (unsigned char *)&sense, sizeof(sense), &sensretlen, &bytcnt); scsi_lock(scsiDevice,0); status = Jorway73ATranslateIosb(IsDataCommand, reqbytcnt,&sense,status); if ( iosb ) *iosb = LastIosb; // [2002.12.11] Jorway73ADoIo_Exit: if( MSGLVL(FUNCTION_NAME+1) ) { // This is only rough - depends on the nature of the "overloaded" vars printf("scsi_mode opcode=%d, dmode=%d, modes[dmode]=%d, [1]=%d, [3]=%d, [5]=%d [7]=%d\n", cmd[0], dmode, modes[dmode], cmd[1], cmd[3], cmd[5], cmd[7]); if (!iosb) {printf("Jorway73ADoIo_Exit: Null pointer to iosb\n"); } else { printf( "%s(): iosb->status [0x%x]\n", J_ROUTINE_NAME, iosb->status ); printf( "%s(): iosb->x [0x%x]\n", J_ROUTINE_NAME, iosb->x ); printf( "%s(): iosb->q [0x%x]\n", J_ROUTINE_NAME, iosb->q ); //printf( "%s(): iosb->bytcnt [%d]\n", J_ROUTINE_NAME, iosb->bytcnt); // [2002.12.11] } } //printf("Jorway73ADoIo(iosb)::->> bytecount= %d\n", iosb->bytcnt); // [2002.12.13] return status; }
/* Invoke the transport and basic error-handling/recovery methods * * This is used by the protocol layers to actually send the message to * the device and receive the response. */ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us) { int need_auto_sense; int result; /* send the command to the transport layer */ srb->resid = 0; result = us->transport(srb, us); /* if the command gets aborted by the higher layers, we need to * short-circuit all other processing */ if (test_bit(US_FLIDX_TIMED_OUT, &us->flags)) { _VMKLNX_USB_STOR_MSG("-- command was aborted\n", srb); US_DEBUGP("-- command was aborted\n"); srb->result = DID_ABORT << 16; goto Handle_Errors; } #if defined(__VMKLNX__) if (unlikely(scsi_dump_active(srb))) { /* can't do much in panic */ if (result != USB_STOR_TRANSPORT_GOOD) { srb->result = DID_ABORT << 16; goto Handle_Errors; } } #endif /* if there is a transport error, reset and don't auto-sense */ if (result == USB_STOR_TRANSPORT_ERROR) { _VMKLNX_USB_STOR_WARN("-- transport indicates error, resetting\n", srb); US_DEBUGP("-- transport indicates error, resetting\n"); srb->result = DID_ERROR << 16; goto Handle_Errors; } /* if the transport provided its own sense data, don't auto-sense */ if (result == USB_STOR_TRANSPORT_NO_SENSE) { #if defined(__VMKLNX__) BUG_ON(srb->sense_buffer[0] == 0); #endif srb->result = SAM_STAT_CHECK_CONDITION; return; } srb->result = SAM_STAT_GOOD; /* Determine if we need to auto-sense * * I normally don't use a flag like this, but it's almost impossible * to understand what's going on here if I don't. */ need_auto_sense = 0; /* * If we're running the CB transport, which is incapable * of determining status on its own, we will auto-sense * unless the operation involved a data-in transfer. Devices * can signal most data-in errors by stalling the bulk-in pipe. */ if ((us->protocol == US_PR_CB || us->protocol == US_PR_DPCM_USB) && srb->sc_data_direction != DMA_FROM_DEVICE) { _VMKLNX_USB_STOR_MSG("-- CB transport device requiring auto-sense\n", srb); US_DEBUGP("-- CB transport device requiring auto-sense\n"); need_auto_sense = 1; } /* * If we have a failure, we're going to do a REQUEST_SENSE * automatically. Note that we differentiate between a command * "failure" and an "error" in the transport mechanism. */ if (result == USB_STOR_TRANSPORT_FAILED) { _VMKLNX_USB_STOR_MSG("-- transport indicates command failure\n", srb); US_DEBUGP("-- transport indicates command failure\n"); need_auto_sense = 1; } /* * A short transfer on a command where we don't expect it * is unusual, but it doesn't mean we need to auto-sense. */ if ((srb->resid > 0) && !((srb->cmnd[0] == REQUEST_SENSE) || (srb->cmnd[0] == INQUIRY) || (srb->cmnd[0] == MODE_SENSE) || (srb->cmnd[0] == LOG_SENSE) || (srb->cmnd[0] == MODE_SENSE_10))) { _VMKLNX_USB_STOR_MSG("-- unexpectedly short transfer\n", srb); US_DEBUGP("-- unexpectedly short transfer\n"); } /* Now, if we need to do the auto-sense, let's do it */ if (need_auto_sense) { int temp_result; struct scsi_eh_save ses; US_DEBUGP("Issuing auto-REQUEST_SENSE\n"); #if defined(__VMKLNX__) /* use us->senebuf to get sense data; srb->sense_buffer might be above 4G, * yet device's dma_mask is set to 32-bit */ usb_stor_prep_cmd(srb, &ses, us->sensebuf); #else scsi_eh_prep_cmnd(srb, &ses, NULL, 0, US_SENSE_SIZE); #endif /* FIXME: we must do the protocol translation here */ if (us->subclass == US_SC_RBC || us->subclass == US_SC_SCSI) srb->cmd_len = 6; else srb->cmd_len = 12; /* issue the auto-sense command */ srb->resid = 0; temp_result = us->transport(us->srb, us); /* let's clean up right away */ #if defined(__VMKLNX__) usb_stor_restore_cmnd(srb, &ses); #else scsi_eh_restore_cmnd(srb, &ses); #endif if (test_bit(US_FLIDX_TIMED_OUT, &us->flags)) { US_DEBUGP("-- auto-sense aborted\n"); srb->result = DID_ABORT << 16; goto Handle_Errors; } if (temp_result != USB_STOR_TRANSPORT_GOOD) { US_DEBUGP("-- auto-sense failure\n"); /* we skip the reset if this happens to be a * multi-target device, since failure of an * auto-sense is perfectly valid */ srb->result = DID_ERROR << 16; if (!(us->flags & US_FL_SCM_MULT_TARG)) goto Handle_Errors; return; } US_DEBUGP("-- Result from auto-sense is %d\n", temp_result); US_DEBUGP("-- code: 0x%x, key: 0x%x, ASC: 0x%x, ASCQ: 0x%x\n", srb->sense_buffer[0], srb->sense_buffer[2] & 0xf, srb->sense_buffer[12], srb->sense_buffer[13]); #ifdef CONFIG_USB_STORAGE_DEBUG usb_stor_show_sense( srb->sense_buffer[2] & 0xf, srb->sense_buffer[12], srb->sense_buffer[13]); #endif /* set the result so the higher layers expect this data */ srb->result = SAM_STAT_CHECK_CONDITION; #if defined(__VMKLNX__) if (unlikely(srb->sense_buffer[0] == 0)) _VMKLNX_USB_STOR_MSG("srb->sense_buffer[0] unexpectedly 0 for srb %p\n", srb, srb); BUG_ON(srb->sense_buffer[0] == 0); #endif /* If things are really okay, then let's show that. Zero * out the sense buffer so the higher layers won't realize * we did an unsolicited auto-sense. */ if (result == USB_STOR_TRANSPORT_GOOD && /* Filemark 0, ignore EOM, ILI 0, no sense */ (srb->sense_buffer[2] & 0xaf) == 0 && /* No ASC or ASCQ */ srb->sense_buffer[12] == 0 && srb->sense_buffer[13] == 0) { srb->result = SAM_STAT_GOOD; srb->sense_buffer[0] = 0x0; } } /* Did we transfer less than the minimum amount required? */ if (srb->result == SAM_STAT_GOOD && srb->request_bufflen - srb->resid < srb->underflow) srb->result = (DID_ERROR << 16) | (SUGGEST_RETRY << 24); return; /* Error and abort processing: try to resynchronize with the device * by issuing a port reset. If that fails, try a class-specific * device reset. */ Handle_Errors: /* Set the RESETTING bit, and clear the ABORTING bit so that * the reset may proceed. */ scsi_lock(us_to_host(us)); set_bit(US_FLIDX_RESETTING, &us->flags); clear_bit(US_FLIDX_ABORTING, &us->flags); scsi_unlock(us_to_host(us)); /* We must release the device lock because the pre_reset routine * will want to acquire it. */ mutex_unlock(&us->dev_mutex); result = usb_stor_port_reset(us); mutex_lock(&us->dev_mutex); if (result < 0) { scsi_lock(us_to_host(us)); usb_stor_report_device_reset(us); scsi_unlock(us_to_host(us)); us->transport_reset(us); } clear_bit(US_FLIDX_RESETTING, &us->flags); }
static int rtsx_control_thread(void * __dev) { struct rtsx_dev *dev = (struct rtsx_dev *)__dev; struct rtsx_chip *chip = dev->chip; struct Scsi_Host *host = rtsx_to_host(dev); current->flags |= PF_NOFREEZE; for(;;) { if(down_interruptible(&dev->sema)) break; mutex_lock(&(dev->dev_mutex)); if (rtsx_chk_stat(chip, RTSX_STAT_DISCONNECT)) { printk(KERN_INFO "-- rtsx-control exiting\n"); mutex_unlock(&dev->dev_mutex); break; } scsi_lock(host); if (rtsx_chk_stat(chip, RTSX_STAT_ABORT)) { chip->srb->result = DID_ABORT << 16; goto SkipForAbort; } scsi_unlock(host); /* reject the command if the direction indicator * is UNKNOWN */ if (chip->srb->sc_data_direction == DMA_BIDIRECTIONAL) { printk(KERN_ERR "UNKNOWN data direction\n"); chip->srb->result = DID_ERROR << 16; } /* reject if target != 0 or if LUN is higher than * the maximum known LUN */ else if (chip->srb->device->id) { printk(KERN_ERR "Bad target number (%d:%d)\n", chip->srb->device->id, chip->srb->device->lun); chip->srb->result = DID_BAD_TARGET << 16; } else if (chip->srb->device->lun > chip->max_lun) { printk(KERN_ERR "Bad LUN (%d:%d)\n", chip->srb->device->id, chip->srb->device->lun); chip->srb->result = DID_BAD_TARGET << 16; } else { RTSX_DEBUG(scsi_show_command(chip->srb)); rtsx_invoke_transport(chip->srb, chip); } scsi_lock(host); if (!chip->srb) ; else if (chip->srb->result != DID_ABORT << 16) { chip->srb->scsi_done(chip->srb); } else { SkipForAbort: printk(KERN_ERR "scsi command aborted\n"); } if (rtsx_chk_stat(chip, RTSX_STAT_ABORT)) { complete(&(dev->notify)); rtsx_set_stat(chip, RTSX_STAT_IDLE); } chip->srb = NULL; scsi_unlock(host); mutex_unlock(&dev->dev_mutex); } scsi_host_put(host); /* notify the exit routine that we're actually exiting now * * complete()/wait_for_completion() is similar to up()/down(), * except that complete() is safe in the case where the structure * is getting deleted in a parallel mode of execution (i.e. just * after the down() -- that's necessary for the thread-shutdown * case. * * complete_and_exit() goes even further than this -- it is safe in * the case that the thread of the caller is going away (not just * the structure) -- this is necessary for the module-remove case. * This is important in preemption kernels, which transfer the flow * of execution immediately upon a complete(). */ complete_and_exit(&threads_gone, 0); }
void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us) { int need_auto_sense; int result; scsi_set_resid(srb, 0); result = us->transport(srb, us); if (test_bit(US_FLIDX_TIMED_OUT, &us->dflags)) { US_DEBUGP("-- command was aborted\n"); srb->result = DID_ABORT << 16; goto Handle_Errors; } if (result == USB_STOR_TRANSPORT_ERROR) { US_DEBUGP("-- transport indicates error, resetting\n"); srb->result = DID_ERROR << 16; goto Handle_Errors; } if (result == USB_STOR_TRANSPORT_NO_SENSE) { srb->result = SAM_STAT_CHECK_CONDITION; last_sector_hacks(us, srb); return; } srb->result = SAM_STAT_GOOD; need_auto_sense = 0; if ((us->protocol == USB_PR_CB || us->protocol == USB_PR_DPCM_USB) && srb->sc_data_direction != DMA_FROM_DEVICE) { US_DEBUGP("-- CB transport device requiring auto-sense\n"); need_auto_sense = 1; } if (result == USB_STOR_TRANSPORT_FAILED) { US_DEBUGP("-- transport indicates command failure\n"); need_auto_sense = 1; } if (unlikely((srb->cmnd[0] == ATA_16 || srb->cmnd[0] == ATA_12) && result == USB_STOR_TRANSPORT_GOOD && !(us->fflags & US_FL_SANE_SENSE) && !(us->fflags & US_FL_BAD_SENSE) && !(srb->cmnd[2] & 0x20))) { US_DEBUGP("-- SAT supported, increasing auto-sense\n"); us->fflags |= US_FL_SANE_SENSE; } if ((scsi_get_resid(srb) > 0) && !((srb->cmnd[0] == REQUEST_SENSE) || (srb->cmnd[0] == INQUIRY) || (srb->cmnd[0] == MODE_SENSE) || (srb->cmnd[0] == LOG_SENSE) || (srb->cmnd[0] == MODE_SENSE_10))) { US_DEBUGP("-- unexpectedly short transfer\n"); } if (need_auto_sense) { int temp_result; struct scsi_eh_save ses; int sense_size = US_SENSE_SIZE; struct scsi_sense_hdr sshdr; const u8 *scdd; u8 fm_ili; if (us->fflags & US_FL_SANE_SENSE) sense_size = ~0; Retry_Sense: US_DEBUGP("Issuing auto-REQUEST_SENSE\n"); scsi_eh_prep_cmnd(srb, &ses, NULL, 0, sense_size); if (us->subclass == USB_SC_RBC || us->subclass == USB_SC_SCSI || us->subclass == USB_SC_CYP_ATACB) srb->cmd_len = 6; else srb->cmd_len = 12; scsi_set_resid(srb, 0); temp_result = us->transport(us->srb, us); scsi_eh_restore_cmnd(srb, &ses); if (test_bit(US_FLIDX_TIMED_OUT, &us->dflags)) { US_DEBUGP("-- auto-sense aborted\n"); srb->result = DID_ABORT << 16; if (sense_size != US_SENSE_SIZE) { us->fflags &= ~US_FL_SANE_SENSE; us->fflags |= US_FL_BAD_SENSE; } goto Handle_Errors; } if (temp_result == USB_STOR_TRANSPORT_FAILED && sense_size != US_SENSE_SIZE) { US_DEBUGP("-- auto-sense failure, retry small sense\n"); sense_size = US_SENSE_SIZE; us->fflags &= ~US_FL_SANE_SENSE; us->fflags |= US_FL_BAD_SENSE; goto Retry_Sense; } if (temp_result != USB_STOR_TRANSPORT_GOOD) { US_DEBUGP("-- auto-sense failure\n"); srb->result = DID_ERROR << 16; if (!(us->fflags & US_FL_SCM_MULT_TARG)) goto Handle_Errors; return; } if (srb->sense_buffer[7] > (US_SENSE_SIZE - 8) && !(us->fflags & US_FL_SANE_SENSE) && !(us->fflags & US_FL_BAD_SENSE) && (srb->sense_buffer[0] & 0x7C) == 0x70) { US_DEBUGP("-- SANE_SENSE support enabled\n"); us->fflags |= US_FL_SANE_SENSE; US_DEBUGP("-- Sense data truncated to %i from %i\n", US_SENSE_SIZE, srb->sense_buffer[7] + 8); srb->sense_buffer[7] = (US_SENSE_SIZE - 8); } scsi_normalize_sense(srb->sense_buffer, SCSI_SENSE_BUFFERSIZE, &sshdr); US_DEBUGP("-- Result from auto-sense is %d\n", temp_result); US_DEBUGP("-- code: 0x%x, key: 0x%x, ASC: 0x%x, ASCQ: 0x%x\n", sshdr.response_code, sshdr.sense_key, sshdr.asc, sshdr.ascq); #ifdef CONFIG_USB_STORAGE_DEBUG usb_stor_show_sense(sshdr.sense_key, sshdr.asc, sshdr.ascq); #endif srb->result = SAM_STAT_CHECK_CONDITION; scdd = scsi_sense_desc_find(srb->sense_buffer, SCSI_SENSE_BUFFERSIZE, 4); fm_ili = (scdd ? scdd[3] : srb->sense_buffer[2]) & 0xA0; if (sshdr.sense_key == 0 && sshdr.asc == 0 && sshdr.ascq == 0 && fm_ili == 0) { if (result == USB_STOR_TRANSPORT_GOOD) { srb->result = SAM_STAT_GOOD; srb->sense_buffer[0] = 0x0; } else { srb->result = DID_ERROR << 16; if ((sshdr.response_code & 0x72) == 0x72) srb->sense_buffer[1] = HARDWARE_ERROR; else srb->sense_buffer[2] = HARDWARE_ERROR; } } } if (unlikely((us->fflags & US_FL_INITIAL_READ10) && srb->cmnd[0] == READ_10)) { if (srb->result == SAM_STAT_GOOD) { set_bit(US_FLIDX_READ10_WORKED, &us->dflags); } else if (test_bit(US_FLIDX_READ10_WORKED, &us->dflags)) { clear_bit(US_FLIDX_READ10_WORKED, &us->dflags); set_bit(US_FLIDX_REDO_READ10, &us->dflags); } if (test_bit(US_FLIDX_REDO_READ10, &us->dflags)) { clear_bit(US_FLIDX_REDO_READ10, &us->dflags); srb->result = DID_IMM_RETRY << 16; srb->sense_buffer[0] = 0; } } if ((srb->result == SAM_STAT_GOOD || srb->sense_buffer[2] == 0) && scsi_bufflen(srb) - scsi_get_resid(srb) < srb->underflow) srb->result = DID_ERROR << 16; last_sector_hacks(us, srb); return; Handle_Errors: scsi_lock(us_to_host(us)); set_bit(US_FLIDX_RESETTING, &us->dflags); clear_bit(US_FLIDX_ABORTING, &us->dflags); scsi_unlock(us_to_host(us)); mutex_unlock(&us->dev_mutex); result = usb_stor_port_reset(us); mutex_lock(&us->dev_mutex); if (result < 0) { scsi_lock(us_to_host(us)); usb_stor_report_device_reset(us); scsi_unlock(us_to_host(us)); us->transport_reset(us); } clear_bit(US_FLIDX_RESETTING, &us->dflags); last_sector_hacks(us, srb); }
/* Invoke the transport and basic error-handling/recovery methods * * This is used by the protocol layers to actually send the message to * the device and receive the response. */ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us) { int need_auto_sense; int result; /* send the command to the transport layer */ srb->resid = 0; result = us->transport(srb, us); /* if the command gets aborted by the higher layers, we need to * short-circuit all other processing */ if (test_bit(US_FLIDX_TIMED_OUT, &us->flags)) { US_DEBUGP("-- command was aborted\n"); srb->result = DID_ABORT << 16; goto Handle_Errors; } /* if there is a transport error, reset and don't auto-sense */ if (result == USB_STOR_TRANSPORT_ERROR) { US_DEBUGP("-- transport indicates error, resetting\n"); srb->result = DID_ERROR << 16; goto Handle_Errors; } /* if the transport provided its own sense data, don't auto-sense */ if (result == USB_STOR_TRANSPORT_NO_SENSE) { srb->result = SAM_STAT_CHECK_CONDITION; return; } srb->result = SAM_STAT_GOOD; /* Determine if we need to auto-sense * * I normally don't use a flag like this, but it's almost impossible * to understand what's going on here if I don't. */ need_auto_sense = 0; /* * If we're running the CB transport, which is incapable * of determining status on its own, we will auto-sense * unless the operation involved a data-in transfer. Devices * can signal most data-in errors by stalling the bulk-in pipe. */ if ((us->protocol == US_PR_CB || us->protocol == US_PR_DPCM_USB) && srb->sc_data_direction != DMA_FROM_DEVICE) { US_DEBUGP("-- CB transport device requiring auto-sense\n"); need_auto_sense = 1; } /* * If we have a failure, we're going to do a REQUEST_SENSE * automatically. Note that we differentiate between a command * "failure" and an "error" in the transport mechanism. */ if (result == USB_STOR_TRANSPORT_FAILED) { US_DEBUGP("-- transport indicates command failure\n"); need_auto_sense = 1; } /* * A short transfer on a command where we don't expect it * is unusual, but it doesn't mean we need to auto-sense. */ if ((srb->resid > 0) && !((srb->cmnd[0] == REQUEST_SENSE) || (srb->cmnd[0] == INQUIRY) || (srb->cmnd[0] == MODE_SENSE) || (srb->cmnd[0] == LOG_SENSE) || (srb->cmnd[0] == MODE_SENSE_10))) { US_DEBUGP("-- unexpectedly short transfer\n"); } /* Now, if we need to do the auto-sense, let's do it */ if (need_auto_sense) { int temp_result; void* old_request_buffer; unsigned short old_sg; unsigned old_request_bufflen; unsigned char old_sc_data_direction; unsigned char old_cmd_len; unsigned char old_cmnd[MAX_COMMAND_SIZE]; int old_resid; US_DEBUGP("Issuing auto-REQUEST_SENSE\n"); /* save the old command */ memcpy(old_cmnd, srb->cmnd, MAX_COMMAND_SIZE); old_cmd_len = srb->cmd_len; /* set the command and the LUN */ memset(srb->cmnd, 0, MAX_COMMAND_SIZE); srb->cmnd[0] = REQUEST_SENSE; srb->cmnd[1] = old_cmnd[1] & 0xE0; srb->cmnd[4] = 18; /* FIXME: we must do the protocol translation here */ if (us->subclass == US_SC_RBC || us->subclass == US_SC_SCSI) srb->cmd_len = 6; else srb->cmd_len = 12; /* set the transfer direction */ old_sc_data_direction = srb->sc_data_direction; srb->sc_data_direction = DMA_FROM_DEVICE; /* use the new buffer we have */ old_request_buffer = srb->request_buffer; srb->request_buffer = us->sensebuf; /* set the buffer length for transfer */ old_request_bufflen = srb->request_bufflen; srb->request_bufflen = US_SENSE_SIZE; /* set up for no scatter-gather use */ old_sg = srb->use_sg; srb->use_sg = 0; /* issue the auto-sense command */ old_resid = srb->resid; srb->resid = 0; temp_result = us->transport(us->srb, us); /* let's clean up right away */ memcpy(srb->sense_buffer, us->sensebuf, US_SENSE_SIZE); srb->resid = old_resid; srb->request_buffer = old_request_buffer; srb->request_bufflen = old_request_bufflen; srb->use_sg = old_sg; srb->sc_data_direction = old_sc_data_direction; srb->cmd_len = old_cmd_len; memcpy(srb->cmnd, old_cmnd, MAX_COMMAND_SIZE); if (test_bit(US_FLIDX_TIMED_OUT, &us->flags)) { US_DEBUGP("-- auto-sense aborted\n"); srb->result = DID_ABORT << 16; goto Handle_Errors; } if (temp_result != USB_STOR_TRANSPORT_GOOD) { US_DEBUGP("-- auto-sense failure\n"); /* we skip the reset if this happens to be a * multi-target device, since failure of an * auto-sense is perfectly valid */ srb->result = DID_ERROR << 16; if (!(us->flags & US_FL_SCM_MULT_TARG)) goto Handle_Errors; return; } US_DEBUGP("-- Result from auto-sense is %d\n", temp_result); US_DEBUGP("-- code: 0x%x, key: 0x%x, ASC: 0x%x, ASCQ: 0x%x\n", srb->sense_buffer[0], srb->sense_buffer[2] & 0xf, srb->sense_buffer[12], srb->sense_buffer[13]); #ifdef CONFIG_USB_STORAGE_DEBUG usb_stor_show_sense( srb->sense_buffer[2] & 0xf, srb->sense_buffer[12], srb->sense_buffer[13]); #endif /* set the result so the higher layers expect this data */ srb->result = SAM_STAT_CHECK_CONDITION; /* If things are really okay, then let's show that. Zero * out the sense buffer so the higher layers won't realize * we did an unsolicited auto-sense. */ if (result == USB_STOR_TRANSPORT_GOOD && /* Filemark 0, ignore EOM, ILI 0, no sense */ (srb->sense_buffer[2] & 0xaf) == 0 && /* No ASC or ASCQ */ srb->sense_buffer[12] == 0 && srb->sense_buffer[13] == 0) { srb->result = SAM_STAT_GOOD; srb->sense_buffer[0] = 0x0; } } /* Did we transfer less than the minimum amount required? */ if (srb->result == SAM_STAT_GOOD && srb->request_bufflen - srb->resid < srb->underflow) srb->result = (DID_ERROR << 16) | (SUGGEST_RETRY << 24); return; /* Error and abort processing: try to resynchronize with the device * by issuing a port reset. If that fails, try a class-specific * device reset. */ Handle_Errors: /* Let the SCSI layer know we are doing a reset, set the * RESETTING bit, and clear the ABORTING bit so that the reset * may proceed. */ scsi_lock(us_to_host(us)); usb_stor_report_bus_reset(us); set_bit(US_FLIDX_RESETTING, &us->flags); clear_bit(US_FLIDX_ABORTING, &us->flags); scsi_unlock(us_to_host(us)); result = usb_stor_port_reset(us); if (result < 0) { scsi_lock(us_to_host(us)); usb_stor_report_device_reset(us); scsi_unlock(us_to_host(us)); us->transport_reset(us); } clear_bit(US_FLIDX_RESETTING, &us->flags); }