X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fscsi%2Flibata-scsi.c;h=7f59ef63fc8caf368469f92edf454f1550bb7c69;hb=6a77f38946aaee1cd85eeec6cf4229b204c15071;hp=47c0af26f1a7bb54e775ddbe04cd0cd363c48a06;hpb=87fc8d1bb10cd459024a742c6a10961fefcef18f;p=linux-2.6.git diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c index 47c0af26f..7f59ef63f 100644 --- a/drivers/scsi/libata-scsi.c +++ b/drivers/scsi/libata-scsi.c @@ -34,9 +34,6 @@ #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); @@ -100,7 +97,7 @@ int ata_scsi_ioctl(struct scsi_device *scsidev, int cmd, void __user *arg) return 0; default: - rc = -EOPNOTSUPP; + rc = -ENOTTY; break; } @@ -159,6 +156,7 @@ 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. While we are at it * we decode and dump the ATA error for the user so that they @@ -204,7 +202,7 @@ void ata_to_sense_error(struct ata_queued_cmd *qc, u8 drv_stat) {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 + {0xFF, 0xFF, 0xFF, 0xFF}, // END mark }; static unsigned char stat_table[][4] = { /* Must be first because BUSY means no other bits valid */ @@ -212,22 +210,22 @@ void ata_to_sense_error(struct ata_queued_cmd *qc, u8 drv_stat) {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 + {0xFF, 0xFF, 0xFF, 0xFF}, // END mark }; int i = 0; cmd->result = SAM_STAT_CHECK_CONDITION; - + /* * 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) { @@ -244,7 +242,7 @@ void ata_to_sense_error(struct ata_queued_cmd *qc, u8 drv_stat) if(drv_stat & 0x01) printk("Error "); } printk("}\n"); - + if(err) { printk(KERN_WARNING "ata%u: error=0x%02x { ", qc->ap->id, err); @@ -261,11 +259,11 @@ void ata_to_sense_error(struct ata_queued_cmd *qc, u8 drv_stat) 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) { @@ -284,7 +282,8 @@ void ata_to_sense_error(struct ata_queued_cmd *qc, u8 drv_stat) /* 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) { @@ -302,7 +301,7 @@ void ata_to_sense_error(struct ata_queued_cmd *qc, u8 drv_stat) /* 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; @@ -411,7 +410,7 @@ static unsigned int ata_scsi_flush_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) tf->protocol = ATA_PROT_NODATA; if ((tf->flags & ATA_TFLAG_LBA48) && - (ata_id_has_flush_ext(qc->dev))) + (ata_id_has_flush_ext(qc->dev->id))) tf->command = ATA_CMD_FLUSH_EXT; else tf->command = ATA_CMD_FLUSH; @@ -489,19 +488,24 @@ static unsigned int ata_scsi_verify_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) } 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 + } else { + tf->command = ATA_CMD_VERIFY; + tf->device |= (sect >> 24) & 0xf; + } tf->nsect = n_sect & 0xff; - tf->hob_lbah = (sect >> 16) & 0xff; - tf->hob_lbam = (sect >> 8) & 0xff; - tf->hob_lbal = sect & 0xff; + tf->lbah = (sect >> 16) & 0xff; + tf->lbam = (sect >> 8) & 0xff; + tf->lbal = sect & 0xff; return 0; } @@ -601,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]; } @@ -681,7 +685,7 @@ static void ata_scsi_translate(struct ata_port *ap, struct ata_device *dev, ata_sg_init_one(qc, cmd->request_buffer, cmd->request_bufflen); - qc->pci_dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction); + qc->dma_dir = cmd->sc_data_direction; } qc->complete_fn = ata_scsi_qc_complete; @@ -697,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"); } @@ -731,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; } @@ -739,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. * @@ -746,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... @@ -780,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); @@ -793,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. * @@ -807,8 +813,6 @@ 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) { - struct ata_device *dev = args->dev; - u8 hdr[] = { TYPE_DISK, 0, @@ -818,7 +822,7 @@ unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf, }; /* set scsi removeable (RMB) bit per ata bit */ - if (ata_id_removeable(dev)) + if (ata_id_removeable(args->id)) hdr[1] |= (1 << 7); VPRINTK("ENTER\n"); @@ -827,8 +831,8 @@ unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf, if (buflen > 35) { memcpy(&rbuf[8], "ATA ", 8); - ata_dev_id_string(dev, &rbuf[16], ATA_ID_PROD_OFS, 16); - ata_dev_id_string(dev, &rbuf[32], ATA_ID_FW_REV_OFS, 4); + 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); } @@ -852,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. * @@ -880,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. * @@ -901,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; @@ -912,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. * @@ -930,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)); @@ -941,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. * @@ -989,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 * @@ -1001,7 +1005,7 @@ 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[] = { @@ -1011,9 +1015,9 @@ static unsigned int ata_msense_caching(struct ata_device *dev, u8 **ptr_io, 0, 0, 0, 0, 0, 0, 0, 0 /* 8 zeroes */ }; - if (ata_id_wcache_enabled(dev)) + if (ata_id_wcache_enabled(id)) page[2] |= (1 << 2); /* write cache enable */ - if (!ata_id_rahead_enabled(dev)) + if (!ata_id_rahead_enabled(id)) page[12] |= (1 << 5); /* disable read ahead */ ata_msense_push(ptr_io, last, page, sizeof(page)); @@ -1067,7 +1071,7 @@ static unsigned int ata_msense_rw_recovery(u8 **ptr_io, const u8 *last) /** * 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. * @@ -1081,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"); @@ -1109,7 +1112,7 @@ unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf, 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 */ @@ -1119,7 +1122,7 @@ unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf, case 0x3f: /* all pages */ output_len += ata_msense_rw_recovery(&p, last); - output_len += ata_msense_caching(dev, &p, last); + output_len += ata_msense_caching(args->id, &p, last); output_len += ata_msense_ctl_mode(&p, last); break; @@ -1141,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. * @@ -1154,11 +1157,15 @@ 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"); + 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 */ @@ -1196,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. * @@ -1248,9 +1255,15 @@ 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))) + if (unlikely(drv_stat & (ATA_ERR | ATA_BUSY | ATA_DRQ))) { + DPRINTK("request check condition\n"); + cmd->result = SAM_STAT_CHECK_CONDITION; - else { + + qc->scsidone(cmd); + + return 1; + } else { u8 *scsicmd = cmd->cmnd; if (scsicmd[0] == INQUIRY) { @@ -1260,7 +1273,7 @@ static int atapi_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat) buflen = ata_scsi_rbuf_get(cmd, &buf); buf[2] = 0x5; buf[3] = (buf[3] & 0xf0) | 2; - ata_scsi_rbuf_put(cmd); + ata_scsi_rbuf_put(cmd, buf); } cmd->result = SAM_STAT_GOOD; } @@ -1288,6 +1301,11 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) int using_pio = (dev->flags & ATA_DFLAG_PIO); int nodata = (cmd->sc_data_direction == SCSI_DATA_NONE); + if (!using_pio) + /* Check whether ATAPI DMA is safe */ + if (ata_check_atapi_dma(qc)) + using_pio = 1; + memcpy(&qc->cdb, scsicmd, qc->ap->cdb_len); qc->complete_fn = atapi_qc_complete; @@ -1322,13 +1340,15 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) #endif } + qc->nbytes = cmd->bufflen; + 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 @@ -1472,7 +1492,7 @@ int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) 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 ata_scsi_translate(ap, dev, cmd, done, atapi_xlat); @@ -1482,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. * @@ -1494,15 +1513,14 @@ 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;