X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fscsi%2Flibata-scsi.c;h=7f59ef63fc8caf368469f92edf454f1550bb7c69;hb=6a77f38946aaee1cd85eeec6cf4229b204c15071;hp=7b5a9789877dcd242316bf1733976382159c78b7;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c index 7b5a97898..7f59ef63f 100644 --- a/drivers/scsi/libata-scsi.c +++ b/drivers/scsi/libata-scsi.c @@ -27,15 +27,15 @@ #include #include #include "scsi.h" -#include "hosts.h" +#include #include +#include #include "libata.h" typedef unsigned int (*ata_xlat_func_t)(struct ata_queued_cmd *qc, u8 *scsicmd); -static void ata_scsi_simulate(struct ata_port *ap, struct ata_device *dev, - struct scsi_cmnd *cmd, - void (*done)(struct scsi_cmnd *)); +static struct ata_device * +ata_scsi_find_dev(struct ata_port *ap, struct scsi_device *scsidev); /** @@ -46,8 +46,8 @@ static void ata_scsi_simulate(struct ata_port *ap, struct ata_device *dev, * @geom: location to which geometry will be output * * Generic bios head/sector/cylinder calculator - * used by sd. Most BIOSes nowadays expect a XXX/255/16 (CHS) - * mapping. Some situations may arise where the disk is not + * used by sd. Most BIOSes nowadays expect a XXX/255/16 (CHS) + * mapping. Some situations may arise where the disk is not * bootable if this is not used. * * LOCKING: @@ -57,7 +57,7 @@ static void ata_scsi_simulate(struct ata_port *ap, struct ata_device *dev, * Zero. */ int ata_std_bios_param(struct scsi_device *sdev, struct block_device *bdev, - sector_t capacity, int geom[]) + sector_t capacity, int geom[]) { geom[0] = 255; geom[1] = 63; @@ -67,6 +67,43 @@ int ata_std_bios_param(struct scsi_device *sdev, struct block_device *bdev, return 0; } +int ata_scsi_ioctl(struct scsi_device *scsidev, int cmd, void __user *arg) +{ + struct ata_port *ap; + struct ata_device *dev; + int val = -EINVAL, rc = -EINVAL; + + ap = (struct ata_port *) &scsidev->host->hostdata[0]; + if (!ap) + goto out; + + dev = ata_scsi_find_dev(ap, scsidev); + if (!dev) { + rc = -ENODEV; + goto out; + } + + switch (cmd) { + case ATA_IOC_GET_IO32: + val = 0; + if (copy_to_user(arg, &val, 1)) + return -EFAULT; + return 0; + + case ATA_IOC_SET_IO32: + val = (unsigned long) arg; + if (val != 0) + return -EINVAL; + return 0; + + default: + rc = -ENOTTY; + break; + } + +out: + return rc; +} /** * ata_scsi_qc_new - acquire new ata_queued_cmd reference @@ -119,35 +156,161 @@ struct ata_queued_cmd *ata_scsi_qc_new(struct ata_port *ap, /** * ata_to_sense_error - convert ATA error to SCSI error * @qc: Command that we are erroring out + * @drv_stat: value contained in ATA status register * - * Converts an ATA error into a SCSI error. - * - * Right now, this routine is laughably primitive. We - * don't even examine what ATA told us, we just look at - * the command data direction, and return a fatal SCSI - * sense error based on that. + * Converts an ATA error into a SCSI error. While we are at it + * we decode and dump the ATA error for the user so that they + * have some idea what really happened at the non make-believe + * layer. * * LOCKING: * spin_lock_irqsave(host_set lock) */ -void ata_to_sense_error(struct ata_queued_cmd *qc) +void ata_to_sense_error(struct ata_queued_cmd *qc, u8 drv_stat) { struct scsi_cmnd *cmd = qc->scsicmd; + u8 err = 0; + unsigned char *sb = cmd->sense_buffer; + /* Based on the 3ware driver translation table */ + static unsigned char sense_table[][4] = { + /* BBD|ECC|ID|MAR */ + {0xd1, ABORTED_COMMAND, 0x00, 0x00}, // Device busy Aborted command + /* BBD|ECC|ID */ + {0xd0, ABORTED_COMMAND, 0x00, 0x00}, // Device busy Aborted command + /* ECC|MC|MARK */ + {0x61, HARDWARE_ERROR, 0x00, 0x00}, // Device fault Hardware error + /* ICRC|ABRT */ /* NB: ICRC & !ABRT is BBD */ + {0x84, ABORTED_COMMAND, 0x47, 0x00}, // Data CRC error SCSI parity error + /* MC|ID|ABRT|TRK0|MARK */ + {0x37, NOT_READY, 0x04, 0x00}, // Unit offline Not ready + /* MCR|MARK */ + {0x09, NOT_READY, 0x04, 0x00}, // Unrecovered disk error Not ready + /* Bad address mark */ + {0x01, MEDIUM_ERROR, 0x13, 0x00}, // Address mark not found Address mark not found for data field + /* TRK0 */ + {0x02, HARDWARE_ERROR, 0x00, 0x00}, // Track 0 not found Hardware error + /* Abort & !ICRC */ + {0x04, ABORTED_COMMAND, 0x00, 0x00}, // Aborted command Aborted command + /* Media change request */ + {0x08, NOT_READY, 0x04, 0x00}, // Media change request FIXME: faking offline + /* SRV */ + {0x10, ABORTED_COMMAND, 0x14, 0x00}, // ID not found Recorded entity not found + /* Media change */ + {0x08, NOT_READY, 0x04, 0x00}, // Media change FIXME: faking offline + /* ECC */ + {0x40, MEDIUM_ERROR, 0x11, 0x04}, // Uncorrectable ECC error Unrecovered read error + /* BBD - block marked bad */ + {0x80, MEDIUM_ERROR, 0x11, 0x04}, // Block marked bad Medium error, unrecovered read error + {0xFF, 0xFF, 0xFF, 0xFF}, // END mark + }; + static unsigned char stat_table[][4] = { + /* Must be first because BUSY means no other bits valid */ + {0x80, ABORTED_COMMAND, 0x47, 0x00}, // Busy, fake parity for now + {0x20, HARDWARE_ERROR, 0x00, 0x00}, // Device fault + {0x08, ABORTED_COMMAND, 0x47, 0x00}, // Timed out in xfer, fake parity for now + {0x04, RECOVERED_ERROR, 0x11, 0x00}, // Recovered ECC error Medium error, recovered + {0xFF, 0xFF, 0xFF, 0xFF}, // END mark + }; + int i = 0; cmd->result = SAM_STAT_CHECK_CONDITION; - cmd->sense_buffer[0] = 0x70; - cmd->sense_buffer[2] = MEDIUM_ERROR; - cmd->sense_buffer[7] = 14 - 8; /* addnl. sense len. FIXME: correct? */ + /* + * Is this an error we can process/parse + */ + + if(drv_stat & ATA_ERR) + /* Read the err bits */ + err = ata_chk_err(qc->ap); + + /* Display the ATA level error info */ + + printk(KERN_WARNING "ata%u: status=0x%02x { ", qc->ap->id, drv_stat); + if(drv_stat & 0x80) + { + printk("Busy "); + err = 0; /* Data is not valid in this case */ + } + else { + if(drv_stat & 0x40) printk("DriveReady "); + if(drv_stat & 0x20) printk("DeviceFault "); + if(drv_stat & 0x10) printk("SeekComplete "); + if(drv_stat & 0x08) printk("DataRequest "); + if(drv_stat & 0x04) printk("CorrectedError "); + if(drv_stat & 0x02) printk("Index "); + if(drv_stat & 0x01) printk("Error "); + } + printk("}\n"); + + if(err) + { + printk(KERN_WARNING "ata%u: error=0x%02x { ", qc->ap->id, err); + if(err & 0x04) printk("DriveStatusError "); + if(err & 0x80) + { + if(err & 0x04) + printk("BadCRC "); + else + printk("Sector "); + } + if(err & 0x40) printk("UncorrectableError "); + if(err & 0x10) printk("SectorIdNotFound "); + if(err & 0x02) printk("TrackZeroNotFound "); + if(err & 0x01) printk("AddrMarkNotFound "); + printk("}\n"); + + /* Should we dump sector info here too ?? */ + } + + /* Look for err */ + while(sense_table[i][0] != 0xFF) + { + /* Look for best matches first */ + if((sense_table[i][0] & err) == sense_table[i][0]) + { + sb[0] = 0x70; + sb[2] = sense_table[i][1]; + sb[7] = 0x0a; + sb[12] = sense_table[i][2]; + sb[13] = sense_table[i][3]; + return; + } + i++; + } + /* No immediate match */ + if(err) + printk(KERN_DEBUG "ata%u: no sense translation for 0x%02x\n", qc->ap->id, err); + + i = 0; + /* Fall back to interpreting status bits */ + while(stat_table[i][0] != 0xFF) + { + if(stat_table[i][0] & drv_stat) + { + sb[0] = 0x70; + sb[2] = stat_table[i][1]; + sb[7] = 0x0a; + sb[12] = stat_table[i][2]; + sb[13] = stat_table[i][3]; + return; + } + i++; + } + /* No error ?? */ + printk(KERN_ERR "ata%u: called with no error (%02X)!\n", qc->ap->id, drv_stat); /* additional-sense-code[-qualifier] */ + + sb[0] = 0x70; + sb[2] = MEDIUM_ERROR; + sb[7] = 0x0A; if (cmd->sc_data_direction == SCSI_DATA_READ) { - cmd->sense_buffer[12] = 0x11; /* "unrecovered read error" */ - cmd->sense_buffer[13] = 0x04; + sb[12] = 0x11; /* "unrecovered read error" */ + sb[13] = 0x04; } else { - cmd->sense_buffer[12] = 0x0C; /* "write error - */ - cmd->sense_buffer[13] = 0x02; /* auto-reallocation failed" */ + sb[12] = 0x0C; /* "write error - */ + sb[13] = 0x02; /* auto-reallocation failed" */ } } @@ -167,8 +330,28 @@ int ata_scsi_slave_config(struct scsi_device *sdev) { sdev->use_10_for_rw = 1; sdev->use_10_for_ms = 1; + blk_queue_max_phys_segments(sdev->request_queue, LIBATA_MAX_PRD); + if (sdev->id < ATA_MAX_DEVICES) { + struct ata_port *ap; + struct ata_device *dev; + + ap = (struct ata_port *) &sdev->host->hostdata[0]; + dev = &ap->device[sdev->id]; + + /* TODO: 1024 is an arbitrary number, not the + * hardware maximum. This should be increased to + * 65534 when Jens Axboe's patch for dynamically + * determining max_sectors is merged. + */ + if ((dev->flags & ATA_DFLAG_LBA48) && + ((dev->flags & ATA_DFLAG_LOCK_SECTORS) == 0)) { + sdev->host->max_sectors = 2048; + blk_queue_max_sectors(sdev->request_queue, 2048); + } + } + return 0; /* scsi layer doesn't check return value, sigh */ } @@ -194,10 +377,139 @@ int ata_scsi_error(struct Scsi_Host *host) ap = (struct ata_port *) &host->hostdata[0]; ap->ops->eng_timeout(ap); + /* TODO: this is per-command; when queueing is supported + * this code will either change or move to a more + * appropriate place + */ + host->host_failed--; + DPRINTK("EXIT\n"); return 0; } +/** + * ata_scsi_flush_xlat - Translate SCSI SYNCHRONIZE CACHE command + * @qc: Storage for translated ATA taskfile + * @scsicmd: SCSI command to translate (ignored) + * + * Sets up an ATA taskfile to issue FLUSH CACHE or + * FLUSH CACHE EXT. + * + * LOCKING: + * spin_lock_irqsave(host_set lock) + * + * RETURNS: + * Zero on success, non-zero on error. + */ + +static unsigned int ata_scsi_flush_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) +{ + struct ata_taskfile *tf = &qc->tf; + + tf->flags |= ATA_TFLAG_DEVICE; + tf->protocol = ATA_PROT_NODATA; + + if ((tf->flags & ATA_TFLAG_LBA48) && + (ata_id_has_flush_ext(qc->dev->id))) + tf->command = ATA_CMD_FLUSH_EXT; + else + tf->command = ATA_CMD_FLUSH; + + return 0; +} + +/** + * ata_scsi_verify_xlat - Translate SCSI VERIFY command into an ATA one + * @qc: Storage for translated ATA taskfile + * @scsicmd: SCSI command to translate + * + * Converts SCSI VERIFY command to an ATA READ VERIFY command. + * + * LOCKING: + * spin_lock_irqsave(host_set lock) + * + * RETURNS: + * Zero on success, non-zero on error. + */ + +static unsigned int ata_scsi_verify_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) +{ + struct ata_taskfile *tf = &qc->tf; + unsigned int lba48 = tf->flags & ATA_TFLAG_LBA48; + u64 dev_sectors = qc->dev->n_sectors; + u64 sect = 0; + u32 n_sect = 0; + + tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + tf->protocol = ATA_PROT_NODATA; + tf->device |= ATA_LBA; + + if (scsicmd[0] == VERIFY) { + sect |= ((u64)scsicmd[2]) << 24; + sect |= ((u64)scsicmd[3]) << 16; + sect |= ((u64)scsicmd[4]) << 8; + sect |= ((u64)scsicmd[5]); + + n_sect |= ((u32)scsicmd[7]) << 8; + n_sect |= ((u32)scsicmd[8]); + } + + else if (scsicmd[0] == VERIFY_16) { + sect |= ((u64)scsicmd[2]) << 56; + sect |= ((u64)scsicmd[3]) << 48; + sect |= ((u64)scsicmd[4]) << 40; + sect |= ((u64)scsicmd[5]) << 32; + sect |= ((u64)scsicmd[6]) << 24; + sect |= ((u64)scsicmd[7]) << 16; + sect |= ((u64)scsicmd[8]) << 8; + sect |= ((u64)scsicmd[9]); + + n_sect |= ((u32)scsicmd[10]) << 24; + n_sect |= ((u32)scsicmd[11]) << 16; + n_sect |= ((u32)scsicmd[12]) << 8; + n_sect |= ((u32)scsicmd[13]); + } + + else + return 1; + + if (!n_sect) + return 1; + if (sect >= dev_sectors) + return 1; + if ((sect + n_sect) > dev_sectors) + return 1; + if (lba48) { + if (n_sect > (64 * 1024)) + return 1; + } else { + if (n_sect > 256) + return 1; + } + + if (lba48) { + tf->command = ATA_CMD_VERIFY_EXT; + + tf->hob_nsect = (n_sect >> 8) & 0xff; + + tf->hob_lbah = (sect >> 40) & 0xff; + tf->hob_lbam = (sect >> 32) & 0xff; + tf->hob_lbal = (sect >> 24) & 0xff; + } else { + tf->command = ATA_CMD_VERIFY; + + tf->device |= (sect >> 24) & 0xf; + } + + tf->nsect = n_sect & 0xff; + + tf->lbah = (sect >> 16) & 0xff; + tf->lbam = (sect >> 8) & 0xff; + tf->lbal = sect & 0xff; + + return 0; +} + /** * ata_scsi_rw_xlat - Translate SCSI r/w command into an ATA one * @qc: Storage for translated ATA taskfile @@ -224,10 +536,6 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) unsigned int lba48 = tf->flags & ATA_TFLAG_LBA48; tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; - tf->hob_nsect = 0; - tf->hob_lbal = 0; - tf->hob_lbam = 0; - tf->hob_lbah = 0; tf->protocol = qc->dev->xfer_protocol; tf->device |= ATA_LBA; @@ -297,7 +605,7 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) return 1; /* stores LBA27:24 in lower 4 bits of device reg */ - tf->device |= scsicmd[2]; + tf->device |= scsicmd[6]; qc->nsect = scsicmd[13]; } @@ -315,12 +623,27 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) return 1; } +static int ata_scsi_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat) +{ + struct scsi_cmnd *cmd = qc->scsicmd; + + if (unlikely(drv_stat & (ATA_ERR | ATA_BUSY | ATA_DRQ))) + ata_to_sense_error(qc, drv_stat); + else + cmd->result = SAM_STAT_GOOD; + + qc->scsidone(cmd); + + return 0; +} + /** * ata_scsi_translate - Translate then issue SCSI command to ATA device * @ap: ATA port to which the command is addressed * @dev: ATA device to which the command is addressed * @cmd: SCSI command to execute * @done: SCSI command completion function + * @xlat_func: Actor which translates @cmd to an ATA taskfile * * Our ->queuecommand() function has decided that the SCSI * command issued can be directly translated into an ATA @@ -343,19 +666,29 @@ static void ata_scsi_translate(struct ata_port *ap, struct ata_device *dev, VPRINTK("ENTER\n"); - if (unlikely(cmd->request_bufflen < 1)) { - printk(KERN_WARNING "ata%u(%u): empty request buffer\n", - ap->id, dev->devno); - goto err_out; - } - qc = ata_scsi_qc_new(ap, dev, cmd, done); if (!qc) return; + /* data is present; dma-map it */ if (cmd->sc_data_direction == SCSI_DATA_READ || - cmd->sc_data_direction == SCSI_DATA_WRITE) - qc->flags |= ATA_QCFLAG_SG; /* data is present; dma-map it */ + cmd->sc_data_direction == SCSI_DATA_WRITE) { + if (unlikely(cmd->request_bufflen < 1)) { + printk(KERN_WARNING "ata%u(%u): WARNING: zero len r/w req\n", + ap->id, dev->devno); + goto err_out; + } + + if (cmd->use_sg) + ata_sg_init(qc, cmd->request_buffer, cmd->use_sg); + else + ata_sg_init_one(qc, cmd->request_buffer, + cmd->request_bufflen); + + qc->dma_dir = cmd->sc_data_direction; + } + + qc->complete_fn = ata_scsi_qc_complete; if (xlat_func(qc, scsicmd)) goto err_out; @@ -368,6 +701,7 @@ static void ata_scsi_translate(struct ata_port *ap, struct ata_device *dev, return; err_out: + ata_qc_free(qc); ata_bad_cdb(cmd, done); DPRINTK("EXIT - badcmd\n"); } @@ -402,7 +736,6 @@ static unsigned int ata_scsi_rbuf_get(struct scsi_cmnd *cmd, u8 **buf_out) buflen = cmd->request_bufflen; } - memset(buf, 0, buflen); *buf_out = buf; return buflen; } @@ -410,6 +743,7 @@ static unsigned int ata_scsi_rbuf_get(struct scsi_cmnd *cmd, u8 **buf_out) /** * ata_scsi_rbuf_put - Unmap response buffer. * @cmd: SCSI command containing buffer to be unmapped. + * @buf: buffer to unmap * * Unmaps response buffer contained within @cmd. * @@ -417,19 +751,19 @@ static unsigned int ata_scsi_rbuf_get(struct scsi_cmnd *cmd, u8 **buf_out) * spin_lock_irqsave(host_set lock) */ -static inline void ata_scsi_rbuf_put(struct scsi_cmnd *cmd) +static inline void ata_scsi_rbuf_put(struct scsi_cmnd *cmd, u8 *buf) { if (cmd->use_sg) { struct scatterlist *sg; sg = (struct scatterlist *) cmd->request_buffer; - kunmap_atomic(sg->page, KM_USER0); + kunmap_atomic(buf - sg->offset, KM_USER0); } } /** * ata_scsi_rbuf_fill - wrapper for SCSI command simulators - * @args: Port / device / SCSI command of interest. + * @args: device IDENTIFY data / SCSI command of interest. * @actor: Callback hook for desired SCSI command simulator * * Takes care of the hard work of simulating a SCSI command... @@ -451,8 +785,9 @@ void ata_scsi_rbuf_fill(struct ata_scsi_args *args, struct scsi_cmnd *cmd = args->cmd; buflen = ata_scsi_rbuf_get(cmd, &rbuf); + memset(rbuf, 0, buflen); rc = actor(args, rbuf, buflen); - ata_scsi_rbuf_put(cmd); + ata_scsi_rbuf_put(cmd, rbuf); if (rc) ata_bad_cdb(cmd, args->done); @@ -464,7 +799,7 @@ void ata_scsi_rbuf_fill(struct ata_scsi_args *args, /** * ata_scsiop_inq_std - Simulate INQUIRY command - * @args: Port / device / SCSI command of interest. + * @args: device IDENTIFY data / SCSI command of interest. * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. * @buflen: Response buffer length. * @@ -478,22 +813,28 @@ void ata_scsi_rbuf_fill(struct ata_scsi_args *args, unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf, unsigned int buflen) { - const u8 hdr[] = { + u8 hdr[] = { TYPE_DISK, 0, 0x5, /* claim SPC-3 version compatibility */ 2, - 96 - 4 + 95 - 4 }; + /* set scsi removeable (RMB) bit per ata bit */ + if (ata_id_removeable(args->id)) + hdr[1] |= (1 << 7); + VPRINTK("ENTER\n"); memcpy(rbuf, hdr, sizeof(hdr)); - if (buflen > 36) { - memcpy(&rbuf[8], args->dev->vendor, 8); - memcpy(&rbuf[16], args->dev->product, 16); - memcpy(&rbuf[32], DRV_VERSION, 4); + if (buflen > 35) { + memcpy(&rbuf[8], "ATA ", 8); + ata_dev_id_string(args->id, &rbuf[16], ATA_ID_PROD_OFS, 16); + ata_dev_id_string(args->id, &rbuf[32], ATA_ID_FW_REV_OFS, 4); + if (rbuf[32] == 0 || rbuf[32] == ' ') + memcpy(&rbuf[32], "n/a ", 4); } if (buflen > 63) { @@ -515,7 +856,7 @@ unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf, /** * ata_scsiop_inq_00 - Simulate INQUIRY EVPD page 0, list of pages - * @args: Port / device / SCSI command of interest. + * @args: device IDENTIFY data / SCSI command of interest. * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. * @buflen: Response buffer length. * @@ -543,7 +884,7 @@ unsigned int ata_scsiop_inq_00(struct ata_scsi_args *args, u8 *rbuf, /** * ata_scsiop_inq_80 - Simulate INQUIRY EVPD page 80, device serial number - * @args: Port / device / SCSI command of interest. + * @args: device IDENTIFY data / SCSI command of interest. * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. * @buflen: Response buffer length. * @@ -564,8 +905,8 @@ unsigned int ata_scsiop_inq_80(struct ata_scsi_args *args, u8 *rbuf, }; memcpy(rbuf, hdr, sizeof(hdr)); - if (buflen > (ATA_SERNO_LEN + 4)) - ata_dev_id_string(args->dev, (unsigned char *) &rbuf[4], + if (buflen > (ATA_SERNO_LEN + 4 - 1)) + ata_dev_id_string(args->id, (unsigned char *) &rbuf[4], ATA_ID_SERNO_OFS, ATA_SERNO_LEN); return 0; @@ -575,7 +916,7 @@ static const char *inq_83_str = "Linux ATA-SCSI simulator"; /** * ata_scsiop_inq_83 - Simulate INQUIRY EVPD page 83, device identity - * @args: Port / device / SCSI command of interest. + * @args: device IDENTIFY data / SCSI command of interest. * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. * @buflen: Response buffer length. * @@ -593,7 +934,7 @@ unsigned int ata_scsiop_inq_83(struct ata_scsi_args *args, u8 *rbuf, rbuf[3] = 4 + strlen(inq_83_str); /* page len */ /* our one and only identification descriptor (vendor-specific) */ - if (buflen > (strlen(inq_83_str) + 4 + 4)) { + if (buflen > (strlen(inq_83_str) + 4 + 4 - 1)) { rbuf[4 + 0] = 2; /* code set: ASCII */ rbuf[4 + 3] = strlen(inq_83_str); memcpy(rbuf + 4 + 4, inq_83_str, strlen(inq_83_str)); @@ -604,7 +945,7 @@ unsigned int ata_scsiop_inq_83(struct ata_scsi_args *args, u8 *rbuf, /** * ata_scsiop_noop - - * @args: Port / device / SCSI command of interest. + * @args: device IDENTIFY data / SCSI command of interest. * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. * @buflen: Response buffer length. * @@ -652,7 +993,7 @@ static void ata_msense_push(u8 **ptr_io, const u8 *last, /** * ata_msense_caching - Simulate MODE SENSE caching info page - * @dev: Device associated with this MODE SENSE command + * @id: device IDENTIFY data * @ptr_io: (input/output) Location to store more output data * @last: End of output data buffer * @@ -664,12 +1005,20 @@ static void ata_msense_push(u8 **ptr_io, const u8 *last, * None. */ -static unsigned int ata_msense_caching(struct ata_device *dev, u8 **ptr_io, +static unsigned int ata_msense_caching(u16 *id, u8 **ptr_io, const u8 *last) { - u8 page[7] = { 0xf, 0, 0x10, 0, 0x8, 0xa, 0 }; - if (dev->flags & ATA_DFLAG_WCACHE) - page[6] = 0x4; + u8 page[] = { + 0x8, /* page code */ + 0x12, /* page length */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10 zeroes */ + 0, 0, 0, 0, 0, 0, 0, 0 /* 8 zeroes */ + }; + + if (ata_id_wcache_enabled(id)) + page[2] |= (1 << 2); /* write cache enable */ + if (!ata_id_rahead_enabled(id)) + page[12] |= (1 << 5); /* disable read ahead */ ata_msense_push(ptr_io, last, page, sizeof(page)); return sizeof(page); @@ -695,9 +1044,34 @@ static unsigned int ata_msense_ctl_mode(u8 **ptr_io, const u8 *last) return sizeof(page); } +/** + * ata_msense_rw_recovery - Simulate MODE SENSE r/w error recovery page + * @dev: Device associated with this MODE SENSE command + * @ptr_io: (input/output) Location to store more output data + * @last: End of output data buffer + * + * Generate a generic MODE SENSE r/w error recovery page. + * + * LOCKING: + * None. + */ + +static unsigned int ata_msense_rw_recovery(u8 **ptr_io, const u8 *last) +{ + const u8 page[] = { + 0x1, /* page code */ + 0xa, /* page length */ + (1 << 7) | (1 << 6), /* note auto r/w reallocation */ + 0, 0, 0, 0, 0, 0, 0, 0, 0 /* 9 zeroes */ + }; + + ata_msense_push(ptr_io, last, page, sizeof(page)); + return sizeof(page); +} + /** * ata_scsiop_mode_sense - Simulate MODE SENSE 6, 10 commands - * @args: Port / device / SCSI command of interest. + * @args: device IDENTIFY data / SCSI command of interest. * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. * @buflen: Response buffer length. * @@ -711,7 +1085,6 @@ unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf, unsigned int buflen) { u8 *scsicmd = args->cmd->cmnd, *p, *last; - struct ata_device *dev = args->dev; unsigned int page_control, six_byte, output_len; VPRINTK("ENTER\n"); @@ -734,8 +1107,12 @@ unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf, last = rbuf + buflen - 1; switch(scsicmd[2] & 0x3f) { + case 0x01: /* r/w error recovery */ + output_len += ata_msense_rw_recovery(&p, last); + break; + case 0x08: /* caching */ - output_len += ata_msense_caching(dev, &p, last); + output_len += ata_msense_caching(args->id, &p, last); break; case 0x0a: { /* control mode */ @@ -744,7 +1121,8 @@ unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf, } case 0x3f: /* all pages */ - output_len += ata_msense_caching(dev, &p, last); + output_len += ata_msense_rw_recovery(&p, last); + output_len += ata_msense_caching(args->id, &p, last); output_len += ata_msense_ctl_mode(&p, last); break; @@ -766,7 +1144,7 @@ unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf, /** * ata_scsiop_read_cap - Simulate READ CAPACITY[ 16] commands - * @args: Port / device / SCSI command of interest. + * @args: device IDENTIFY data / SCSI command of interest. * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. * @buflen: Response buffer length. * @@ -779,25 +1157,32 @@ unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf, unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf, unsigned int buflen) { - u64 n_sectors = args->dev->n_sectors; + u64 n_sectors; u32 tmp; VPRINTK("ENTER\n"); - n_sectors--; /* one off */ + if (ata_id_has_lba48(args->id)) + n_sectors = ata_id_u64(args->id, 100); + else + n_sectors = ata_id_u32(args->id, 60); + n_sectors--; /* ATA TotalUserSectors - 1 */ tmp = n_sectors; /* note: truncates, if lba48 */ if (args->cmd->cmnd[0] == READ_CAPACITY) { + /* sector count, 32-bit */ rbuf[0] = tmp >> (8 * 3); rbuf[1] = tmp >> (8 * 2); rbuf[2] = tmp >> (8 * 1); rbuf[3] = tmp; + /* sector size */ tmp = ATA_SECT_SIZE; rbuf[6] = tmp >> 8; rbuf[7] = tmp; } else { + /* sector count, 64-bit */ rbuf[2] = n_sectors >> (8 * 7); rbuf[3] = n_sectors >> (8 * 6); rbuf[4] = n_sectors >> (8 * 5); @@ -807,6 +1192,7 @@ unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf, rbuf[8] = tmp >> (8 * 1); rbuf[9] = tmp; + /* sector size */ tmp = ATA_SECT_SIZE; rbuf[12] = tmp >> 8; rbuf[13] = tmp; @@ -817,7 +1203,7 @@ unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf, /** * ata_scsiop_report_luns - Simulate REPORT LUNS command - * @args: Port / device / SCSI command of interest. + * @args: device IDENTIFY data / SCSI command of interest. * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. * @buflen: Response buffer length. * @@ -865,57 +1251,64 @@ void ata_scsi_badcmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *), u8 done(cmd); } +static int atapi_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat) +{ + struct scsi_cmnd *cmd = qc->scsicmd; + + if (unlikely(drv_stat & (ATA_ERR | ATA_BUSY | ATA_DRQ))) { + DPRINTK("request check condition\n"); + + cmd->result = SAM_STAT_CHECK_CONDITION; + + qc->scsidone(cmd); + + return 1; + } else { + u8 *scsicmd = cmd->cmnd; + + if (scsicmd[0] == INQUIRY) { + u8 *buf = NULL; + unsigned int buflen; + + buflen = ata_scsi_rbuf_get(cmd, &buf); + buf[2] = 0x5; + buf[3] = (buf[3] & 0xf0) | 2; + ata_scsi_rbuf_put(cmd, buf); + } + cmd->result = SAM_STAT_GOOD; + } + + qc->scsidone(cmd); + + return 0; +} /** - * atapi_scsi_queuecmd - Send CDB to ATAPI device - * @ap: Port to which ATAPI device is attached. - * @dev: Target device for CDB. - * @cmd: SCSI command being sent to device. - * @done: SCSI command completion function. - * - * Sends CDB to ATAPI device. If the Linux SCSI layer sends a - * non-data command, then this function handles the command - * directly, via polling. Otherwise, the bmdma engine is started. + * atapi_xlat - Initialize PACKET taskfile + * @qc: command structure to be initialized + * @scsicmd: SCSI CDB associated with this PACKET command * * LOCKING: * spin_lock_irqsave(host_set lock) + * + * RETURNS: + * Zero on success, non-zero on failure. */ -static void atapi_scsi_queuecmd(struct ata_port *ap, struct ata_device *dev, - struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) +static unsigned int atapi_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) { - struct ata_queued_cmd *qc; - u8 *scsicmd = cmd->cmnd, status; - unsigned int doing_dma = 0; + struct scsi_cmnd *cmd = qc->scsicmd; + struct ata_device *dev = qc->dev; + int using_pio = (dev->flags & ATA_DFLAG_PIO); + int nodata = (cmd->sc_data_direction == SCSI_DATA_NONE); - VPRINTK("ENTER, drv_stat = 0x%x\n", ata_chk_status(ap)); + if (!using_pio) + /* Check whether ATAPI DMA is safe */ + if (ata_check_atapi_dma(qc)) + using_pio = 1; - if (cmd->sc_data_direction == SCSI_DATA_UNKNOWN) { - DPRINTK("unknown data, scsicmd 0x%x\n", scsicmd[0]); - ata_bad_cdb(cmd, done); - return; - } - - switch(scsicmd[0]) { - case READ_6: - case WRITE_6: - case MODE_SELECT: - case MODE_SENSE: - DPRINTK("read6/write6/modesel/modesense trap\n"); - ata_bad_scsiop(cmd, done); - return; + memcpy(&qc->cdb, scsicmd, qc->ap->cdb_len); - default: - /* do nothing */ - break; - } - - qc = ata_scsi_qc_new(ap, dev, cmd, done); - if (!qc) { - printk(KERN_ERR "ata%u: command queue empty\n", ap->id); - return; - } - - qc->flags |= ATA_QCFLAG_ATAPI; + qc->complete_fn = atapi_qc_complete; qc->tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; if (cmd->sc_data_direction == SCSI_DATA_WRITE) { @@ -925,58 +1318,37 @@ static void atapi_scsi_queuecmd(struct ata_port *ap, struct ata_device *dev, qc->tf.command = ATA_CMD_PACKET; - /* set up SG table */ - if (cmd->sc_data_direction == SCSI_DATA_NONE) { - ap->active_tag = qc->tag; - qc->flags |= ATA_QCFLAG_ACTIVE | ATA_QCFLAG_POLL; - qc->tf.protocol = ATA_PROT_ATAPI; - - ata_dev_select(ap, dev->devno, 1, 0); + /* no data, or PIO data xfer */ + if (using_pio || nodata) { + if (nodata) + qc->tf.protocol = ATA_PROT_ATAPI_NODATA; + else + qc->tf.protocol = ATA_PROT_ATAPI; + qc->tf.lbam = (8 * 1024) & 0xff; + qc->tf.lbah = (8 * 1024) >> 8; + } - DPRINTK("direction: none\n"); - qc->tf.ctl |= ATA_NIEN; /* disable interrupts */ - ata_tf_to_host_nolock(ap, &qc->tf); - } else { - qc->flags |= ATA_QCFLAG_SG; /* data is present; dma-map it */ - qc->tf.feature = ATAPI_PKT_DMA; + /* DMA data xfer */ + else { qc->tf.protocol = ATA_PROT_ATAPI_DMA; + qc->tf.feature |= ATAPI_PKT_DMA; - doing_dma = 1; - - /* select device, send command to hardware */ - if (ata_qc_issue(qc)) - goto err_out; +#ifdef ATAPI_ENABLE_DMADIR + /* some SATA bridges need us to indicate data xfer direction */ + if (cmd->sc_data_direction != SCSI_DATA_WRITE) + qc->tf.feature |= ATAPI_DMADIR; +#endif } - status = ata_busy_wait(ap, ATA_BUSY, 1000); - if (status & ATA_BUSY) { - ata_thread_wake(ap, THR_PACKET); - return; - } - if ((status & ATA_DRQ) == 0) - goto err_out; + qc->nbytes = cmd->bufflen; - /* FIXME: mmio-ize */ - DPRINTK("writing cdb\n"); - outsl(ap->ioaddr.data_addr, scsicmd, ap->host->max_cmd_len / 4); - - if (!doing_dma) - ata_thread_wake(ap, THR_PACKET); - - VPRINTK("EXIT\n"); - return; - -err_out: - if (!doing_dma) - ata_irq_on(ap); /* re-enable interrupts */ - ata_bad_cdb(cmd, done); - DPRINTK("EXIT - badcmd\n"); + return 0; } /** * ata_scsi_find_dev - lookup ata_device from scsi_cmnd * @ap: ATA port to which the device is attached - * @cmd: SCSI command to be sent to the device + * @scsidev: SCSI device from which we derive the ATA device * * Given various information provided in struct scsi_cmnd, * map that onto an ATA bus, and using that mapping @@ -990,19 +1362,19 @@ err_out: * Associated ATA device, or %NULL if not found. */ -static inline struct ata_device * -ata_scsi_find_dev(struct ata_port *ap, struct scsi_cmnd *cmd) +static struct ata_device * +ata_scsi_find_dev(struct ata_port *ap, struct scsi_device *scsidev) { struct ata_device *dev; /* skip commands not addressed to targets we simulate */ - if (likely(cmd->device->id < ATA_MAX_DEVICES)) - dev = &ap->device[cmd->device->id]; + if (likely(scsidev->id < ATA_MAX_DEVICES)) + dev = &ap->device[scsidev->id]; else return NULL; - if (unlikely((cmd->device->channel != 0) || - (cmd->device->lun != 0))) + if (unlikely((scsidev->channel != 0) || + (scsidev->lun != 0))) return NULL; if (unlikely(!ata_dev_present(dev))) @@ -1018,6 +1390,7 @@ ata_scsi_find_dev(struct ata_port *ap, struct scsi_cmnd *cmd) /** * ata_get_xlat_func - check if SCSI to ATA translation is possible + * @dev: ATA device * @cmd: SCSI command opcode to consider * * Look up the SCSI command given, and determine whether the @@ -1027,7 +1400,7 @@ ata_scsi_find_dev(struct ata_port *ap, struct scsi_cmnd *cmd) * Pointer to translation function if possible, %NULL if not. */ -static inline ata_xlat_func_t ata_get_xlat_func(u8 cmd) +static inline ata_xlat_func_t ata_get_xlat_func(struct ata_device *dev, u8 cmd) { switch (cmd) { case READ_6: @@ -1038,6 +1411,15 @@ static inline ata_xlat_func_t ata_get_xlat_func(u8 cmd) case WRITE_10: case WRITE_16: return ata_scsi_rw_xlat; + + case SYNCHRONIZE_CACHE: + if (ata_try_flush_cache(dev)) + return ata_scsi_flush_xlat; + break; + + case VERIFY: + case VERIFY_16: + return ata_scsi_verify_xlat; } return NULL; @@ -1055,11 +1437,12 @@ static inline void ata_scsi_dump_cdb(struct ata_port *ap, struct scsi_cmnd *cmd) { #ifdef ATA_DEBUG + struct scsi_device *scsidev = cmd->device; u8 *scsicmd = cmd->cmnd; DPRINTK("CDB (%u:%d,%d,%d) %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", ap->id, - cmd->device->channel, cmd->device->id, cmd->device->lun, + scsidev->channel, scsidev->id, scsidev->lun, scsicmd[0], scsicmd[1], scsicmd[2], scsicmd[3], scsicmd[4], scsicmd[5], scsicmd[6], scsicmd[7], scsicmd[8]); @@ -1089,12 +1472,13 @@ int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) { struct ata_port *ap; struct ata_device *dev; + struct scsi_device *scsidev = cmd->device; - ap = (struct ata_port *) &cmd->device->host->hostdata[0]; + ap = (struct ata_port *) &scsidev->host->hostdata[0]; ata_scsi_dump_cdb(ap, cmd); - dev = ata_scsi_find_dev(ap, cmd); + dev = ata_scsi_find_dev(ap, scsidev); if (unlikely(!dev)) { cmd->result = (DID_BAD_TARGET << 16); done(cmd); @@ -1102,14 +1486,15 @@ int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) } if (dev->class == ATA_DEV_ATA) { - ata_xlat_func_t xlat_func = ata_get_xlat_func(cmd->cmnd[0]); + ata_xlat_func_t xlat_func = ata_get_xlat_func(dev, + cmd->cmnd[0]); if (xlat_func) ata_scsi_translate(ap, dev, cmd, done, xlat_func); else - ata_scsi_simulate(ap, dev, cmd, done); + ata_scsi_simulate(dev->id, cmd, done); } else - atapi_scsi_queuecmd(ap, dev, cmd, done); + ata_scsi_translate(ap, dev, cmd, done, atapi_xlat); out_unlock: return 0; @@ -1117,8 +1502,7 @@ out_unlock: /** * ata_scsi_simulate - simulate SCSI command on ATA device - * @ap: Port to which ATA device is attached. - * @dev: Target device for CDB. + * @id: current IDENTIFY data for target device. * @cmd: SCSI command being sent to device. * @done: SCSI command completion function. * @@ -1129,20 +1513,24 @@ out_unlock: * spin_lock_irqsave(host_set lock) */ -static void ata_scsi_simulate(struct ata_port *ap, struct ata_device *dev, - struct scsi_cmnd *cmd, - void (*done)(struct scsi_cmnd *)) +void ata_scsi_simulate(u16 *id, + struct scsi_cmnd *cmd, + void (*done)(struct scsi_cmnd *)) { struct ata_scsi_args args; u8 *scsicmd = cmd->cmnd; - args.ap = ap; - args.dev = dev; + args.id = id; args.cmd = cmd; args.done = done; switch(scsicmd[0]) { - case TEST_UNIT_READY: /* FIXME: correct? */ + /* no-op's, complete with success */ + case SYNCHRONIZE_CACHE: + case REZERO_UNIT: + case SEEK_6: + case SEEK_10: + case TEST_UNIT_READY: case FORMAT_UNIT: /* FIXME: correct? */ case SEND_DIAGNOSTIC: /* FIXME: correct? */ ata_scsi_rbuf_fill(&args, ata_scsiop_noop);