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;
	}
}
Exemple #2
0
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;
	}
}
Exemple #3
0
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;
}
Exemple #4
0
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;
}
Exemple #5
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);
}
Exemple #6
0
/*
 * 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);
}
Exemple #8
0
/*
 * 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;
}
Exemple #9
0
/* 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");
	}
}
Exemple #10
0
/*
 * 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;
}
Exemple #11
0
/*
 * 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);
	}