diff options
Diffstat (limited to 'drivers/ata/libata-scsi.c')
| -rw-r--r-- | drivers/ata/libata-scsi.c | 683 |
1 files changed, 435 insertions, 248 deletions
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 097080c8b82d..5dc9586d9724 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -216,17 +216,21 @@ void ata_scsi_set_sense(struct ata_device *dev, struct scsi_cmnd *cmd, scsi_build_sense(cmd, d_sense, sk, asc, ascq); } -void ata_scsi_set_sense_information(struct ata_device *dev, - struct scsi_cmnd *cmd, - const struct ata_taskfile *tf) +static void ata_scsi_set_sense_information(struct ata_queued_cmd *qc) { u64 information; - information = ata_tf_read_block(tf, dev); + if (!(qc->flags & ATA_QCFLAG_RTF_FILLED)) { + ata_dev_dbg(qc->dev, + "missing result TF: can't set INFORMATION sense field\n"); + return; + } + + information = ata_tf_read_block(&qc->result_tf, qc->dev); if (information == U64_MAX) return; - scsi_set_sense_information(cmd->sense_buffer, + scsi_set_sense_information(qc->scsicmd->sense_buffer, SCSI_SENSE_BUFFERSIZE, information); } @@ -347,7 +351,7 @@ EXPORT_SYMBOL_GPL(ata_common_sdev_groups); /** * ata_std_bios_param - generic bios head/sector/cylinder calculator used by sd. * @sdev: SCSI device for which BIOS geometry is to be determined - * @bdev: block device associated with @sdev + * @unused: gendisk associated with @sdev * @capacity: capacity of SCSI device * @geom: location to which geometry will be output * @@ -362,7 +366,7 @@ EXPORT_SYMBOL_GPL(ata_common_sdev_groups); * RETURNS: * Zero. */ -int ata_std_bios_param(struct scsi_device *sdev, struct block_device *bdev, +int ata_std_bios_param(struct scsi_device *sdev, struct gendisk *unused, sector_t capacity, int geom[]) { geom[0] = 255; @@ -969,8 +973,7 @@ static void ata_gen_passthru_sense(struct ata_queued_cmd *qc) * ata_gen_ata_sense - generate a SCSI fixed sense block * @qc: Command that we are erroring out * - * Generate sense block for a failed ATA command @qc. Descriptor - * format is used to accommodate LBA48 block address. + * Generate sense block for a failed ATA command @qc. * * LOCKING: * None. @@ -980,8 +983,6 @@ static void ata_gen_ata_sense(struct ata_queued_cmd *qc) struct ata_device *dev = qc->dev; struct scsi_cmnd *cmd = qc->scsicmd; struct ata_taskfile *tf = &qc->result_tf; - unsigned char *sb = cmd->sense_buffer; - u64 block; u8 sense_key, asc, ascq; if (ata_dev_disabled(dev)) { @@ -1012,11 +1013,6 @@ static void ata_gen_ata_sense(struct ata_queued_cmd *qc) ata_to_sense_error(tf->status, tf->error, &sense_key, &asc, &ascq); ata_scsi_set_sense(dev, cmd, sense_key, asc, ascq); - - block = ata_tf_read_block(&qc->result_tf, dev); - if (block != U64_MAX) - scsi_set_sense_information(sb, SCSI_SENSE_BUFFERSIZE, - block); return; } @@ -1139,7 +1135,7 @@ int ata_scsi_dev_config(struct scsi_device *sdev, struct queue_limits *lim, } /** - * ata_scsi_slave_alloc - Early setup of SCSI device + * ata_scsi_sdev_init - Early setup of SCSI device * @sdev: SCSI device to examine * * This is called from scsi_alloc_sdev() when the scsi device @@ -1149,7 +1145,7 @@ int ata_scsi_dev_config(struct scsi_device *sdev, struct queue_limits *lim, * Defined by SCSI layer. We don't really care. */ -int ata_scsi_slave_alloc(struct scsi_device *sdev) +int ata_scsi_sdev_init(struct scsi_device *sdev) { struct ata_port *ap = ata_shost_to_port(sdev->host); struct device_link *link; @@ -1172,10 +1168,10 @@ int ata_scsi_slave_alloc(struct scsi_device *sdev) return 0; } -EXPORT_SYMBOL_GPL(ata_scsi_slave_alloc); +EXPORT_SYMBOL_GPL(ata_scsi_sdev_init); /** - * ata_scsi_device_configure - Set SCSI device attributes + * ata_scsi_sdev_configure - Set SCSI device attributes * @sdev: SCSI device to examine * @lim: queue limits * @@ -1187,8 +1183,7 @@ EXPORT_SYMBOL_GPL(ata_scsi_slave_alloc); * Defined by SCSI layer. We don't really care. */ -int ata_scsi_device_configure(struct scsi_device *sdev, - struct queue_limits *lim) +int ata_scsi_sdev_configure(struct scsi_device *sdev, struct queue_limits *lim) { struct ata_port *ap = ata_shost_to_port(sdev->host); struct ata_device *dev = __ata_scsi_find_dev(ap, sdev); @@ -1198,10 +1193,10 @@ int ata_scsi_device_configure(struct scsi_device *sdev, return 0; } -EXPORT_SYMBOL_GPL(ata_scsi_device_configure); +EXPORT_SYMBOL_GPL(ata_scsi_sdev_configure); /** - * ata_scsi_slave_destroy - SCSI device is about to be destroyed + * ata_scsi_sdev_destroy - SCSI device is about to be destroyed * @sdev: SCSI device to be destroyed * * @sdev is about to be destroyed for hot/warm unplugging. If @@ -1214,7 +1209,7 @@ EXPORT_SYMBOL_GPL(ata_scsi_device_configure); * LOCKING: * Defined by SCSI layer. We don't really care. */ -void ata_scsi_slave_destroy(struct scsi_device *sdev) +void ata_scsi_sdev_destroy(struct scsi_device *sdev) { struct ata_port *ap = ata_shost_to_port(sdev->host); unsigned long flags; @@ -1234,7 +1229,7 @@ void ata_scsi_slave_destroy(struct scsi_device *sdev) kfree(sdev->dma_drain_buf); } -EXPORT_SYMBOL_GPL(ata_scsi_slave_destroy); +EXPORT_SYMBOL_GPL(ata_scsi_sdev_destroy); /** * ata_scsi_start_stop_xlat - Translate SCSI START STOP UNIT command @@ -1340,17 +1335,8 @@ static unsigned int ata_scsi_flush_xlat(struct ata_queued_cmd *qc) */ static void scsi_6_lba_len(const u8 *cdb, u64 *plba, u32 *plen) { - u64 lba = 0; - u32 len; - - lba |= ((u64)(cdb[1] & 0x1f)) << 16; - lba |= ((u64)cdb[2]) << 8; - lba |= ((u64)cdb[3]); - - len = cdb[4]; - - *plba = lba; - *plen = len; + *plba = get_unaligned_be24(&cdb[1]) & 0x1fffff; + *plen = cdb[4]; } /** @@ -1671,8 +1657,77 @@ static void ata_qc_done(struct ata_queued_cmd *qc) done(cmd); } +void ata_scsi_deferred_qc_work(struct work_struct *work) +{ + struct ata_port *ap = + container_of(work, struct ata_port, deferred_qc_work); + struct ata_queued_cmd *qc; + unsigned long flags; + + spin_lock_irqsave(ap->lock, flags); + + /* + * If we still have a deferred qc and we are not in EH, issue it. In + * such case, we should not need any more deferring the qc, so warn if + * qc_defer() says otherwise. + */ + qc = ap->deferred_qc; + if (qc && !ata_port_eh_scheduled(ap)) { + WARN_ON_ONCE(ap->ops->qc_defer(qc)); + ap->deferred_qc = NULL; + ata_qc_issue(qc); + } + + spin_unlock_irqrestore(ap->lock, flags); +} + +void ata_scsi_requeue_deferred_qc(struct ata_port *ap) +{ + struct ata_queued_cmd *qc = ap->deferred_qc; + struct scsi_cmnd *scmd; + + lockdep_assert_held(ap->lock); + + /* + * If we have a deferred qc when a reset occurs or NCQ commands fail, + * do not try to be smart about what to do with this deferred command + * and simply retry it by completing it with DID_SOFT_ERROR. + */ + if (!qc) + return; + + scmd = qc->scsicmd; + ap->deferred_qc = NULL; + ata_qc_free(qc); + scmd->result = (DID_SOFT_ERROR << 16); + scsi_done(scmd); +} + +static void ata_scsi_schedule_deferred_qc(struct ata_port *ap) +{ + struct ata_queued_cmd *qc = ap->deferred_qc; + + lockdep_assert_held(ap->lock); + + /* + * If we have a deferred qc, then qc_defer() is defined and we can use + * this callback to determine if this qc is good to go, unless EH has + * been scheduled. + */ + if (!qc) + return; + + if (ata_port_eh_scheduled(ap)) { + ata_scsi_requeue_deferred_qc(ap); + return; + } + if (!ap->ops->qc_defer(qc)) + queue_work(system_highpri_wq, &ap->deferred_qc_work); +} + static void ata_scsi_qc_complete(struct ata_queued_cmd *qc) { + struct ata_port *ap = qc->ap; struct scsi_cmnd *cmd = qc->scsicmd; u8 *cdb = cmd->cmnd; bool have_sense = qc->flags & ATA_QCFLAG_SENSE_VALID; @@ -1695,11 +1750,15 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc) ata_scsi_set_passthru_sense_fields(qc); if (is_ck_cond_request) set_status_byte(qc->scsicmd, SAM_STAT_CHECK_CONDITION); - } else if (is_error && !have_sense) { - ata_gen_ata_sense(qc); + } else if (is_error) { + if (!have_sense) + ata_gen_ata_sense(qc); + ata_scsi_set_sense_information(qc); } ata_qc_done(qc); + + ata_scsi_schedule_deferred_qc(ap); } static int ata_scsi_qc_issue(struct ata_port *ap, struct ata_queued_cmd *qc) @@ -1709,6 +1768,16 @@ static int ata_scsi_qc_issue(struct ata_port *ap, struct ata_queued_cmd *qc) if (!ap->ops->qc_defer) goto issue; + /* + * If we already have a deferred qc, then rely on the SCSI layer to + * requeue and defer all incoming commands until the deferred qc is + * processed, once all on-going commands complete. + */ + if (ap->deferred_qc) { + ata_qc_free(qc); + return SCSI_MLQUEUE_DEVICE_BUSY; + } + /* Check if the command needs to be deferred. */ ret = ap->ops->qc_defer(qc); switch (ret) { @@ -1727,6 +1796,18 @@ static int ata_scsi_qc_issue(struct ata_port *ap, struct ata_queued_cmd *qc) } if (ret) { + /* + * We must defer this qc: if this is not an NCQ command, keep + * this qc as a deferred one and report to the SCSI layer that + * we issued it so that it is not requeued. The deferred qc will + * be issued with the port deferred_qc_work once all on-going + * commands complete. + */ + if (!ata_is_ncq(qc->tf.protocol)) { + ap->deferred_qc = qc; + return 0; + } + /* Force a requeue of the command to defer its execution. */ ata_qc_free(qc); return ret; @@ -1806,15 +1887,10 @@ done: return 0; } -struct ata_scsi_args { - struct ata_device *dev; - u16 *id; - struct scsi_cmnd *cmd; -}; - /** * ata_scsi_rbuf_fill - wrapper for SCSI command simulators - * @args: device IDENTIFY data / SCSI command of interest. + * @dev: Target device. + * @cmd: SCSI command of interest. * @actor: Callback hook for desired SCSI command simulator * * Takes care of the hard work of simulating a SCSI command... @@ -1827,30 +1903,32 @@ struct ata_scsi_args { * LOCKING: * spin_lock_irqsave(host lock) */ -static void ata_scsi_rbuf_fill(struct ata_scsi_args *args, - unsigned int (*actor)(struct ata_scsi_args *args, u8 *rbuf)) +static void ata_scsi_rbuf_fill(struct ata_device *dev, struct scsi_cmnd *cmd, + unsigned int (*actor)(struct ata_device *dev, + struct scsi_cmnd *cmd, u8 *rbuf)) { - unsigned int rc; - struct scsi_cmnd *cmd = args->cmd; unsigned long flags; + unsigned int len; spin_lock_irqsave(&ata_scsi_rbuf_lock, flags); memset(ata_scsi_rbuf, 0, ATA_SCSI_RBUF_SIZE); - rc = actor(args, ata_scsi_rbuf); - if (rc == 0) + len = actor(dev, cmd, ata_scsi_rbuf); + if (len) { sg_copy_from_buffer(scsi_sglist(cmd), scsi_sg_count(cmd), ata_scsi_rbuf, ATA_SCSI_RBUF_SIZE); + cmd->result = SAM_STAT_GOOD; + if (scsi_bufflen(cmd) > len) + scsi_set_resid(cmd, scsi_bufflen(cmd) - len); + } spin_unlock_irqrestore(&ata_scsi_rbuf_lock, flags); - - if (rc == 0) - cmd->result = SAM_STAT_GOOD; } /** - * ata_scsiop_inq_std - Simulate INQUIRY command - * @args: device IDENTIFY data / SCSI command of interest. + * ata_scsiop_inq_std - Simulate standard INQUIRY command + * @dev: Target device. + * @cmd: SCSI command of interest. * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. * * Returns standard device identification data associated @@ -1859,7 +1937,8 @@ static void ata_scsi_rbuf_fill(struct ata_scsi_args *args, * LOCKING: * spin_lock_irqsave(host lock) */ -static unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf) +static unsigned int ata_scsiop_inq_std(struct ata_device *dev, + struct scsi_cmnd *cmd, u8 *rbuf) { static const u8 versions[] = { 0x00, @@ -1900,40 +1979,45 @@ static unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf) * Set the SCSI Removable Media Bit (RMB) if the ATA removable media * device bit (obsolete since ATA-8 ACS) is set. */ - if (ata_id_removable(args->id)) + if (ata_id_removable(dev->id)) hdr[1] |= (1 << 7); - if (args->dev->class == ATA_DEV_ZAC) { + if (dev->class == ATA_DEV_ZAC) { hdr[0] = TYPE_ZBC; hdr[2] = 0x7; /* claim SPC-5 version compatibility */ } - if (args->dev->flags & ATA_DFLAG_CDL) + if (dev->flags & ATA_DFLAG_CDL) hdr[2] = 0xd; /* claim SPC-6 version compatibility */ memcpy(rbuf, hdr, sizeof(hdr)); memcpy(&rbuf[8], "ATA ", 8); - ata_id_string(args->id, &rbuf[16], ATA_ID_PROD, 16); + ata_id_string(dev->id, &rbuf[16], ATA_ID_PROD, 16); /* From SAT, use last 2 words from fw rev unless they are spaces */ - ata_id_string(args->id, &rbuf[32], ATA_ID_FW_REV + 2, 4); + ata_id_string(dev->id, &rbuf[32], ATA_ID_FW_REV + 2, 4); if (strncmp(&rbuf[32], " ", 4) == 0) - ata_id_string(args->id, &rbuf[32], ATA_ID_FW_REV, 4); + ata_id_string(dev->id, &rbuf[32], ATA_ID_FW_REV, 4); if (rbuf[32] == 0 || rbuf[32] == ' ') memcpy(&rbuf[32], "n/a ", 4); - if (ata_id_zoned_cap(args->id) || args->dev->class == ATA_DEV_ZAC) + if (ata_id_zoned_cap(dev->id) || dev->class == ATA_DEV_ZAC) memcpy(rbuf + 58, versions_zbc, sizeof(versions_zbc)); else memcpy(rbuf + 58, versions, sizeof(versions)); - return 0; + /* + * Include all 8 possible version descriptors, even if not all of + * them are popoulated. + */ + return 96; } /** * ata_scsiop_inq_00 - Simulate INQUIRY VPD page 0, list of pages - * @args: device IDENTIFY data / SCSI command of interest. + * @dev: Target device. + * @cmd: SCSI command of interest. * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. * * Returns list of inquiry VPD pages available. @@ -1941,7 +2025,8 @@ static unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf) * LOCKING: * spin_lock_irqsave(host lock) */ -static unsigned int ata_scsiop_inq_00(struct ata_scsi_args *args, u8 *rbuf) +static unsigned int ata_scsiop_inq_00(struct ata_device *dev, + struct scsi_cmnd *cmd, u8 *rbuf) { int i, num_pages = 0; static const u8 pages[] = { @@ -1957,19 +2042,20 @@ static unsigned int ata_scsiop_inq_00(struct ata_scsi_args *args, u8 *rbuf) }; for (i = 0; i < sizeof(pages); i++) { - if (pages[i] == 0xb6 && - !(args->dev->flags & ATA_DFLAG_ZAC)) + if (pages[i] == 0xb6 && !ata_dev_is_zac(dev)) continue; rbuf[num_pages + 4] = pages[i]; num_pages++; } rbuf[3] = num_pages; /* number of supported VPD pages */ - return 0; + + return get_unaligned_be16(&rbuf[2]) + 4; } /** * ata_scsiop_inq_80 - Simulate INQUIRY VPD page 80, device serial number - * @args: device IDENTIFY data / SCSI command of interest. + * @dev: Target device. + * @cmd: SCSI command of interest. * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. * * Returns ATA device serial number. @@ -1977,7 +2063,8 @@ static unsigned int ata_scsiop_inq_00(struct ata_scsi_args *args, u8 *rbuf) * LOCKING: * spin_lock_irqsave(host lock) */ -static unsigned int ata_scsiop_inq_80(struct ata_scsi_args *args, u8 *rbuf) +static unsigned int ata_scsiop_inq_80(struct ata_device *dev, + struct scsi_cmnd *cmd, u8 *rbuf) { static const u8 hdr[] = { 0, @@ -1987,14 +2074,16 @@ static unsigned int ata_scsiop_inq_80(struct ata_scsi_args *args, u8 *rbuf) }; memcpy(rbuf, hdr, sizeof(hdr)); - ata_id_string(args->id, (unsigned char *) &rbuf[4], + ata_id_string(dev->id, (unsigned char *) &rbuf[4], ATA_ID_SERNO, ATA_ID_SERNO_LEN); - return 0; + + return get_unaligned_be16(&rbuf[2]) + 4; } /** * ata_scsiop_inq_83 - Simulate INQUIRY VPD page 83, device identity - * @args: device IDENTIFY data / SCSI command of interest. + * @dev: Target device. + * @cmd: SCSI command of interest. * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. * * Yields two logical unit device identification designators: @@ -2005,7 +2094,8 @@ static unsigned int ata_scsiop_inq_80(struct ata_scsi_args *args, u8 *rbuf) * LOCKING: * spin_lock_irqsave(host lock) */ -static unsigned int ata_scsiop_inq_83(struct ata_scsi_args *args, u8 *rbuf) +static unsigned int ata_scsiop_inq_83(struct ata_device *dev, + struct scsi_cmnd *cmd, u8 *rbuf) { const int sat_model_serial_desc_len = 68; int num; @@ -2017,7 +2107,7 @@ static unsigned int ata_scsiop_inq_83(struct ata_scsi_args *args, u8 *rbuf) rbuf[num + 0] = 2; rbuf[num + 3] = ATA_ID_SERNO_LEN; num += 4; - ata_id_string(args->id, (unsigned char *) rbuf + num, + ata_id_string(dev->id, (unsigned char *) rbuf + num, ATA_ID_SERNO, ATA_ID_SERNO_LEN); num += ATA_ID_SERNO_LEN; @@ -2029,31 +2119,33 @@ static unsigned int ata_scsiop_inq_83(struct ata_scsi_args *args, u8 *rbuf) num += 4; memcpy(rbuf + num, "ATA ", 8); num += 8; - ata_id_string(args->id, (unsigned char *) rbuf + num, ATA_ID_PROD, + ata_id_string(dev->id, (unsigned char *) rbuf + num, ATA_ID_PROD, ATA_ID_PROD_LEN); num += ATA_ID_PROD_LEN; - ata_id_string(args->id, (unsigned char *) rbuf + num, ATA_ID_SERNO, + ata_id_string(dev->id, (unsigned char *) rbuf + num, ATA_ID_SERNO, ATA_ID_SERNO_LEN); num += ATA_ID_SERNO_LEN; - if (ata_id_has_wwn(args->id)) { + if (ata_id_has_wwn(dev->id)) { /* SAT defined lu world wide name */ /* piv=0, assoc=lu, code_set=binary, designator=NAA */ rbuf[num + 0] = 1; rbuf[num + 1] = 3; rbuf[num + 3] = ATA_ID_WWN_LEN; num += 4; - ata_id_string(args->id, (unsigned char *) rbuf + num, + ata_id_string(dev->id, (unsigned char *) rbuf + num, ATA_ID_WWN, ATA_ID_WWN_LEN); num += ATA_ID_WWN_LEN; } rbuf[3] = num - 4; /* page len (assume less than 256 bytes) */ - return 0; + + return get_unaligned_be16(&rbuf[2]) + 4; } /** * ata_scsiop_inq_89 - Simulate INQUIRY VPD page 89, ATA info - * @args: device IDENTIFY data / SCSI command of interest. + * @dev: Target device. + * @cmd: SCSI command of interest. * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. * * Yields SAT-specified ATA VPD page. @@ -2061,7 +2153,8 @@ static unsigned int ata_scsiop_inq_83(struct ata_scsi_args *args, u8 *rbuf) * LOCKING: * spin_lock_irqsave(host lock) */ -static unsigned int ata_scsiop_inq_89(struct ata_scsi_args *args, u8 *rbuf) +static unsigned int ata_scsiop_inq_89(struct ata_device *dev, + struct scsi_cmnd *cmd, u8 *rbuf) { rbuf[1] = 0x89; /* our page code */ rbuf[2] = (0x238 >> 8); /* page size fixed at 238h */ @@ -2082,13 +2175,25 @@ static unsigned int ata_scsiop_inq_89(struct ata_scsi_args *args, u8 *rbuf) rbuf[56] = ATA_CMD_ID_ATA; - memcpy(&rbuf[60], &args->id[0], 512); - return 0; + memcpy(&rbuf[60], &dev->id[0], 512); + + return get_unaligned_be16(&rbuf[2]) + 4; } -static unsigned int ata_scsiop_inq_b0(struct ata_scsi_args *args, u8 *rbuf) +/** + * ata_scsiop_inq_b0 - Simulate INQUIRY VPD page B0, Block Limits + * @dev: Target device. + * @cmd: SCSI command of interest. + * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. + * + * Return data for the VPD page B0h (Block Limits). + * + * LOCKING: + * spin_lock_irqsave(host lock) + */ +static unsigned int ata_scsiop_inq_b0(struct ata_device *dev, + struct scsi_cmnd *cmd, u8 *rbuf) { - struct ata_device *dev = args->dev; u16 min_io_sectors; rbuf[1] = 0xb0; @@ -2101,7 +2206,7 @@ static unsigned int ata_scsiop_inq_b0(struct ata_scsi_args *args, u8 *rbuf) * logical than physical sector size we need to figure out what the * latter is. */ - min_io_sectors = 1 << ata_id_log2_per_physical_sector(args->id); + min_io_sectors = 1 << ata_id_log2_per_physical_sector(dev->id); put_unaligned_be16(min_io_sectors, &rbuf[6]); /* @@ -2113,7 +2218,7 @@ static unsigned int ata_scsiop_inq_b0(struct ata_scsi_args *args, u8 *rbuf) * that we support some form of unmap - in thise case via WRITE SAME * with the unmap bit set. */ - if (ata_id_has_trim(args->id)) { + if (ata_id_has_trim(dev->id)) { u64 max_blocks = 65535 * ATA_MAX_TRIM_RNUM; if (dev->quirks & ATA_QUIRK_MAX_TRIM_128M) @@ -2123,14 +2228,27 @@ static unsigned int ata_scsiop_inq_b0(struct ata_scsi_args *args, u8 *rbuf) put_unaligned_be32(1, &rbuf[28]); } - return 0; + return get_unaligned_be16(&rbuf[2]) + 4; } -static unsigned int ata_scsiop_inq_b1(struct ata_scsi_args *args, u8 *rbuf) +/** + * ata_scsiop_inq_b1 - Simulate INQUIRY VPD page B1, Block Device + * Characteristics + * @dev: Target device. + * @cmd: SCSI command of interest. + * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. + * + * Return data for the VPD page B1h (Block Device Characteristics). + * + * LOCKING: + * spin_lock_irqsave(host lock) + */ +static unsigned int ata_scsiop_inq_b1(struct ata_device *dev, + struct scsi_cmnd *cmd, u8 *rbuf) { - int form_factor = ata_id_form_factor(args->id); - int media_rotation_rate = ata_id_rotation_rate(args->id); - u8 zoned = ata_id_zoned_cap(args->id); + int form_factor = ata_id_form_factor(dev->id); + int media_rotation_rate = ata_id_rotation_rate(dev->id); + u8 zoned = ata_id_zoned_cap(dev->id); rbuf[1] = 0xb1; rbuf[3] = 0x3c; @@ -2140,21 +2258,52 @@ static unsigned int ata_scsiop_inq_b1(struct ata_scsi_args *args, u8 *rbuf) if (zoned) rbuf[8] = (zoned << 4); - return 0; + return get_unaligned_be16(&rbuf[2]) + 4; } -static unsigned int ata_scsiop_inq_b2(struct ata_scsi_args *args, u8 *rbuf) +/** + * ata_scsiop_inq_b2 - Simulate INQUIRY VPD page B2, Logical Block + * Provisioning + * @dev: Target device. + * @cmd: SCSI command of interest. + * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. + * + * Return data for the VPD page B2h (Logical Block Provisioning). + * + * LOCKING: + * spin_lock_irqsave(host lock) + */ +static unsigned int ata_scsiop_inq_b2(struct ata_device *dev, + struct scsi_cmnd *cmd, u8 *rbuf) { /* SCSI Thin Provisioning VPD page: SBC-3 rev 22 or later */ rbuf[1] = 0xb2; rbuf[3] = 0x4; rbuf[5] = 1 << 6; /* TPWS */ - return 0; + return get_unaligned_be16(&rbuf[2]) + 4; } -static unsigned int ata_scsiop_inq_b6(struct ata_scsi_args *args, u8 *rbuf) +/** + * ata_scsiop_inq_b6 - Simulate INQUIRY VPD page B6, Zoned Block Device + * Characteristics + * @dev: Target device. + * @cmd: SCSI command of interest. + * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. + * + * Return data for the VPD page B2h (Zoned Block Device Characteristics). + * + * LOCKING: + * spin_lock_irqsave(host lock) + */ +static unsigned int ata_scsiop_inq_b6(struct ata_device *dev, + struct scsi_cmnd *cmd, u8 *rbuf) { + if (!ata_dev_is_zac(dev)) { + ata_scsi_set_invalid_field(dev, cmd, 2, 0xff); + return 0; + } + /* * zbc-r05 SCSI Zoned Block device characteristics VPD page */ @@ -2164,21 +2313,39 @@ static unsigned int ata_scsiop_inq_b6(struct ata_scsi_args *args, u8 *rbuf) /* * URSWRZ bit is only meaningful for host-managed ZAC drives */ - if (args->dev->zac_zoned_cap & 1) + if (dev->zac_zoned_cap & 1) rbuf[4] |= 1; - put_unaligned_be32(args->dev->zac_zones_optimal_open, &rbuf[8]); - put_unaligned_be32(args->dev->zac_zones_optimal_nonseq, &rbuf[12]); - put_unaligned_be32(args->dev->zac_zones_max_open, &rbuf[16]); + put_unaligned_be32(dev->zac_zones_optimal_open, &rbuf[8]); + put_unaligned_be32(dev->zac_zones_optimal_nonseq, &rbuf[12]); + put_unaligned_be32(dev->zac_zones_max_open, &rbuf[16]); - return 0; + return get_unaligned_be16(&rbuf[2]) + 4; } -static unsigned int ata_scsiop_inq_b9(struct ata_scsi_args *args, u8 *rbuf) +/** + * ata_scsiop_inq_b9 - Simulate INQUIRY VPD page B9, Concurrent Positioning + * Ranges + * @dev: Target device. + * @cmd: SCSI command of interest. + * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. + * + * Return data for the VPD page B9h (Concurrent Positioning Ranges). + * + * LOCKING: + * spin_lock_irqsave(host lock) + */ +static unsigned int ata_scsiop_inq_b9(struct ata_device *dev, + struct scsi_cmnd *cmd, u8 *rbuf) { - struct ata_cpr_log *cpr_log = args->dev->cpr_log; + struct ata_cpr_log *cpr_log = dev->cpr_log; u8 *desc = &rbuf[64]; int i; + if (!cpr_log) { + ata_scsi_set_invalid_field(dev, cmd, 2, 0xff); + return 0; + } + /* SCSI Concurrent Positioning Ranges VPD page: SBC-5 rev 1 or later */ rbuf[1] = 0xb9; put_unaligned_be16(64 + (int)cpr_log->nr_cpr * 32 - 4, &rbuf[2]); @@ -2190,7 +2357,58 @@ static unsigned int ata_scsiop_inq_b9(struct ata_scsi_args *args, u8 *rbuf) put_unaligned_be64(cpr_log->cpr[i].num_lbas, &desc[16]); } - return 0; + return get_unaligned_be16(&rbuf[2]) + 4; +} + +/** + * ata_scsiop_inquiry - Simulate INQUIRY command + * @dev: Target device. + * @cmd: SCSI command of interest. + * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. + * + * Returns data associated with an INQUIRY command output. + * + * LOCKING: + * spin_lock_irqsave(host lock) + */ +static unsigned int ata_scsiop_inquiry(struct ata_device *dev, + struct scsi_cmnd *cmd, u8 *rbuf) +{ + const u8 *scsicmd = cmd->cmnd; + + /* is CmdDt set? */ + if (scsicmd[1] & 2) { + ata_scsi_set_invalid_field(dev, cmd, 1, 0xff); + return 0; + } + + /* Is EVPD clear? */ + if ((scsicmd[1] & 1) == 0) + return ata_scsiop_inq_std(dev, cmd, rbuf); + + switch (scsicmd[2]) { + case 0x00: + return ata_scsiop_inq_00(dev, cmd, rbuf); + case 0x80: + return ata_scsiop_inq_80(dev, cmd, rbuf); + case 0x83: + return ata_scsiop_inq_83(dev, cmd, rbuf); + case 0x89: + return ata_scsiop_inq_89(dev, cmd, rbuf); + case 0xb0: + return ata_scsiop_inq_b0(dev, cmd, rbuf); + case 0xb1: + return ata_scsiop_inq_b1(dev, cmd, rbuf); + case 0xb2: + return ata_scsiop_inq_b2(dev, cmd, rbuf); + case 0xb6: + return ata_scsiop_inq_b6(dev, cmd, rbuf); + case 0xb9: + return ata_scsiop_inq_b9(dev, cmd, rbuf); + default: + ata_scsi_set_invalid_field(dev, cmd, 2, 0xff); + return 0; + } } /** @@ -2413,7 +2631,8 @@ static unsigned int ata_msense_rw_recovery(u8 *buf, bool changeable) /** * ata_scsiop_mode_sense - Simulate MODE SENSE 6, 10 commands - * @args: device IDENTIFY data / SCSI command of interest. + * @dev: Target device. + * @cmd: SCSI command of interest. * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. * * Simulate MODE SENSE commands. Assume this is invoked for direct @@ -2423,10 +2642,10 @@ static unsigned int ata_msense_rw_recovery(u8 *buf, bool changeable) * LOCKING: * spin_lock_irqsave(host lock) */ -static unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf) +static unsigned int ata_scsiop_mode_sense(struct ata_device *dev, + struct scsi_cmnd *cmd, u8 *rbuf) { - struct ata_device *dev = args->dev; - u8 *scsicmd = args->cmd->cmnd, *p = rbuf; + u8 *scsicmd = cmd->cmnd, *p = rbuf; static const u8 sat_blk_desc[] = { 0, 0, 0, 0, /* number of blocks: sat unspecified */ 0, @@ -2491,17 +2710,17 @@ static unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf) break; case CACHE_MPAGE: - p += ata_msense_caching(args->id, p, page_control == 1); + p += ata_msense_caching(dev->id, p, page_control == 1); break; case CONTROL_MPAGE: - p += ata_msense_control(args->dev, p, spg, page_control == 1); + p += ata_msense_control(dev, p, spg, page_control == 1); break; case ALL_MPAGES: p += ata_msense_rw_recovery(p, page_control == 1); - p += ata_msense_caching(args->id, p, page_control == 1); - p += ata_msense_control(args->dev, p, spg, page_control == 1); + p += ata_msense_caching(dev->id, p, page_control == 1); + p += ata_msense_control(dev, p, spg, page_control == 1); break; default: /* invalid page code */ @@ -2519,29 +2738,33 @@ static unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf) rbuf[3] = sizeof(sat_blk_desc); memcpy(rbuf + 4, sat_blk_desc, sizeof(sat_blk_desc)); } - } else { - put_unaligned_be16(p - rbuf - 2, &rbuf[0]); - rbuf[3] |= dpofua; - if (ebd) { - rbuf[7] = sizeof(sat_blk_desc); - memcpy(rbuf + 8, sat_blk_desc, sizeof(sat_blk_desc)); - } + + return rbuf[0] + 1; } - return 0; + + put_unaligned_be16(p - rbuf - 2, &rbuf[0]); + rbuf[3] |= dpofua; + if (ebd) { + rbuf[7] = sizeof(sat_blk_desc); + memcpy(rbuf + 8, sat_blk_desc, sizeof(sat_blk_desc)); + } + + return get_unaligned_be16(&rbuf[0]) + 2; invalid_fld: - ata_scsi_set_invalid_field(dev, args->cmd, fp, bp); - return 1; + ata_scsi_set_invalid_field(dev, cmd, fp, bp); + return 0; saving_not_supp: - ata_scsi_set_sense(dev, args->cmd, ILLEGAL_REQUEST, 0x39, 0x0); + ata_scsi_set_sense(dev, cmd, ILLEGAL_REQUEST, 0x39, 0x0); /* "Saving parameters not supported" */ - return 1; + return 0; } /** * ata_scsiop_read_cap - Simulate READ CAPACITY[ 16] commands - * @args: device IDENTIFY data / SCSI command of interest. + * @dev: Target device. + * @cmd: SCSI command of interest. * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. * * Simulate READ CAPACITY commands. @@ -2549,9 +2772,10 @@ saving_not_supp: * LOCKING: * None. */ -static unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf) +static unsigned int ata_scsiop_read_cap(struct ata_device *dev, + struct scsi_cmnd *cmd, u8 *rbuf) { - struct ata_device *dev = args->dev; + u8 *scsicmd = cmd->cmnd; u64 last_lba = dev->n_sectors - 1; /* LBA of the last block */ u32 sector_size; /* physical sector size in bytes */ u8 log2_per_phys; @@ -2561,7 +2785,7 @@ static unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf) log2_per_phys = ata_id_log2_per_physical_sector(dev->id); lowest_aligned = ata_id_logical_sector_offset(dev->id, log2_per_phys); - if (args->cmd->cmnd[0] == READ_CAPACITY) { + if (scsicmd[0] == READ_CAPACITY) { if (last_lba >= 0xffffffffULL) last_lba = 0xffffffff; @@ -2576,48 +2800,59 @@ static unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf) rbuf[5] = sector_size >> (8 * 2); rbuf[6] = sector_size >> (8 * 1); rbuf[7] = sector_size; - } else { - /* sector count, 64-bit */ - rbuf[0] = last_lba >> (8 * 7); - rbuf[1] = last_lba >> (8 * 6); - rbuf[2] = last_lba >> (8 * 5); - rbuf[3] = last_lba >> (8 * 4); - rbuf[4] = last_lba >> (8 * 3); - rbuf[5] = last_lba >> (8 * 2); - rbuf[6] = last_lba >> (8 * 1); - rbuf[7] = last_lba; - /* sector size */ - rbuf[ 8] = sector_size >> (8 * 3); - rbuf[ 9] = sector_size >> (8 * 2); - rbuf[10] = sector_size >> (8 * 1); - rbuf[11] = sector_size; - - rbuf[12] = 0; - rbuf[13] = log2_per_phys; - rbuf[14] = (lowest_aligned >> 8) & 0x3f; - rbuf[15] = lowest_aligned; - - if (ata_id_has_trim(args->id) && - !(dev->quirks & ATA_QUIRK_NOTRIM)) { - rbuf[14] |= 0x80; /* LBPME */ - - if (ata_id_has_zero_after_trim(args->id) && - dev->quirks & ATA_QUIRK_ZERO_AFTER_TRIM) { - ata_dev_info(dev, "Enabling discard_zeroes_data\n"); - rbuf[14] |= 0x40; /* LBPRZ */ - } + return 8; + } + + /* + * READ CAPACITY 16 command is defined as a service action + * (SERVICE_ACTION_IN_16 command). + */ + if (scsicmd[0] != SERVICE_ACTION_IN_16 || + (scsicmd[1] & 0x1f) != SAI_READ_CAPACITY_16) { + ata_scsi_set_invalid_field(dev, cmd, 1, 0xff); + return 0; + } + + /* sector count, 64-bit */ + rbuf[0] = last_lba >> (8 * 7); + rbuf[1] = last_lba >> (8 * 6); + rbuf[2] = last_lba >> (8 * 5); + rbuf[3] = last_lba >> (8 * 4); + rbuf[4] = last_lba >> (8 * 3); + rbuf[5] = last_lba >> (8 * 2); + rbuf[6] = last_lba >> (8 * 1); + rbuf[7] = last_lba; + + /* sector size */ + rbuf[ 8] = sector_size >> (8 * 3); + rbuf[ 9] = sector_size >> (8 * 2); + rbuf[10] = sector_size >> (8 * 1); + rbuf[11] = sector_size; + + if (ata_id_zoned_cap(dev->id) || dev->class == ATA_DEV_ZAC) + rbuf[12] = (1 << 4); /* RC_BASIS */ + rbuf[13] = log2_per_phys; + rbuf[14] = (lowest_aligned >> 8) & 0x3f; + rbuf[15] = lowest_aligned; + + if (ata_id_has_trim(dev->id) && !(dev->quirks & ATA_QUIRK_NOTRIM)) { + rbuf[14] |= 0x80; /* LBPME */ + + if (ata_id_has_zero_after_trim(dev->id) && + dev->quirks & ATA_QUIRK_ZERO_AFTER_TRIM) { + ata_dev_info(dev, "Enabling discard_zeroes_data\n"); + rbuf[14] |= 0x40; /* LBPRZ */ } - if (ata_id_zoned_cap(args->id) || - args->dev->class == ATA_DEV_ZAC) - rbuf[12] = (1 << 4); /* RC_BASIS */ } - return 0; + + return 16; } /** * ata_scsiop_report_luns - Simulate REPORT LUNS command - * @args: device IDENTIFY data / SCSI command of interest. + * @dev: Target device. + * @cmd: SCSI command of interest. * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. * * Simulate REPORT LUNS command. @@ -2625,11 +2860,12 @@ static unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf) * LOCKING: * spin_lock_irqsave(host lock) */ -static unsigned int ata_scsiop_report_luns(struct ata_scsi_args *args, u8 *rbuf) +static unsigned int ata_scsiop_report_luns(struct ata_device *dev, + struct scsi_cmnd *cmd, u8 *rbuf) { rbuf[3] = 8; /* just one lun, LUN 0, size 8 bytes */ - return 0; + return 16; } /* @@ -3340,7 +3576,8 @@ invalid_opcode: /** * ata_scsiop_maint_in - Simulate a subset of MAINTENANCE_IN - * @args: device MAINTENANCE_IN data / SCSI command of interest. + * @dev: Target device. + * @cmd: SCSI command of interest. * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. * * Yields a subset to satisfy scsi_report_opcode() @@ -3348,17 +3585,21 @@ invalid_opcode: * LOCKING: * spin_lock_irqsave(host lock) */ -static unsigned int ata_scsiop_maint_in(struct ata_scsi_args *args, u8 *rbuf) +static unsigned int ata_scsiop_maint_in(struct ata_device *dev, + struct scsi_cmnd *cmd, u8 *rbuf) { - struct ata_device *dev = args->dev; - u8 *cdb = args->cmd->cmnd; + u8 *cdb = cmd->cmnd; u8 supported = 0, cdlp = 0, rwcdlp = 0; - unsigned int err = 0; + + if ((cdb[1] & 0x1f) != MI_REPORT_SUPPORTED_OPERATION_CODES) { + ata_scsi_set_invalid_field(dev, cmd, 1, 0xff); + return 0; + } if (cdb[2] != 1 && cdb[2] != 3) { ata_dev_warn(dev, "invalid command format %d\n", cdb[2]); - err = 2; - goto out; + ata_scsi_set_invalid_field(dev, cmd, 1, 0xff); + return 0; } switch (cdb[3]) { @@ -3426,11 +3667,12 @@ static unsigned int ata_scsiop_maint_in(struct ata_scsi_args *args, u8 *rbuf) default: break; } -out: + /* One command format */ rbuf[0] = rwcdlp; rbuf[1] = cdlp | supported; - return err; + + return 4; } /** @@ -4191,9 +4433,10 @@ int __ata_scsi_queuecmd(struct scsi_cmnd *scmd, struct ata_device *dev) * scsi_queue_rq() will defer commands if scsi_host_in_recovery(). * However, this check is done without holding the ap->lock (a libata * specific lock), so we can have received an error irq since then, - * therefore we must check if EH is pending, while holding ap->lock. + * therefore we must check if EH is pending or running, while holding + * ap->lock. */ - if (ap->pflags & (ATA_PFLAG_EH_PENDING | ATA_PFLAG_EH_IN_PROGRESS)) + if (ata_port_eh_scheduled(ap)) return SCSI_MLQUEUE_DEVICE_BUSY; if (unlikely(!scmd->cmd_len)) @@ -4294,78 +4537,26 @@ EXPORT_SYMBOL_GPL(ata_scsi_queuecmd); void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd) { - struct ata_scsi_args args; const u8 *scsicmd = cmd->cmnd; u8 tmp8; - args.dev = dev; - args.id = dev->id; - args.cmd = cmd; - switch(scsicmd[0]) { case INQUIRY: - if (scsicmd[1] & 2) /* is CmdDt set? */ - ata_scsi_set_invalid_field(dev, cmd, 1, 0xff); - else if ((scsicmd[1] & 1) == 0) /* is EVPD clear? */ - ata_scsi_rbuf_fill(&args, ata_scsiop_inq_std); - else switch (scsicmd[2]) { - case 0x00: - ata_scsi_rbuf_fill(&args, ata_scsiop_inq_00); - break; - case 0x80: - ata_scsi_rbuf_fill(&args, ata_scsiop_inq_80); - break; - case 0x83: - ata_scsi_rbuf_fill(&args, ata_scsiop_inq_83); - break; - case 0x89: - ata_scsi_rbuf_fill(&args, ata_scsiop_inq_89); - break; - case 0xb0: - ata_scsi_rbuf_fill(&args, ata_scsiop_inq_b0); - break; - case 0xb1: - ata_scsi_rbuf_fill(&args, ata_scsiop_inq_b1); - break; - case 0xb2: - ata_scsi_rbuf_fill(&args, ata_scsiop_inq_b2); - break; - case 0xb6: - if (dev->flags & ATA_DFLAG_ZAC) - ata_scsi_rbuf_fill(&args, ata_scsiop_inq_b6); - else - ata_scsi_set_invalid_field(dev, cmd, 2, 0xff); - break; - case 0xb9: - if (dev->cpr_log) - ata_scsi_rbuf_fill(&args, ata_scsiop_inq_b9); - else - ata_scsi_set_invalid_field(dev, cmd, 2, 0xff); - break; - default: - ata_scsi_set_invalid_field(dev, cmd, 2, 0xff); - break; - } + ata_scsi_rbuf_fill(dev, cmd, ata_scsiop_inquiry); break; case MODE_SENSE: case MODE_SENSE_10: - ata_scsi_rbuf_fill(&args, ata_scsiop_mode_sense); + ata_scsi_rbuf_fill(dev, cmd, ata_scsiop_mode_sense); break; case READ_CAPACITY: - ata_scsi_rbuf_fill(&args, ata_scsiop_read_cap); - break; - case SERVICE_ACTION_IN_16: - if ((scsicmd[1] & 0x1f) == SAI_READ_CAPACITY_16) - ata_scsi_rbuf_fill(&args, ata_scsiop_read_cap); - else - ata_scsi_set_invalid_field(dev, cmd, 1, 0xff); + ata_scsi_rbuf_fill(dev, cmd, ata_scsiop_read_cap); break; case REPORT_LUNS: - ata_scsi_rbuf_fill(&args, ata_scsiop_report_luns); + ata_scsi_rbuf_fill(dev, cmd, ata_scsiop_report_luns); break; case REQUEST_SENSE: @@ -4393,10 +4584,7 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd) break; case MAINTENANCE_IN: - if ((scsicmd[1] & 0x1f) == MI_REPORT_SUPPORTED_OPERATION_CODES) - ata_scsi_rbuf_fill(&args, ata_scsiop_maint_in); - else - ata_scsi_set_invalid_field(dev, cmd, 1, 0xff); + ata_scsi_rbuf_fill(dev, cmd, ata_scsiop_maint_in); break; /* all other commands */ @@ -4563,24 +4751,23 @@ void ata_scsi_scan_host(struct ata_port *ap, int sync) * ata_scsi_offline_dev - offline attached SCSI device * @dev: ATA device to offline attached SCSI device for * - * This function is called from ata_eh_hotplug() and responsible - * for taking the SCSI device attached to @dev offline. This - * function is called with host lock which protects dev->sdev - * against clearing. + * This function is called from ata_eh_detach_dev() and is responsible for + * taking the SCSI device attached to @dev offline. This function is + * called with host lock which protects dev->sdev against clearing. * * LOCKING: * spin_lock_irqsave(host lock) * * RETURNS: - * 1 if attached SCSI device exists, 0 otherwise. + * true if attached SCSI device exists, false otherwise. */ -int ata_scsi_offline_dev(struct ata_device *dev) +bool ata_scsi_offline_dev(struct ata_device *dev) { if (dev->sdev) { scsi_device_set_state(dev->sdev, SDEV_OFFLINE); - return 1; + return true; } - return 0; + return false; } /** |
