libata test-unit-ready for ATAPI devices
PATCH 1/1 libata test-unit-ready for ATAPI devices
The following patch clears the "I was just reset" condition from an ATAPI device, and waits for it to come online, before continuing with the probe.
Not checking this into any upstream-bound branch, as I'm not yet convinced of its value.
drivers/scsi/libata-core.c | 135 +++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 135 insertions(+)
drivers/scsi/libata-core.c +135 -0
@@ -68,6 +68,7 @@ static void ata_dev_reread_id(struct atastatic void ata_dev_init_params (struct ata_port *ap,struct ata_device *dev);static void ata_set_mode (struct ata_port *ap);static void ata_dev_set_xfermode (struct ata_port *ap,struct ata_device *dev); +static void atapi_dev_tur (struct ata_port *ap,struct ata_device *dev);static unsigned int ata_get_mode_mask (const struct ata_port *ap,int shift);static int fgb (u32 bitmap); static int ata_choose_xfer_mode(const struct ata_port *ap,
@@ -1361,6 +1362,10 @@ static int ata_bus_probe(struct ata_portif (ap->flags &ATA_FLAG_PORT_DISABLED ) goto err_out_disable; +for (i =0 ; i <ATA_MAX_DEVICES ; i++) +if (ap->device[i].class ==ATA_DEV_ATAPI ) +atapi_dev_tur (ap, &ap->device[i]); +return 0 ; err_out_disable:
@@ -2376,6 +2381,136 @@ static void ata_dev_init_params(struct aDPRINTK ("EXIT\n" ); } +static int atapi_tur_request_sense (struct ata_port *ap,struct ata_device *dev) +{ +DECLARE_COMPLETION (wait); +struct ata_queued_cmd *qc; +unsigned long flags; +u8 sense_buffer[SCSI_SENSE_BUFFERSIZE ]; +int rc, do_poll =0 ; + +DPRINTK ("ATAPI TUR request sense\n" ); + +memset (&sense_buffer,0xff ,sizeof (sense_buffer)); + + qc =ata_qc_new_init (ap, dev); +BUG_ON (qc ==NULL ); + +ata_sg_init_one (qc, sense_buffer,sizeof (sense_buffer)); + qc->dma_dir =DMA_FROM_DEVICE ; + +memset (&qc->cdb,0 , ap->cdb_len); + qc->cdb[0 ] =REQUEST_SENSE ; + qc->cdb[4 ] =SCSI_SENSE_BUFFERSIZE ; + + qc->tf.flags |=ATA_TFLAG_ISADDR |ATA_TFLAG_DEVICE ; + qc->tf.command =ATA_CMD_PACKET ; + + qc->tf.protocol =ATA_PROT_ATAPI ; + qc->tf.lbam = (8 *1024 ) &0xff ; + qc->tf.lbah = (8 *1024 ) >>8 ; + + qc->nbytes =SCSI_SENSE_BUFFERSIZE ; + + qc->waiting = &wait; + qc->complete_fn = ata_qc_complete_noop; + +spin_lock_irqsave (&ap->host_set->lock, flags); + rc =ata_qc_issue (qc); +spin_unlock_irqrestore (&ap->host_set->lock, flags); + +if (!rc) +wait_for_completion (&wait); + +switch (sense_buffer[12 ]) {/* byte 12 == ASC */ +case 0x29 : +case 0x4 : + do_poll =1 ; +break ; + } + +DPRINTK ("EXIT\n" ); + +return do_poll; +} + +static int ata_qc_complete_sense (struct ata_queued_cmd *qc,unsigned int err_mask) +{ +unsigned int *sense = qc->private_data; + + qc->ap->ops->tf_read (qc->ap, &qc->tf); +if (qc->tf.command &ATA_ERR ) + *sense = qc->tf.feature >>4 ; +else + *sense =0 ; +return 0 ; +} + +static void atapi_dev_tur (struct ata_port *ap,struct ata_device *dev) +{ +DECLARE_COMPLETION (wait); +struct ata_queued_cmd *qc; +int rc, do_poll; +unsigned long flags; +unsigned int sense; +unsigned int retries =15 ; + +/* set up TUR taskfile */ +DPRINTK ("TUR\n" ); + +tur_retry: + qc =ata_qc_new_init (ap, dev); +BUG_ON (qc ==NULL ); + +memset (&qc->cdb,0 , ap->cdb_len); + qc->cdb[0 ] =TEST_UNIT_READY ; + + qc->dma_dir =DMA_NONE ; + qc->tf.command =ATA_CMD_PACKET ; + qc->tf.flags |=ATA_TFLAG_ISADDR |ATA_TFLAG_DEVICE ; + qc->tf.protocol =ATA_PROT_ATAPI ; + qc->tf.lbam = (8 *1024 ) &0xff ; + qc->tf.lbah = (8 *1024 ) >>8 ; + + sense =0xffffffffU ; + qc->private_data = &sense; + + qc->waiting = &wait; + qc->complete_fn = ata_qc_complete_sense; + +spin_lock_irqsave (&ap->host_set->lock, flags); + rc =ata_qc_issue (qc); +spin_unlock_irqrestore (&ap->host_set->lock, flags); + +if (rc) { +tur_error: +printk (KERN_WARNING "ata%u: TUR failure, port disabled\n" , + ap->id); +ata_port_disable (ap); +return ; + } + +wait_for_completion (&wait); + +if (sense ==0 ) +return ; +if (sense >0xf ) + goto tur_error; + + do_poll =atapi_tur_request_sense (ap, dev); +if (do_poll ==0 ) +return ; +if (do_poll <0 ) + goto tur_error; + +msleep (500 ); + + retries--; + goto tur_retry; + +DPRINTK ("EXIT\n" ); +} +/** * ata_sg_clean - Unmap DMA memory associated with command * @qc: Command containing DMA memory to be released
Quoted 8 lines · Jeff Garzik
The following patch clears the "I was just reset" condition from an ATAPI device, and waits for it to come online, before continuing with the probe.
Not checking this into any upstream-bound branch, as I'm not yet convinced of its value.
How about the following one? It doesn't make libata wait for the device to become ready before trying to configure ATA stuff. It just makes sr wait for the device to become ready before performing SCSI configuration. Maybe both are needed?
drivers/scsi/sr.c +46 -21
@@ -44,6 +44,7 @@#include <linux/interrupt.h> #include <linux/init.h> #include <linux/blkdev.h> +#include <linux/delay.h> #include <asm/uaccess.h> #include <scsi/scsi.h>
@@ -721,14 +722,53 @@ Enomem: goto out; } -static void get_capabilities (struct scsi_cd *cd) +static int initial_test_unit_ready (struct scsi_cd *cd) { -unsigned char *buffer; -struct scsi_mode_data data;unsigned char cmd[MAX_COMMAND_SIZE ];struct scsi_sense_hdr sshdr;unsigned int the_result; -int retries, rc, n; +int retries =5 , becoming_ready =0 , first_becoming_ready =1 ; + +memset ((void *)cmd,0 ,MAX_COMMAND_SIZE ); + cmd[0 ] =TEST_UNIT_READY ; + +while (--retries) { + the_result =scsi_execute_req (cd->device, cmd,DMA_NONE ,NULL , +0 , &sshdr,SR_TIMEOUT , +MAX_RETRIES ); + +if (scsi_status_is_good (the_result)) +return 0 ; + +if (!scsi_sense_valid (&sshdr)) +continue ; + + becoming_ready = sshdr.sense_key ==NOT_READY && + sshdr.asc ==0x04 && sshdr.ascq ==0x01 ; + +if (becoming_ready) { +if (first_becoming_ready) { +printk ("%s: device is becoming ready, please " +"be patient\n" , cd->cdi.name); + retries =30 ;/* 15secs */ + first_becoming_ready =0 ; + } +msleep (500 ); + }else if (sshdr.sense_key !=UNIT_ATTENTION ) +break ; + } + +if (becoming_ready) +printk (KERN_WARNING "%s: device failed to become ready\n" , + cd->cdi.name); +return -1 ; +} + +static void get_capabilities (struct scsi_cd *cd) +{ +unsigned char *buffer; +struct scsi_mode_data data; +int rc, n;static char *loadmech[] = {
@@ -750,23 +790,8 @@ static void get_capabilities(struct scsireturn ; } -/* issue TEST_UNIT_READY until the initial startup UNIT_ATTENTION -* conditions are gone, or a timeout happens -*/ - retries =0 ; -do { -memset ((void *)cmd,0 ,MAX_COMMAND_SIZE ); - cmd[0 ] =TEST_UNIT_READY ; - - the_result =scsi_execute_req (cd->device, cmd,DMA_NONE ,NULL , -0 , &sshdr,SR_TIMEOUT , -MAX_RETRIES ); - - retries++; - }while (retries <5 && - (!scsi_status_is_good (the_result) || - (scsi_sense_valid (&sshdr) && - sshdr.sense_key ==UNIT_ATTENTION ))); +/* test for readiness */ +initial_test_unit_ready (cd);/* ask for mode page 0x2a */ rc = scsi_mode_sense(cd->device, 0, 0x2a, buffer, 128,
include/linux/libata.h +0 -0
Quoted 11 lines · Tejun Heo
Quoted 7 lines · Jeff Garzik
The following patch clears the "I was just reset" condition from an ATAPI device, and waits for it to come online, before continuing with the probe.
Not checking this into any upstream-bound branch, as I'm not yet convinced of its value.
Quoted 4 lines
How about the following one? It doesn't make libata wait for the device to become ready before trying to configure ATA stuff. It just makes sr wait for the device to become ready before performing SCSI configuration. Maybe both are needed?
[thinking out loud] My rationale for doing TUR in libata was to clear the UNIT ATTENTION that libata caused through software/hardware reset. Once the UNIT ATTENTION was cleared, my rationale for waiting for the NOT READY(BECOMING READY) condition was simply symmetry with other libata probe tasks, which similarly wait for device readiness.
However, given that sr is already coded to clear "the initial startup UNIT_ATTENTION", I tend to think your patch is more appropriate, and my patch should not be applied at all.
Jeff
Quoted 22 lines · Jeff Garzik
Quoted 6 lines · Tejun Heo
Quoted 4 lines · Jeff Garzik
The following patch clears the "I was just reset" condition from an ATAPI device, and waits for it to come online, before continuing with the probe.
Quoted 8 lines
Quoted 2 lines
Not checking this into any upstream-bound branch, as I'm not yet convinced of its value.
How about the following one? It doesn't make libata wait for the device to become ready before trying to configure ATA stuff. It just makes sr wait for the device to become ready before performing SCSI configuration. Maybe both are needed?
[thinking out loud] My rationale for doing TUR in libata was to clear the UNIT ATTENTION that libata caused through software/hardware reset. Once the UNIT ATTENTION was cleared, my rationale for waiting for the NOT READY(BECOMING READY) condition was simply symmetry with other libata probe tasks, which similarly wait for device readiness.
Quoted 3 lines
However, given that sr is already coded to clear "the initial startup
UNIT_ATTENTION", I tend to think your patch is more appropriate, and my patch should not be applied at all.
I don't know when this code would get executed - if it is only at boot I don't mind, but other than that, in the osst driver, I need to know if the device gets reset (I test for the UNIT ATTENTION), because it changes the state of the drive, that is where the read/write head is on the tape.
So please make sure not to destroy information needed by higher layers.
Thanks, Willem Riede.
Quoted 21 lines · Willem Riede
Quoted 18 lines · Jeff Garzik
Quoted 15 lines · Tejun Heo
Quoted 6 lines · Jeff Garzik
The following patch clears the "I was just reset" condition from an ATAPI device, and waits for it to come online, before continuing with the probe.
Not checking this into any upstream-bound branch, as I'm not yet convinced of its value.
How about the following one? It doesn't make libata wait for the device to become ready before trying to configure ATA stuff. It just makes sr wait for the device to become ready before performing SCSI configuration. Maybe both are needed?
Quoted 7 lines
Quoted 3 lines
[thinking out loud] My rationale for doing TUR in libata was to clear the UNIT ATTENTION that libata caused through software/hardware reset. Once the UNIT ATTENTION was cleared, my rationale for waiting for the NOT READY(BECOMING READY) condition was simply symmetry with other libata probe tasks, which similarly wait for device readiness.
However, given that sr is already coded to clear "the initial startup
UNIT_ATTENTION", I tend to think your patch is more appropriate, and my patch should not be applied at all.I don't know when this code would get executed - if it is only at boot I don't mind, but other than that, in the osst driver, I need to know if the
This is only at boot.
Jeff