From 972dcafb6d743a6c7611a2e4681ed814e30d6230 Mon Sep 17 00:00:00 2001 From: Douglas Gilbert Date: Thu, 11 Aug 2005 03:35:53 -0400 Subject: [libata scsi] add START STOP UNIT translation --- drivers/scsi/libata-scsi.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) (limited to 'drivers/scsi/libata-scsi.c') diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c index 6a75ec2..f58311b 100644 --- a/drivers/scsi/libata-scsi.c +++ b/drivers/scsi/libata-scsi.c @@ -392,6 +392,60 @@ int ata_scsi_error(struct Scsi_Host *host) } /** + * ata_scsi_start_stop_xlat - Translate SCSI START STOP UNIT command + * @qc: Storage for translated ATA taskfile + * @scsicmd: SCSI command to translate + * + * Sets up an ATA taskfile to issue STANDBY (to stop) or READ VERIFY + * (to start). Perhaps these commands should be preceded by + * CHECK POWER MODE to see what power mode the device is already in. + * [See SAT revision 5 at www.t10.org] + * + * LOCKING: + * spin_lock_irqsave(host_set lock) + * + * RETURNS: + * Zero on success, non-zero on error. + */ + +static unsigned int ata_scsi_start_stop_xlat(struct ata_queued_cmd *qc, + u8 *scsicmd) +{ + struct ata_taskfile *tf = &qc->tf; + + tf->flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR; + tf->protocol = ATA_PROT_NODATA; + if (scsicmd[1] & 0x1) { + ; /* ignore IMMED bit, violates sat-r05 */ + } + if (scsicmd[4] & 0x2) + return 1; /* LOEJ bit set not supported */ + if (((scsicmd[4] >> 4) & 0xf) != 0) + return 1; /* power conditions not supported */ + if (scsicmd[4] & 0x1) { + tf->nsect = 1; /* 1 sector, lba=0 */ + tf->lbah = 0x0; + tf->lbam = 0x0; + tf->lbal = 0x0; + tf->device |= ATA_LBA; + tf->command = ATA_CMD_VERIFY; /* READ VERIFY */ + } else { + tf->nsect = 0; /* time period value (0 implies now) */ + tf->command = ATA_CMD_STANDBY; + /* Consider: ATA STANDBY IMMEDIATE command */ + } + /* + * Standby and Idle condition timers could be implemented but that + * would require libata to implement the Power condition mode page + * and allow the user to change it. Changing mode pages requires + * MODE SELECT to be implemented. + */ + + return 0; +} + + +/** * ata_scsi_flush_xlat - Translate SCSI SYNCHRONIZE CACHE command * @qc: Storage for translated ATA taskfile * @scsicmd: SCSI command to translate (ignored) @@ -1435,6 +1489,8 @@ static inline ata_xlat_func_t ata_get_xlat_func(struct ata_device *dev, u8 cmd) case VERIFY: case VERIFY_16: return ata_scsi_verify_xlat; + case START_STOP: + return ata_scsi_start_stop_xlat; } return NULL; -- cgit v1.1 From 135932651fd1eeb95eb6c5d4f6652aae73fe2c24 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Sat, 27 Aug 2005 04:20:12 -0400 Subject: [libata scsi] fix read/write translation edge cases Fix bugs for unlikely edge cases noticed by Douglas Gilbert: - When READ(6)/WRITE(6) sector count == 0, treat it as 256 sectors - For other READ(x)/WRITE(x), when sector count == 0, error. We don't support successfully completing zero-length transfers at this time. --- drivers/scsi/libata-scsi.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers/scsi/libata-scsi.c') diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c index f58311b..4074e78 100644 --- a/drivers/scsi/libata-scsi.c +++ b/drivers/scsi/libata-scsi.c @@ -630,11 +630,19 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) tf->lbah = scsicmd[3]; VPRINTK("ten-byte command\n"); + if (qc->nsect == 0) /* we don't support length==0 cmds */ + return 1; return 0; } if (scsicmd[0] == READ_6 || scsicmd[0] == WRITE_6) { qc->nsect = tf->nsect = scsicmd[4]; + if (!qc->nsect) { + qc->nsect = 256; + if (lba48) + tf->hob_nsect = 1; + } + tf->lbal = scsicmd[3]; tf->lbam = scsicmd[2]; tf->lbah = scsicmd[1] & 0x1f; /* mask out reserved bits */ @@ -674,6 +682,8 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) tf->lbah = scsicmd[7]; VPRINTK("sixteen-byte command\n"); + if (qc->nsect == 0) /* we don't support length==0 cmds */ + return 1; return 0; } -- cgit v1.1