X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fscsi%2Flibata-scsi.c;h=246639fe651e4aa4af23b9ee546e9fe4c213dac4;hb=720b94a4e7548e78be55ab8fd3be4686c57dc808;hp=7b5a9789877dcd242316bf1733976382159c78b7;hpb=86090fcac5e27b630656fe3d963a6b80e26dac44;p=linux-2.6.git diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c index 7b5a97898..246639fe6 100644 --- a/drivers/scsi/libata-scsi.c +++ b/drivers/scsi/libata-scsi.c @@ -27,7 +27,7 @@ #include #include #include "scsi.h" -#include "hosts.h" +#include #include #include "libata.h" @@ -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; @@ -167,8 +167,27 @@ 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) { + sdev->host->max_sectors = 2048; + blk_queue_max_sectors(sdev->request_queue, 2048); + } + } + return 0; /* scsi layer doesn't check return value, sigh */ } @@ -321,6 +340,7 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) * @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 +363,20 @@ 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; if (cmd->sc_data_direction == SCSI_DATA_READ || - cmd->sc_data_direction == SCSI_DATA_WRITE) + 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; + } + qc->flags |= ATA_QCFLAG_SG; /* data is present; dma-map it */ + } if (xlat_func(qc, scsicmd)) goto err_out; @@ -478,7 +499,9 @@ 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[] = { + struct ata_device *dev = args->dev; + + u8 hdr[] = { TYPE_DISK, 0, 0x5, /* claim SPC-3 version compatibility */ @@ -486,14 +509,20 @@ unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf, 96 - 4 }; + /* set scsi removeable (RMB) bit per ata bit */ + if (ata_id_removeable(dev)) + 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); + 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); + if (rbuf[32] == 0 || rbuf[32] == ' ') + memcpy(&rbuf[32], "n/a ", 4); } if (buflen > 63) { @@ -667,9 +696,17 @@ static void ata_msense_push(u8 **ptr_io, const u8 *last, static unsigned int ata_msense_caching(struct ata_device *dev, 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(dev)) + page[2] |= (1 << 2); /* write cache enable */ + if (!ata_id_rahead_enabled(dev)) + page[12] |= (1 << 5); /* disable read ahead */ ata_msense_push(ptr_io, last, page, sizeof(page)); return sizeof(page); @@ -695,6 +732,31 @@ 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. @@ -734,6 +796,10 @@ 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); break; @@ -744,6 +810,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_ctl_mode(&p, last); break; @@ -784,20 +851,23 @@ unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf, VPRINTK("ENTER\n"); - n_sectors--; /* one off */ + 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 +877,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; @@ -866,56 +937,20 @@ void ata_scsi_badcmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *), u8 } /** - * 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; - - VPRINTK("ENTER, drv_stat = 0x%x\n", ata_chk_status(ap)); - - 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; - - 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; + struct scsi_cmnd *cmd = qc->scsicmd; qc->tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; if (cmd->sc_data_direction == SCSI_DATA_WRITE) { @@ -925,52 +960,30 @@ 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; + /* no data - interrupt-driven */ + if (cmd->sc_data_direction == SCSI_DATA_NONE) qc->tf.protocol = ATA_PROT_ATAPI; - ata_dev_select(ap, dev->devno, 1, 0); + /* PIO data xfer - polling */ + else if ((qc->flags & ATA_QCFLAG_DMA) == 0) { + ata_qc_set_polling(qc); + 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); + /* DMA data xfer - interrupt-driven */ } else { - qc->flags |= ATA_QCFLAG_SG; /* data is present; dma-map it */ - qc->tf.feature = ATAPI_PKT_DMA; 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; - } - - status = ata_busy_wait(ap, ATA_BUSY, 1000); - if (status & ATA_BUSY) { - ata_thread_wake(ap, THR_PACKET); - return; +#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 } - if ((status & ATA_DRQ) == 0) - goto err_out; - /* 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; } /** @@ -1109,7 +1122,7 @@ int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) else ata_scsi_simulate(ap, dev, cmd, done); } else - atapi_scsi_queuecmd(ap, dev, cmd, done); + ata_scsi_translate(ap, dev, cmd, done, atapi_xlat); out_unlock: return 0; @@ -1142,7 +1155,11 @@ static void ata_scsi_simulate(struct ata_port *ap, struct ata_device *dev, args.done = done; switch(scsicmd[0]) { - case TEST_UNIT_READY: /* FIXME: correct? */ + /* no-op's, complete with success */ + 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);