linux-scsi.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: James Bottomley <jbottomley@parallels.com>
To: "hare@suse.de" <hare@suse.de>
Cc: "hch@lst.de" <hch@lst.de>,
	"linux-scsi@vger.kernel.org" <linux-scsi@vger.kernel.org>,
	"Matthias.Roessler@ts.fujitsu.com"
	<Matthias.Roessler@ts.fujitsu.com>
Subject: Re: [PATCH] scsi_scan: Send TEST UNIT READY to LUN0 before LUN scanning
Date: Fri, 5 Dec 2014 00:19:22 +0000	[thread overview]
Message-ID: <1417738774.8998.21.camel@parallels.com> (raw)
In-Reply-To: <1417711162-102950-1-git-send-email-hare@suse.de>

On Thu, 2014-12-04 at 17:39 +0100, Hannes Reinecke wrote:
[...]
> diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
> index 0af7133..ca39e32 100644
> --- a/drivers/scsi/scsi_scan.c
> +++ b/drivers/scsi/scsi_scan.c
> @@ -119,6 +119,13 @@ MODULE_PARM_DESC(inq_timeout,
>  		 "Timeout (in seconds) waiting for devices to answer INQUIRY."
>  		 " Default is 20. Some devices may need more; most need less.");
>  
> +static unsigned int scsi_scan_timeout = SCSI_TIMEOUT/HZ + 58;
> +
> +module_param_named(scan_timeout, scsi_scan_timeout, uint, S_IRUGO|S_IWUSR);
> +MODULE_PARM_DESC(scan_timeout,
> +		 "Timeout (in seconds) waiting for devices to become ready"
> +		 " after INQUIRY. Default is 60.");
> +
>  /* This lock protects only this list */
>  static DEFINE_SPINLOCK(async_scan_lock);
>  static LIST_HEAD(scanning_hosts);
> @@ -719,19 +726,6 @@ static int scsi_probe_lun(struct scsi_device *sdev, unsigned char *inq_result,
>  	}
>  
>  	/*
> -	 * Related to the above issue:
> -	 *
> -	 * XXX Devices (disk or all?) should be sent a TEST UNIT READY,
> -	 * and if not ready, sent a START_STOP to start (maybe spin up) and
> -	 * then send the INQUIRY again, since the INQUIRY can change after
> -	 * a device is initialized.

You're not sending a start_stop unit, so why is this being deleted?  Any
unstarted unit will still return initialization command required and may
or may not return lun data.

> -	 *
> -	 * Ideally, start a device if explicitly asked to do so.  This
> -	 * assumes that a device is spun up on power on, spun down on
> -	 * request, and then spun up on request.
> -	 */
> -
> -	/*
>  	 * The scanning code needs to know the scsi_level, even if no
>  	 * device is attached at LUN 0 (SCSI_SCAN_TARGET_PRESENT) so
>  	 * non-zero LUNs can be scanned.
> @@ -756,6 +750,65 @@ static int scsi_probe_lun(struct scsi_device *sdev, unsigned char *inq_result,
>  }
>  
>  /**
> + * scsi_test_lun - waiting for a LUN to become ready
> + * @sdev:	scsi_device to test
> + *
> + * Description:
> + *     Wait for the lun associated with @sdev to become ready
> + *
> + *     Send a TEST UNIT READY to detect any unit attention conditions.
> + *     Retry TEST UNIT READY for up to @scsi_scan_timeout if the
> + *     returned sense key is 02/04/01 (Not ready, Logical Unit is
> + *     in process of becoming ready)
> + **/
> +static int
> +scsi_test_lun(struct scsi_device *sdev)
> +{
> +	struct scsi_sense_hdr sshdr;
> +	int res = SCSI_SCAN_TARGET_PRESENT;
> +	int tur_result;
> +	unsigned long tur_timeout = jiffies + scsi_scan_timeout * HZ;
> +
> +	/* Skip for older devices */
> +	if (sdev->scsi_level <= SCSI_3)
> +		return SCSI_SCAN_LUN_PRESENT;
> +
> +	/*
> +	 * Wait for the device to become ready.
> +	 *
> +	 * Some targets take some time before the firmware is
> +	 * fully initialized, during which time they might not
> +	 * be able to fill out any REPORT_LUN command correctly.
> +	 * And as we're not capable of handling the
> +	 * INQUIRY DATA CHANGED unit attention correctly we'd
> +	 * rather wait here.

Can't we just fix that?  All you need is rescan to re-read the inquiry
data.

> +	 */
> +	do {
> +		tur_result = scsi_test_unit_ready(sdev, SCSI_TIMEOUT,
> +							  3, &sshdr);
> +		if (!tur_result) {
> +			res = SCSI_SCAN_LUN_PRESENT;
> +			break;
> +		}
> +		if ((driver_byte(tur_result) & DRIVER_SENSE) &&
> +		    scsi_sense_valid(&sshdr)) {
> +			SCSI_LOG_SCAN_BUS(3, sdev_printk(KERN_INFO, sdev,
> +				"scsi_scan: tur returned %02x/%02x/%02x\n",
> +				sshdr.sense_key, sshdr.asc, sshdr.ascq));

If we're waiting 60s and coming in here every 100ms we'll get 600 of
these in the log ... that's going to drown out anything that came before
it.

> +			if (sshdr.sense_key == NOT_READY &&
> +			    sshdr.asc == 0x04 && sshdr.ascq == 0x01) {
> +				/* Logical Unit is in process
> +				 * of becoming ready */
> +				msleep(100);
> +				continue;
> +			}
> +		}
> +		res = SCSI_SCAN_LUN_PRESENT;

Aren't you missing a break here?  Otherwise how does an unexpected
return code from the test unit ready do anything other than loop around
dumping log messages until 60s have expired.

> +	} while (time_before_eq(jiffies, tur_timeout));
> +	return res;
> +}
> +
> +/**
>   * scsi_add_lun - allocate and fully initialze a scsi_device
>   * @sdev:	holds information to be stored in the new scsi_device
>   * @inq_result:	holds the result of a previous INQUIRY to the LUN
> @@ -1159,6 +1212,15 @@ static int scsi_probe_and_add_lun(struct scsi_target *starget,
>  		goto out_free_result;
>  	}
>  
> +	if (bflags & BLIST_TEST_LUN0) {
> +		res = scsi_test_lun(sdev);
> +		if (res == SCSI_SCAN_TARGET_PRESENT) {
> +			SCSI_LOG_SCAN_BUS(1, sdev_printk(KERN_INFO, sdev,
> +				"scsi scan: device not ready\n"));
> +			goto out_free_result;
> +		}
> +	}
> +
>  	res = scsi_add_lun(sdev, result, &bflags, shost->async_scan);

So any return other than SCSI_SCAN_TARGET_PRESENT gets thrown away.  Why
not just return true/false from the scsi_test_lun(sdev) and set res to
SCSI_SCAN_TARGET_PRESENT in the if clause if it fails?  That should
greatly simplify the logic inside scsi_test_lun().

James


  parent reply	other threads:[~2014-12-05  0:19 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-12-04 16:39 [PATCH] scsi_scan: Send TEST UNIT READY to LUN0 before LUN scanning Hannes Reinecke
2014-12-04 20:00 ` Elliott, Robert (Server Storage)
2014-12-05  7:02   ` Hannes Reinecke
2014-12-04 23:43 ` Sebastian Herbszt
2014-12-05 18:34   ` Hannes Reinecke
2014-12-08 17:11     ` Matthias Roessler
2014-12-05  0:19 ` James Bottomley [this message]
2014-12-05 18:40   ` Hannes Reinecke
2014-12-30 12:09     ` Christoph Hellwig

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1417738774.8998.21.camel@parallels.com \
    --to=jbottomley@parallels.com \
    --cc=Matthias.Roessler@ts.fujitsu.com \
    --cc=hare@suse.de \
    --cc=hch@lst.de \
    --cc=linux-scsi@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).