mirror of https://gitee.com/openkylin/linux.git
[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>
This commit is contained in:
parent
4a03d90e35
commit
001aac257c
|
@ -244,7 +244,7 @@ int scsi_ioctl(struct scsi_device *sdev, int cmd, void __user *arg)
|
|||
return scsi_set_medium_removal(sdev, SCSI_REMOVAL_ALLOW);
|
||||
case SCSI_IOCTL_TEST_UNIT_READY:
|
||||
return scsi_test_unit_ready(sdev, IOCTL_NORMAL_TIMEOUT,
|
||||
NORMAL_RETRIES);
|
||||
NORMAL_RETRIES, NULL);
|
||||
case SCSI_IOCTL_START_UNIT:
|
||||
scsi_cmd[0] = START_STOP;
|
||||
scsi_cmd[1] = 0;
|
||||
|
|
|
@ -1973,27 +1973,57 @@ scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage,
|
|||
}
|
||||
EXPORT_SYMBOL(scsi_mode_sense);
|
||||
|
||||
/**
|
||||
* scsi_test_unit_ready - test if unit is ready
|
||||
* @sdev: scsi device to change the state of.
|
||||
* @timeout: command timeout
|
||||
* @retries: number of retries before failing
|
||||
* @sshdr_external: Optional pointer to struct scsi_sense_hdr for
|
||||
* returning sense. Make sure that this is cleared before passing
|
||||
* in.
|
||||
*
|
||||
* Returns zero if unsuccessful or an error if TUR failed. For
|
||||
* removable media, a return of NOT_READY or UNIT_ATTENTION is
|
||||
* translated to success, with the ->changed flag updated.
|
||||
**/
|
||||
int
|
||||
scsi_test_unit_ready(struct scsi_device *sdev, int timeout, int retries)
|
||||
scsi_test_unit_ready(struct scsi_device *sdev, int timeout, int retries,
|
||||
struct scsi_sense_hdr *sshdr_external)
|
||||
{
|
||||
char cmd[] = {
|
||||
TEST_UNIT_READY, 0, 0, 0, 0, 0,
|
||||
};
|
||||
struct scsi_sense_hdr sshdr;
|
||||
struct scsi_sense_hdr *sshdr;
|
||||
int result;
|
||||
|
||||
result = scsi_execute_req(sdev, cmd, DMA_NONE, NULL, 0, &sshdr,
|
||||
timeout, retries);
|
||||
|
||||
if (!sshdr_external)
|
||||
sshdr = kzalloc(sizeof(*sshdr), GFP_KERNEL);
|
||||
else
|
||||
sshdr = sshdr_external;
|
||||
|
||||
/* try to eat the UNIT_ATTENTION if there are enough retries */
|
||||
do {
|
||||
result = scsi_execute_req(sdev, cmd, DMA_NONE, NULL, 0, sshdr,
|
||||
timeout, retries);
|
||||
} while ((driver_byte(result) & DRIVER_SENSE) &&
|
||||
sshdr && sshdr->sense_key == UNIT_ATTENTION &&
|
||||
--retries);
|
||||
|
||||
if (!sshdr)
|
||||
/* could not allocate sense buffer, so can't process it */
|
||||
return result;
|
||||
|
||||
if ((driver_byte(result) & DRIVER_SENSE) && sdev->removable) {
|
||||
|
||||
if ((scsi_sense_valid(&sshdr)) &&
|
||||
((sshdr.sense_key == UNIT_ATTENTION) ||
|
||||
(sshdr.sense_key == NOT_READY))) {
|
||||
if ((scsi_sense_valid(sshdr)) &&
|
||||
((sshdr->sense_key == UNIT_ATTENTION) ||
|
||||
(sshdr->sense_key == NOT_READY))) {
|
||||
sdev->changed = 1;
|
||||
result = 0;
|
||||
}
|
||||
}
|
||||
if (!sshdr_external)
|
||||
kfree(sshdr);
|
||||
return result;
|
||||
}
|
||||
EXPORT_SYMBOL(scsi_test_unit_ready);
|
||||
|
|
|
@ -736,6 +736,7 @@ static int sd_media_changed(struct gendisk *disk)
|
|||
{
|
||||
struct scsi_disk *sdkp = scsi_disk(disk);
|
||||
struct scsi_device *sdp = sdkp->device;
|
||||
struct scsi_sense_hdr *sshdr = NULL;
|
||||
int retval;
|
||||
|
||||
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)
|
|||
*/
|
||||
retval = -ENODEV;
|
||||
|
||||
if (scsi_block_when_processing_errors(sdp))
|
||||
retval = scsi_test_unit_ready(sdp, SD_TIMEOUT, SD_MAX_RETRIES);
|
||||
if (scsi_block_when_processing_errors(sdp)) {
|
||||
sshdr = kzalloc(sizeof(*sshdr), GFP_KERNEL);
|
||||
retval = scsi_test_unit_ready(sdp, SD_TIMEOUT, SD_MAX_RETRIES,
|
||||
sshdr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Unable to test, unit probably not ready. This usually
|
||||
|
@ -775,7 +779,9 @@ static int sd_media_changed(struct gendisk *disk)
|
|||
* and we will figure it out later once the drive is
|
||||
* available again.
|
||||
*/
|
||||
if (retval) {
|
||||
if (retval || (scsi_sense_valid(sshdr) &&
|
||||
/* 0x3a is medium not present */
|
||||
sshdr->asc == 0x3a)) {
|
||||
set_media_not_present(sdkp);
|
||||
retval = 1;
|
||||
goto out;
|
||||
|
@ -794,6 +800,7 @@ static int sd_media_changed(struct gendisk *disk)
|
|||
if (retval != sdkp->previous_state)
|
||||
sdev_evt_send_simple(sdp, SDEV_EVT_MEDIA_CHANGE, GFP_KERNEL);
|
||||
sdkp->previous_state = retval;
|
||||
kfree(sshdr);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
|
|
@ -179,18 +179,24 @@ static int sr_media_change(struct cdrom_device_info *cdi, int slot)
|
|||
{
|
||||
struct scsi_cd *cd = cdi->handle;
|
||||
int retval;
|
||||
struct scsi_sense_hdr *sshdr;
|
||||
|
||||
if (CDSL_CURRENT != slot) {
|
||||
/* no changer support */
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
retval = scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES);
|
||||
if (retval) {
|
||||
/* Unable to test, unit probably not ready. This usually
|
||||
* means there is no disc in the drive. Mark as changed,
|
||||
* and we will figure it out later once the drive is
|
||||
* available again. */
|
||||
sshdr = kzalloc(sizeof(*sshdr), GFP_KERNEL);
|
||||
retval = scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES,
|
||||
sshdr);
|
||||
if (retval || (scsi_sense_valid(sshdr) &&
|
||||
/* 0x3a is medium not present */
|
||||
sshdr->asc == 0x3a)) {
|
||||
/* Media not present or unable to test, unit probably not
|
||||
* ready. This usually means there is no disc in the drive.
|
||||
* Mark as changed, and we will figure it out later once
|
||||
* the drive is available again.
|
||||
*/
|
||||
cd->device->changed = 1;
|
||||
/* This will force a flush, if called from check_disk_change */
|
||||
retval = 1;
|
||||
|
@ -213,6 +219,7 @@ static int sr_media_change(struct cdrom_device_info *cdi, int slot)
|
|||
sdev_evt_send_simple(cd->device, SDEV_EVT_MEDIA_CHANGE,
|
||||
GFP_KERNEL);
|
||||
cd->previous_state = retval;
|
||||
kfree(sshdr);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
|
|
@ -295,7 +295,7 @@ extern int scsi_mode_select(struct scsi_device *sdev, int pf, int sp,
|
|||
struct scsi_mode_data *data,
|
||||
struct scsi_sense_hdr *);
|
||||
extern int scsi_test_unit_ready(struct scsi_device *sdev, int timeout,
|
||||
int retries);
|
||||
int retries, struct scsi_sense_hdr *sshdr);
|
||||
extern int scsi_device_set_state(struct scsi_device *sdev,
|
||||
enum scsi_device_state state);
|
||||
extern struct scsi_event *sdev_evt_alloc(enum scsi_device_event evt_type,
|
||||
|
|
Loading…
Reference in New Issue