[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:
James Bottomley
2007-12-02 19:10:40 +02:00
committed by James Bottomley
parent 4a03d90e35
commit 001aac257c
5 changed files with 63 additions and 19 deletions

View File

@@ -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);