aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Bottomley <James.Bottomley@SteelEye.com>2007-12-02 12:10:40 -0500
committerJames Bottomley <James.Bottomley@HansenPartnership.com>2008-01-11 19:22:50 -0500
commit001aac257cf8adbe90cdcba6e07f8d12dfc8fa6b (patch)
tree0eb6294049245e05f47fdb76e3f878c78c015d88
parent4a03d90e35bc5273d27301fa669d4b2103196f94 (diff)
[SCSI] sd,sr: add early detection of medium not present
The current scsi_test_unit_ready() is updated to return sense code information (in struct scsi_sense_hdr). The sd and sr drivers are changed to interpret the sense code return asc 0x3a as no media and adjust the device status accordingly. Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
-rw-r--r--drivers/scsi/scsi_ioctl.c2
-rw-r--r--drivers/scsi/scsi_lib.c46
-rw-r--r--drivers/scsi/sd.c13
-rw-r--r--drivers/scsi/sr.c19
-rw-r--r--include/scsi/scsi_device.h2
5 files changed, 63 insertions, 19 deletions
diff --git a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c
index 83e144716901..28b19ef26309 100644
--- a/drivers/scsi/scsi_ioctl.c
+++ b/drivers/scsi/scsi_ioctl.c
@@ -244,7 +244,7 @@ int scsi_ioctl(struct scsi_device *sdev, int cmd, void __user *arg)
244 return scsi_set_medium_removal(sdev, SCSI_REMOVAL_ALLOW); 244 return scsi_set_medium_removal(sdev, SCSI_REMOVAL_ALLOW);
245 case SCSI_IOCTL_TEST_UNIT_READY: 245 case SCSI_IOCTL_TEST_UNIT_READY:
246 return scsi_test_unit_ready(sdev, IOCTL_NORMAL_TIMEOUT, 246 return scsi_test_unit_ready(sdev, IOCTL_NORMAL_TIMEOUT,
247 NORMAL_RETRIES); 247 NORMAL_RETRIES, NULL);
248 case SCSI_IOCTL_START_UNIT: 248 case SCSI_IOCTL_START_UNIT:
249 scsi_cmd[0] = START_STOP; 249 scsi_cmd[0] = START_STOP;
250 scsi_cmd[1] = 0; 250 scsi_cmd[1] = 0;
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index aa17e718666e..db52222885b7 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -1973,27 +1973,57 @@ scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage,
1973} 1973}
1974EXPORT_SYMBOL(scsi_mode_sense); 1974EXPORT_SYMBOL(scsi_mode_sense);
1975 1975
1976/**
1977 * scsi_test_unit_ready - test if unit is ready
1978 * @sdev: scsi device to change the state of.
1979 * @timeout: command timeout
1980 * @retries: number of retries before failing
1981 * @sshdr_external: Optional pointer to struct scsi_sense_hdr for
1982 * returning sense. Make sure that this is cleared before passing
1983 * in.
1984 *
1985 * Returns zero if unsuccessful or an error if TUR failed. For
1986 * removable media, a return of NOT_READY or UNIT_ATTENTION is
1987 * translated to success, with the ->changed flag updated.
1988 **/
1976int 1989int
1977scsi_test_unit_ready(struct scsi_device *sdev, int timeout, int retries) 1990scsi_test_unit_ready(struct scsi_device *sdev, int timeout, int retries,
1991 struct scsi_sense_hdr *sshdr_external)
1978{ 1992{
1979 char cmd[] = { 1993 char cmd[] = {
1980 TEST_UNIT_READY, 0, 0, 0, 0, 0, 1994 TEST_UNIT_READY, 0, 0, 0, 0, 0,
1981 }; 1995 };
1982 struct scsi_sense_hdr sshdr; 1996 struct scsi_sense_hdr *sshdr;
1983 int result; 1997 int result;
1984 1998
1985 result = scsi_execute_req(sdev, cmd, DMA_NONE, NULL, 0, &sshdr, 1999 if (!sshdr_external)
1986 timeout, retries); 2000 sshdr = kzalloc(sizeof(*sshdr), GFP_KERNEL);
2001 else
2002 sshdr = sshdr_external;
2003
2004 /* try to eat the UNIT_ATTENTION if there are enough retries */
2005 do {
2006 result = scsi_execute_req(sdev, cmd, DMA_NONE, NULL, 0, sshdr,
2007 timeout, retries);
2008 } while ((driver_byte(result) & DRIVER_SENSE) &&
2009 sshdr && sshdr->sense_key == UNIT_ATTENTION &&
2010 --retries);
2011
2012 if (!sshdr)
2013 /* could not allocate sense buffer, so can't process it */
2014 return result;
1987 2015
1988 if ((driver_byte(result) & DRIVER_SENSE) && sdev->removable) { 2016 if ((driver_byte(result) & DRIVER_SENSE) && sdev->removable) {
1989 2017
1990 if ((scsi_sense_valid(&sshdr)) && 2018 if ((scsi_sense_valid(sshdr)) &&
1991 ((sshdr.sense_key == UNIT_ATTENTION) || 2019 ((sshdr->sense_key == UNIT_ATTENTION) ||
1992 (sshdr.sense_key == NOT_READY))) { 2020 (sshdr->sense_key == NOT_READY))) {
1993 sdev->changed = 1; 2021 sdev->changed = 1;
1994 result = 0; 2022 result = 0;
1995 } 2023 }
1996 } 2024 }
2025 if (!sshdr_external)
2026 kfree(sshdr);
1997 return result; 2027 return result;
1998} 2028}
1999EXPORT_SYMBOL(scsi_test_unit_ready); 2029EXPORT_SYMBOL(scsi_test_unit_ready);
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 18343a6acd8e..212f6bcfd457 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -736,6 +736,7 @@ static int sd_media_changed(struct gendisk *disk)
736{ 736{
737 struct scsi_disk *sdkp = scsi_disk(disk); 737 struct scsi_disk *sdkp = scsi_disk(disk);
738 struct scsi_device *sdp = sdkp->device; 738 struct scsi_device *sdp = sdkp->device;
739 struct scsi_sense_hdr *sshdr = NULL;
739 int retval; 740 int retval;
740 741
741 SCSI_LOG_HLQUEUE(3, sd_printk(KERN_INFO, sdkp, "sd_media_changed\n")); 742 SCSI_LOG_HLQUEUE(3, sd_printk(KERN_INFO, sdkp, "sd_media_changed\n"));
@@ -766,8 +767,11 @@ static int sd_media_changed(struct gendisk *disk)
766 */ 767 */
767 retval = -ENODEV; 768 retval = -ENODEV;
768 769
769 if (scsi_block_when_processing_errors(sdp)) 770 if (scsi_block_when_processing_errors(sdp)) {
770 retval = scsi_test_unit_ready(sdp, SD_TIMEOUT, SD_MAX_RETRIES); 771 sshdr = kzalloc(sizeof(*sshdr), GFP_KERNEL);
772 retval = scsi_test_unit_ready(sdp, SD_TIMEOUT, SD_MAX_RETRIES,
773 sshdr);
774 }
771 775
772 /* 776 /*
773 * Unable to test, unit probably not ready. This usually 777 * Unable to test, unit probably not ready. This usually
@@ -775,7 +779,9 @@ static int sd_media_changed(struct gendisk *disk)
775 * and we will figure it out later once the drive is 779 * and we will figure it out later once the drive is
776 * available again. 780 * available again.
777 */ 781 */
778 if (retval) { 782 if (retval || (scsi_sense_valid(sshdr) &&
783 /* 0x3a is medium not present */
784 sshdr->asc == 0x3a)) {
779 set_media_not_present(sdkp); 785 set_media_not_present(sdkp);
780 retval = 1; 786 retval = 1;
781 goto out; 787 goto out;
@@ -794,6 +800,7 @@ out:
794 if (retval != sdkp->previous_state) 800 if (retval != sdkp->previous_state)
795 sdev_evt_send_simple(sdp, SDEV_EVT_MEDIA_CHANGE, GFP_KERNEL); 801 sdev_evt_send_simple(sdp, SDEV_EVT_MEDIA_CHANGE, GFP_KERNEL);
796 sdkp->previous_state = retval; 802 sdkp->previous_state = retval;
803 kfree(sshdr);
797 return retval; 804 return retval;
798} 805}
799 806
diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c
index 7702681d93f9..896be4ab285d 100644
--- a/drivers/scsi/sr.c
+++ b/drivers/scsi/sr.c
@@ -179,18 +179,24 @@ static int sr_media_change(struct cdrom_device_info *cdi, int slot)
179{ 179{
180 struct scsi_cd *cd = cdi->handle; 180 struct scsi_cd *cd = cdi->handle;
181 int retval; 181 int retval;
182 struct scsi_sense_hdr *sshdr;
182 183
183 if (CDSL_CURRENT != slot) { 184 if (CDSL_CURRENT != slot) {
184 /* no changer support */ 185 /* no changer support */
185 return -EINVAL; 186 return -EINVAL;
186 } 187 }
187 188
188 retval = scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES); 189 sshdr = kzalloc(sizeof(*sshdr), GFP_KERNEL);
189 if (retval) { 190 retval = scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES,
190 /* Unable to test, unit probably not ready. This usually 191 sshdr);
191 * means there is no disc in the drive. Mark as changed, 192 if (retval || (scsi_sense_valid(sshdr) &&
192 * and we will figure it out later once the drive is 193 /* 0x3a is medium not present */
193 * available again. */ 194 sshdr->asc == 0x3a)) {
195 /* Media not present or unable to test, unit probably not
196 * ready. This usually means there is no disc in the drive.
197 * Mark as changed, and we will figure it out later once
198 * the drive is available again.
199 */
194 cd->device->changed = 1; 200 cd->device->changed = 1;
195 /* This will force a flush, if called from check_disk_change */ 201 /* This will force a flush, if called from check_disk_change */
196 retval = 1; 202 retval = 1;
@@ -213,6 +219,7 @@ out:
213 sdev_evt_send_simple(cd->device, SDEV_EVT_MEDIA_CHANGE, 219 sdev_evt_send_simple(cd->device, SDEV_EVT_MEDIA_CHANGE,
214 GFP_KERNEL); 220 GFP_KERNEL);
215 cd->previous_state = retval; 221 cd->previous_state = retval;
222 kfree(sshdr);
216 223
217 return retval; 224 return retval;
218} 225}
diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h
index 45bb12b54175..e0c645ac5014 100644
--- a/include/scsi/scsi_device.h
+++ b/include/scsi/scsi_device.h
@@ -295,7 +295,7 @@ extern int scsi_mode_select(struct scsi_device *sdev, int pf, int sp,
295 struct scsi_mode_data *data, 295 struct scsi_mode_data *data,
296 struct scsi_sense_hdr *); 296 struct scsi_sense_hdr *);
297extern int scsi_test_unit_ready(struct scsi_device *sdev, int timeout, 297extern int scsi_test_unit_ready(struct scsi_device *sdev, int timeout,
298 int retries); 298 int retries, struct scsi_sense_hdr *sshdr);
299extern int scsi_device_set_state(struct scsi_device *sdev, 299extern int scsi_device_set_state(struct scsi_device *sdev,
300 enum scsi_device_state state); 300 enum scsi_device_state state);
301extern struct scsi_event *sdev_evt_alloc(enum scsi_device_event evt_type, 301extern struct scsi_event *sdev_evt_alloc(enum scsi_device_event evt_type,