static void scsi_decode_sense_buffer(const unsigned char *sense_buffer, int sense_len, struct scsi_sense_hdr *sshdr) { int k, num, res; res = scsi_normalize_sense(sense_buffer, sense_len, sshdr); if (0 == res) { /* this may be SCSI-1 sense data */ num = (sense_len < 32) ? sense_len : 32; printk("Unrecognized sense data (in hex):"); for (k = 0; k < num; ++k) { if (0 == (k % 16)) { printk("\n"); printk(KERN_INFO " "); } printk("%02x ", sense_buffer[k]); } printk("\n"); return; } }
static void scsi_decode_sense_buffer(const unsigned char *sense_buffer, int sense_len, struct scsi_sense_hdr *sshdr) { int k, num, res; res = scsi_normalize_sense(sense_buffer, sense_len, sshdr); if (0 == res) { /* this may be SCSI-1 sense data */ num = (sense_len < 32) ? sense_len : 32; ; for (k = 0; k < num; ++k) { if (0 == (k % 16)) { ; ; } ; } ; return; } }
static int clariion_std_inquiry(struct scsi_device *sdev, struct clariion_dh_data *csdev) { int err; char *sp_model; err = send_inquiry_cmd(sdev, 0, csdev); if (err != SCSI_DH_OK && csdev->senselen) { struct scsi_sense_hdr sshdr; if (scsi_normalize_sense(csdev->sense, SCSI_SENSE_BUFFERSIZE, &sshdr)) { sdev_printk(KERN_ERR, sdev, "%s: INQUIRY sense code " "%02x/%02x/%02x\n", CLARIION_NAME, sshdr.sense_key, sshdr.asc, sshdr.ascq); } err = SCSI_DH_IO; goto out; } sp_model = parse_sp_model(sdev, csdev->buffer); if (!sp_model) { err = SCSI_DH_DEV_UNSUPP; goto out; } /* * FC Series arrays do not support long trespass */ if (!strlen(sp_model) || !strncmp(sp_model, "FC",2)) csdev->flags |= CLARIION_SHORT_TRESPASS; sdev_printk(KERN_INFO, sdev, "%s: detected Clariion %s, flags %x\n", CLARIION_NAME, sp_model, csdev->flags); out: return err; }
int sr_do_ioctl(Scsi_CD *cd, struct packet_command *cgc) { struct scsi_device *SDev; struct scsi_sense_hdr sshdr; int result, err = 0, retries = 0; struct request_sense *sense = cgc->sense; SDev = cd->device; if (!sense) { sense = kmalloc(SCSI_SENSE_BUFFERSIZE, GFP_KERNEL); if (!sense) { err = -ENOMEM; goto out; } } retry: if (!scsi_block_when_processing_errors(SDev)) { err = -ENODEV; goto out; } memset(sense, 0, sizeof(*sense)); result = scsi_execute(SDev, cgc->cmd, cgc->data_direction, cgc->buffer, cgc->buflen, (char *)sense, cgc->timeout, IOCTL_RETRIES, 0, NULL); scsi_normalize_sense((char *)sense, sizeof(*sense), &sshdr); /* Minimal error checking. Ignore cases we know about, and report the rest. */ if (driver_byte(result) != 0) { switch (sshdr.sense_key) { case UNIT_ATTENTION: SDev->changed = 1; if (!cgc->quiet) sr_printk(KERN_INFO, cd, "disc change detected.\n"); if (retries++ < 10) goto retry; err = -ENOMEDIUM; break; case NOT_READY: /* This happens if there is no disc in drive */ if (sshdr.asc == 0x04 && sshdr.ascq == 0x01) { /* sense: Logical unit is in process of becoming ready */ if (!cgc->quiet) sr_printk(KERN_INFO, cd, "CDROM not ready yet.\n"); if (retries++ < 10) { /* sleep 2 sec and try again */ ssleep(2); goto retry; } else { /* 20 secs are enough? */ err = -ENOMEDIUM; break; } } if (!cgc->quiet) sr_printk(KERN_INFO, cd, "CDROM not ready. Make sure there " "is a disc in the drive.\n"); err = -ENOMEDIUM; break; case ILLEGAL_REQUEST: err = -EIO; if (sshdr.asc == 0x20 && sshdr.ascq == 0x00) /* sense: Invalid command operation code */ err = -EDRIVE_CANT_DO_THIS; break; default: err = -EIO; } } /* Wake up a process waiting for device */ out: if (!cgc->sense) kfree(sense); cgc->stat = err; return err; }
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); }
/* * alua_rtpg - Evaluate REPORT TARGET GROUP STATES * @sdev: the device to be evaluated. * @wait_for_transition: if nonzero, wait ALUA_FAILOVER_TIMEOUT seconds for device to exit transitioning state * * Evaluate the Target Port Group State. * Returns SCSI_DH_DEV_OFFLINED if the path is * found to be unusable. */ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_for_transition) { struct scsi_sense_hdr sense_hdr; int len, k, off, valid_states = 0; unsigned char *ucp; unsigned err, retval; unsigned long expiry, interval = 0; unsigned int tpg_desc_tbl_off; unsigned char orig_transition_tmo; if (!h->transition_tmo) expiry = round_jiffies_up(jiffies + ALUA_FAILOVER_TIMEOUT * HZ); else expiry = round_jiffies_up(jiffies + h->transition_tmo * HZ); retry: retval = submit_rtpg(sdev, h); if (retval) { if (!scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE, &sense_hdr)) { sdev_printk(KERN_INFO, sdev, "%s: rtpg failed, result %d\n", ALUA_DH_NAME, retval); if (driver_byte(retval) == DRIVER_BUSY) return SCSI_DH_DEV_TEMP_BUSY; return SCSI_DH_IO; } /* * submit_rtpg() has failed on existing arrays * when requesting extended header info, and * the array doesn't support extended headers, * even though it shouldn't according to T10. * The retry without rtpg_ext_hdr_req set * handles this. */ if (!(h->flags & ALUA_RTPG_EXT_HDR_UNSUPP) && sense_hdr.sense_key == ILLEGAL_REQUEST && sense_hdr.asc == 0x24 && sense_hdr.ascq == 0) { h->flags |= ALUA_RTPG_EXT_HDR_UNSUPP; goto retry; } /* * Retry on ALUA state transition or if any * UNIT ATTENTION occurred. */ if (sense_hdr.sense_key == NOT_READY && sense_hdr.asc == 0x04 && sense_hdr.ascq == 0x0a) err = SCSI_DH_RETRY; else if (sense_hdr.sense_key == UNIT_ATTENTION) err = SCSI_DH_RETRY; if (err == SCSI_DH_RETRY && time_before(jiffies, expiry)) { sdev_printk(KERN_ERR, sdev, "%s: rtpg retry\n", ALUA_DH_NAME); scsi_print_sense_hdr(sdev, ALUA_DH_NAME, &sense_hdr); goto retry; } sdev_printk(KERN_ERR, sdev, "%s: rtpg failed\n", ALUA_DH_NAME); scsi_print_sense_hdr(sdev, ALUA_DH_NAME, &sense_hdr); return SCSI_DH_IO; } len = get_unaligned_be32(&h->buff[0]) + 4; if (len > h->bufflen) { /* Resubmit with the correct length */ if (realloc_buffer(h, len)) { sdev_printk(KERN_WARNING, sdev, "%s: kmalloc buffer failed\n",__func__); /* Temporary failure, bypass */ return SCSI_DH_DEV_TEMP_BUSY; } goto retry; } orig_transition_tmo = h->transition_tmo; if ((h->buff[4] & RTPG_FMT_MASK) == RTPG_FMT_EXT_HDR && h->buff[5] != 0) h->transition_tmo = h->buff[5]; else h->transition_tmo = ALUA_FAILOVER_TIMEOUT; if (wait_for_transition && (orig_transition_tmo != h->transition_tmo)) { sdev_printk(KERN_INFO, sdev, "%s: transition timeout set to %d seconds\n", ALUA_DH_NAME, h->transition_tmo); expiry = jiffies + h->transition_tmo * HZ; } if ((h->buff[4] & RTPG_FMT_MASK) == RTPG_FMT_EXT_HDR) tpg_desc_tbl_off = 8; else tpg_desc_tbl_off = 4; for (k = tpg_desc_tbl_off, ucp = h->buff + tpg_desc_tbl_off; k < len; k += off, ucp += off) { if (h->group_id == get_unaligned_be16(&ucp[2])) { h->state = ucp[0] & 0x0f; h->pref = ucp[0] >> 7; valid_states = ucp[1]; } off = 8 + (ucp[7] * 4); }
/* 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); }
/* * alua_rtpg - Evaluate REPORT TARGET GROUP STATES * @sdev: the device to be evaluated. * * Evaluate the Target Port Group State. * Returns SCSI_DH_DEV_OFFLINED if the path is * found to be unuseable. */ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h) { struct scsi_sense_hdr sense_hdr; int len, k, off, valid_states = 0; unsigned char *ucp; unsigned err; unsigned long expiry, interval = 10; expiry = round_jiffies_up(jiffies + ALUA_FAILOVER_TIMEOUT); retry: err = submit_rtpg(sdev, h); if (err == SCSI_DH_IO && h->senselen > 0) { err = scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE, &sense_hdr); if (!err) return SCSI_DH_IO; err = alua_check_sense(sdev, &sense_hdr); if (err == ADD_TO_MLQUEUE && time_before(jiffies, expiry)) goto retry; sdev_printk(KERN_INFO, sdev, "%s: rtpg sense code %02x/%02x/%02x\n", ALUA_DH_NAME, sense_hdr.sense_key, sense_hdr.asc, sense_hdr.ascq); err = SCSI_DH_IO; } if (err != SCSI_DH_OK) return err; len = (h->buff[0] << 24) + (h->buff[1] << 16) + (h->buff[2] << 8) + h->buff[3] + 4; if (len > h->bufflen) { /* Resubmit with the correct length */ if (realloc_buffer(h, len)) { sdev_printk(KERN_WARNING, sdev, "%s: kmalloc buffer failed\n",__func__); /* Temporary failure, bypass */ return SCSI_DH_DEV_TEMP_BUSY; } goto retry; } for (k = 4, ucp = h->buff + 4; k < len; k += off, ucp += off) { if (h->group_id == (ucp[2] << 8) + ucp[3]) { h->state = ucp[0] & 0x0f; valid_states = ucp[1]; } off = 8 + (ucp[7] * 4); } sdev_printk(KERN_INFO, sdev, "%s: port group %02x state %c supports %c%c%c%c%c%c%c\n", ALUA_DH_NAME, h->group_id, print_alua_state(h->state), valid_states&TPGS_SUPPORT_TRANSITION?'T':'t', valid_states&TPGS_SUPPORT_OFFLINE?'O':'o', valid_states&TPGS_SUPPORT_LBA_DEPENDENT?'L':'l', valid_states&TPGS_SUPPORT_UNAVAILABLE?'U':'u', valid_states&TPGS_SUPPORT_STANDBY?'S':'s', valid_states&TPGS_SUPPORT_NONOPTIMIZED?'N':'n', valid_states&TPGS_SUPPORT_OPTIMIZED?'A':'a'); switch (h->state) { case TPGS_STATE_TRANSITIONING: if (time_before(jiffies, expiry)) { /* State transition, retry */ interval *= 10; msleep(interval); goto retry; } /* Transitioning time exceeded, set port to standby */ err = SCSI_DH_RETRY; h->state = TPGS_STATE_STANDBY; break; case TPGS_STATE_OFFLINE: case TPGS_STATE_UNAVAILABLE: /* Path unuseable for unavailable/offline */ err = SCSI_DH_DEV_OFFLINED; break; default: /* Useable path if active */ err = SCSI_DH_OK; break; } return err; }
/* Print sense information */ void __scsi_print_sense(const char *name, const unsigned char *sense_buffer, int sense_len) { int k, num, res; unsigned int info; struct scsi_sense_hdr ssh; res = scsi_normalize_sense(sense_buffer, sense_len, &ssh); if (0 == res) { /* this may be SCSI-1 sense data */ num = (sense_len < 32) ? sense_len : 32; printk(KERN_INFO "Unrecognized sense data (in hex):"); for (k = 0; k < num; ++k) { if (0 == (k % 16)) { printk("\n"); printk(KERN_INFO " "); } printk("%02x ", sense_buffer[k]); } printk("\n"); return; } scsi_print_sense_hdr(name, &ssh); if (ssh.response_code < 0x72) { /* only decode extras for "fixed" format now */ char buff[80]; int blen, fixed_valid; fixed_valid = sense_buffer[0] & 0x80; info = ((sense_buffer[3] << 24) | (sense_buffer[4] << 16) | (sense_buffer[5] << 8) | sense_buffer[6]); res = 0; memset(buff, 0, sizeof(buff)); blen = sizeof(buff) - 1; if (fixed_valid) res += snprintf(buff + res, blen - res, "Info fld=0x%x", info); if (sense_buffer[2] & 0x80) { /* current command has read a filemark */ if (res > 0) res += snprintf(buff + res, blen - res, ", "); res += snprintf(buff + res, blen - res, "FMK"); } if (sense_buffer[2] & 0x40) { /* end-of-medium condition exists */ if (res > 0) res += snprintf(buff + res, blen - res, ", "); res += snprintf(buff + res, blen - res, "EOM"); } if (sense_buffer[2] & 0x20) { /* incorrect block length requested */ if (res > 0) res += snprintf(buff + res, blen - res, ", "); res += snprintf(buff + res, blen - res, "ILI"); } if (res > 0) printk(KERN_INFO "%s\n", buff); } else if (ssh.additional_length > 0) { /* descriptor format with sense descriptors */ num = 8 + ssh.additional_length; num = (sense_len < num) ? sense_len : num; printk(KERN_INFO "Descriptor sense data with sense " "descriptors (in hex):"); for (k = 0; k < num; ++k) { if (0 == (k % 16)) { printk("\n"); printk(KERN_INFO " "); } printk("%02x ", sense_buffer[k]); } printk("\n"); } }
/* * alua_rtpg - Evaluate REPORT TARGET GROUP STATES * @sdev: the device to be evaluated. * * Evaluate the Target Port Group State. * Returns SCSI_DH_DEV_OFFLINED if the path is * found to be unuseable. */ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h) { struct scsi_sense_hdr sense_hdr; int len, k, off, valid_states = 0; char *ucp; unsigned err; retry: err = submit_rtpg(sdev, h); if (err == SCSI_DH_IO && h->senselen > 0) { err = scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE, &sense_hdr); if (!err) return SCSI_DH_IO; err = alua_check_sense(sdev, &sense_hdr); if (err == ADD_TO_MLQUEUE) goto retry; sdev_printk(KERN_INFO, sdev, "%s: rtpg sense code %02x/%02x/%02x\n", ALUA_DH_NAME, sense_hdr.sense_key, sense_hdr.asc, sense_hdr.ascq); err = SCSI_DH_IO; } if (err != SCSI_DH_OK) return err; len = (h->buff[0] << 24) + (h->buff[1] << 16) + (h->buff[2] << 8) + h->buff[3] + 4; if (len > h->bufflen) { /* Resubmit with the correct length */ if (realloc_buffer(h, len)) { sdev_printk(KERN_WARNING, sdev, "%s: kmalloc buffer failed\n",__func__); /* Temporary failure, bypass */ return SCSI_DH_DEV_TEMP_BUSY; } goto retry; } for (k = 4, ucp = h->buff + 4; k < len; k += off, ucp += off) { if (h->group_id == (ucp[2] << 8) + ucp[3]) { h->state = ucp[0] & 0x0f; valid_states = ucp[1]; } off = 8 + (ucp[7] * 4); } sdev_printk(KERN_INFO, sdev, "%s: port group %02x state %c supports %c%c%c%c%c%c\n", ALUA_DH_NAME, h->group_id, print_alua_state(h->state), valid_states&TPGS_SUPPORT_TRANSITION?'T':'t', valid_states&TPGS_SUPPORT_OFFLINE?'O':'o', valid_states&TPGS_SUPPORT_UNAVAILABLE?'U':'u', valid_states&TPGS_SUPPORT_STANDBY?'S':'s', valid_states&TPGS_SUPPORT_NONOPTIMIZED?'N':'n', valid_states&TPGS_SUPPORT_OPTIMIZED?'A':'a'); if (h->tpgs & TPGS_MODE_EXPLICIT) { switch (h->state) { case TPGS_STATE_TRANSITIONING: /* State transition, retry */ goto retry; break; case TPGS_STATE_OFFLINE: /* Path is offline, fail */ err = SCSI_DH_DEV_OFFLINED; break; default: break; } } else { /* Only Implicit ALUA support */ if (h->state == TPGS_STATE_OPTIMIZED || h->state == TPGS_STATE_NONOPTIMIZED || h->state == TPGS_STATE_STANDBY) /* Useable path if active */ err = SCSI_DH_OK; else /* Path unuseable for unavailable/offline */ err = SCSI_DH_DEV_OFFLINED; } return err; }
/* * alua_rtpg - Evaluate REPORT TARGET GROUP STATES * @sdev: the device to be evaluated. * * Evaluate the Target Port Group State. * Returns SCSI_DH_DEV_OFFLINED if the path is * found to be unuseable. */ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h) { struct scsi_sense_hdr sense_hdr; int len, k, off, valid_states = 0; unsigned char *ucp; unsigned err; bool rtpg_ext_hdr_req = 1; unsigned long expiry, interval = 0; unsigned int tpg_desc_tbl_off; unsigned char orig_transition_tmo; if (!h->transition_tmo) expiry = round_jiffies_up(jiffies + ALUA_FAILOVER_TIMEOUT * HZ); else expiry = round_jiffies_up(jiffies + h->transition_tmo * HZ); retry: err = submit_rtpg(sdev, h, rtpg_ext_hdr_req); if (err == SCSI_DH_IO && h->senselen > 0) { err = scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE, &sense_hdr); if (!err) return SCSI_DH_IO; /* * submit_rtpg() has failed on existing arrays * when requesting extended header info, and * the array doesn't support extended headers, * even though it shouldn't according to T10. * The retry without rtpg_ext_hdr_req set * handles this. */ if (rtpg_ext_hdr_req == 1 && sense_hdr.sense_key == ILLEGAL_REQUEST && sense_hdr.asc == 0x24 && sense_hdr.ascq == 0) { rtpg_ext_hdr_req = 0; goto retry; } err = alua_check_sense(sdev, &sense_hdr); if (err == ADD_TO_MLQUEUE && time_before(jiffies, expiry)) goto retry; sdev_printk(KERN_INFO, sdev, "%s: rtpg sense code %02x/%02x/%02x\n", ALUA_DH_NAME, sense_hdr.sense_key, sense_hdr.asc, sense_hdr.ascq); err = SCSI_DH_IO; } if (err != SCSI_DH_OK) return err; len = (h->buff[0] << 24) + (h->buff[1] << 16) + (h->buff[2] << 8) + h->buff[3] + 4; if (len > h->bufflen) { /* Resubmit with the correct length */ if (realloc_buffer(h, len)) { sdev_printk(KERN_WARNING, sdev, "%s: kmalloc buffer failed\n",__func__); /* Temporary failure, bypass */ return SCSI_DH_DEV_TEMP_BUSY; } goto retry; } orig_transition_tmo = h->transition_tmo; if ((h->buff[4] & RTPG_FMT_MASK) == RTPG_FMT_EXT_HDR && h->buff[5] != 0) h->transition_tmo = h->buff[5]; else h->transition_tmo = ALUA_FAILOVER_TIMEOUT; if (orig_transition_tmo != h->transition_tmo) { sdev_printk(KERN_INFO, sdev, "%s: transition timeout set to %d seconds\n", ALUA_DH_NAME, h->transition_tmo); expiry = jiffies + h->transition_tmo * HZ; } if ((h->buff[4] & RTPG_FMT_MASK) == RTPG_FMT_EXT_HDR) tpg_desc_tbl_off = 8; else tpg_desc_tbl_off = 4; for (k = tpg_desc_tbl_off, ucp = h->buff + tpg_desc_tbl_off; k < len; k += off, ucp += off) { if (h->group_id == (ucp[2] << 8) + ucp[3]) { h->state = ucp[0] & 0x0f; h->pref = ucp[0] >> 7; valid_states = ucp[1]; } off = 8 + (ucp[7] * 4); }