diff options
Diffstat (limited to 'drivers/ata/libata-scsi.c')
-rw-r--r-- | drivers/ata/libata-scsi.c | 847 |
1 files changed, 495 insertions, 352 deletions
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index e954976891a9..a21c9895408d 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -30,7 +30,7 @@ #include <linux/hdreg.h> #include <linux/uaccess.h> #include <linux/suspend.h> -#include <asm/unaligned.h> +#include <linux/unaligned.h> #include <linux/ioprio.h> #include <linux/of.h> @@ -216,20 +216,105 @@ 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); } +/** + * ata_scsi_set_passthru_sense_fields - Set ATA fields in sense buffer + * @qc: ATA PASS-THROUGH command. + * + * Populates "ATA Status Return sense data descriptor" / "Fixed format + * sense data" with ATA taskfile fields. + * + * LOCKING: + * None. + */ +static void ata_scsi_set_passthru_sense_fields(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; + + if (!(qc->flags & ATA_QCFLAG_RTF_FILLED)) { + ata_dev_dbg(dev, + "missing result TF: can't set ATA PT sense fields\n"); + return; + } + + if ((sb[0] & 0x7f) >= 0x72) { + unsigned char *desc; + u8 len; + + /* descriptor format */ + len = sb[7]; + desc = (char *)scsi_sense_desc_find(sb, len + 8, 9); + if (!desc) { + if (SCSI_SENSE_BUFFERSIZE < len + 14) + return; + sb[7] = len + 14; + desc = sb + 8 + len; + } + desc[0] = 9; + desc[1] = 12; + /* + * Copy registers into sense buffer. + */ + desc[2] = 0x00; + desc[3] = tf->error; + desc[5] = tf->nsect; + desc[7] = tf->lbal; + desc[9] = tf->lbam; + desc[11] = tf->lbah; + desc[12] = tf->device; + desc[13] = tf->status; + + /* + * Fill in Extend bit, and the high order bytes + * if applicable. + */ + if (tf->flags & ATA_TFLAG_LBA48) { + desc[2] |= 0x01; + desc[4] = tf->hob_nsect; + desc[6] = tf->hob_lbal; + desc[8] = tf->hob_lbam; + desc[10] = tf->hob_lbah; + } + } else { + /* Fixed sense format */ + sb[0] |= 0x80; + sb[3] = tf->error; + sb[4] = tf->status; + sb[5] = tf->device; + sb[6] = tf->nsect; + if (tf->flags & ATA_TFLAG_LBA48) { + sb[8] |= 0x80; + if (tf->hob_nsect) + sb[8] |= 0x40; + if (tf->hob_lbal || tf->hob_lbam || tf->hob_lbah) + sb[8] |= 0x20; + } + sb[9] = tf->lbal; + sb[10] = tf->lbam; + sb[11] = tf->lbah; + } +} + static void ata_scsi_set_invalid_field(struct ata_device *dev, struct scsi_cmnd *cmd, u16 field, u8 bit) { @@ -711,7 +796,6 @@ static void ata_qc_set_pc_nbytes(struct ata_queued_cmd *qc) /** * ata_to_sense_error - convert ATA error to SCSI error - * @id: ATA device number * @drv_stat: value contained in ATA status register * @drv_err: value contained in ATA error register * @sk: the sense key we'll fill out @@ -725,8 +809,8 @@ static void ata_qc_set_pc_nbytes(struct ata_queued_cmd *qc) * LOCKING: * spin_lock_irqsave(host lock) */ -static void ata_to_sense_error(unsigned id, u8 drv_stat, u8 drv_err, u8 *sk, - u8 *asc, u8 *ascq) +static void ata_to_sense_error(u8 drv_stat, u8 drv_err, u8 *sk, u8 *asc, + u8 *ascq) { int i; @@ -837,10 +921,8 @@ static void ata_to_sense_error(unsigned id, u8 drv_stat, u8 drv_err, u8 *sk, * ata_gen_passthru_sense - Generate check condition sense block. * @qc: Command that completed. * - * This function is specific to the ATA descriptor format sense - * block specified for the ATA pass through commands. Regardless - * of whether the command errored or not, return a sense - * block. Copy all controller registers into the sense + * This function is specific to the ATA pass through commands. + * Regardless of whether the command errored or not, return a sense * block. If there was no error, we get the request from an ATA * passthrough command, so we use the following sense data: * sk = RECOVERED ERROR @@ -852,13 +934,16 @@ static void ata_to_sense_error(unsigned id, u8 drv_stat, u8 drv_err, u8 *sk, */ static void ata_gen_passthru_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; - unsigned char *desc = sb + 8; u8 sense_key, asc, ascq; - memset(sb, 0, SCSI_SENSE_BUFFERSIZE); + if (!(qc->flags & ATA_QCFLAG_RTF_FILLED)) { + ata_dev_dbg(dev, + "missing result TF: can't generate ATA PT sense data\n"); + return; + } /* * Use ata_to_sense_error() to map status register bits @@ -866,80 +951,31 @@ static void ata_gen_passthru_sense(struct ata_queued_cmd *qc) */ if (qc->err_mask || tf->status & (ATA_BUSY | ATA_DF | ATA_ERR | ATA_DRQ)) { - ata_to_sense_error(qc->ap->print_id, tf->status, tf->error, + ata_to_sense_error(tf->status, tf->error, &sense_key, &asc, &ascq); ata_scsi_set_sense(qc->dev, cmd, sense_key, asc, ascq); } else { /* * ATA PASS-THROUGH INFORMATION AVAILABLE - * Always in descriptor format sense. + * + * Note: we are supposed to call ata_scsi_set_sense(), which + * respects the D_SENSE bit, instead of unconditionally + * generating the sense data in descriptor format. However, + * because hdparm, hddtemp, and udisks incorrectly assume sense + * data in descriptor format, without even looking at the + * RESPONSE CODE field in the returned sense data (to see which + * format the returned sense data is in), we are stuck with + * being bug compatible with older kernels. */ scsi_build_sense(cmd, 1, RECOVERED_ERROR, 0, 0x1D); } - - if ((cmd->sense_buffer[0] & 0x7f) >= 0x72) { - u8 len; - - /* descriptor format */ - len = sb[7]; - desc = (char *)scsi_sense_desc_find(sb, len + 8, 9); - if (!desc) { - if (SCSI_SENSE_BUFFERSIZE < len + 14) - return; - sb[7] = len + 14; - desc = sb + 8 + len; - } - desc[0] = 9; - desc[1] = 12; - /* - * Copy registers into sense buffer. - */ - desc[2] = 0x00; - desc[3] = tf->error; - desc[5] = tf->nsect; - desc[7] = tf->lbal; - desc[9] = tf->lbam; - desc[11] = tf->lbah; - desc[12] = tf->device; - desc[13] = tf->status; - - /* - * Fill in Extend bit, and the high order bytes - * if applicable. - */ - if (tf->flags & ATA_TFLAG_LBA48) { - desc[2] |= 0x01; - desc[4] = tf->hob_nsect; - desc[6] = tf->hob_lbal; - desc[8] = tf->hob_lbam; - desc[10] = tf->hob_lbah; - } - } else { - /* Fixed sense format */ - desc[0] = tf->error; - desc[1] = tf->status; - desc[2] = tf->device; - desc[3] = tf->nsect; - desc[7] = 0; - if (tf->flags & ATA_TFLAG_LBA48) { - desc[8] |= 0x80; - if (tf->hob_nsect) - desc[8] |= 0x40; - if (tf->hob_lbal || tf->hob_lbam || tf->hob_lbah) - desc[8] |= 0x20; - } - desc[9] = tf->lbal; - desc[10] = tf->lbam; - desc[11] = tf->lbah; - } } /** * 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. @@ -949,24 +985,27 @@ 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; - memset(sb, 0, SCSI_SENSE_BUFFERSIZE); - if (ata_dev_disabled(dev)) { /* Device disabled after error recovery */ /* LOGICAL UNIT NOT READY, HARD RESET REQUIRED */ ata_scsi_set_sense(dev, cmd, NOT_READY, 0x04, 0x21); return; } + + if (!(qc->flags & ATA_QCFLAG_RTF_FILLED)) { + ata_dev_dbg(dev, + "missing result TF: can't generate sense data\n"); + return; + } + /* Use ata_to_sense_error() to map status register bits * onto sense key, asc & ascq. */ if (qc->err_mask || tf->status & (ATA_BUSY | ATA_DF | ATA_ERR | ATA_DRQ)) { - ata_to_sense_error(qc->ap->print_id, tf->status, tf->error, + ata_to_sense_error(tf->status, tf->error, &sense_key, &asc, &ascq); ata_scsi_set_sense(dev, cmd, sense_key, asc, ascq); } else { @@ -976,12 +1015,6 @@ static void ata_gen_ata_sense(struct ata_queued_cmd *qc) ata_scsi_set_sense(dev, cmd, ABORTED_COMMAND, 0, 0); return; } - - block = ata_tf_read_block(&qc->result_tf, dev); - if (block == U64_MAX) - return; - - scsi_set_sense_information(sb, SCSI_SENSE_BUFFERSIZE, block); } void ata_scsi_sdev_config(struct scsi_device *sdev) @@ -1021,9 +1054,9 @@ bool ata_scsi_dma_need_drain(struct request *rq) } EXPORT_SYMBOL_GPL(ata_scsi_dma_need_drain); -int ata_scsi_dev_config(struct scsi_device *sdev, struct ata_device *dev) +int ata_scsi_dev_config(struct scsi_device *sdev, struct queue_limits *lim, + struct ata_device *dev) { - struct request_queue *q = sdev->request_queue; int depth = 1; if (!ata_id_has_unload(dev->id)) @@ -1031,16 +1064,16 @@ int ata_scsi_dev_config(struct scsi_device *sdev, struct ata_device *dev) /* configure max sectors */ dev->max_sectors = min(dev->max_sectors, sdev->host->max_sectors); - blk_queue_max_hw_sectors(q, dev->max_sectors); + lim->max_hw_sectors = dev->max_sectors; if (dev->class == ATA_DEV_ATAPI) { sdev->sector_size = ATA_SECT_SIZE; /* set DMA padding */ - blk_queue_update_dma_pad(q, ATA_DMA_PAD_SZ - 1); + lim->dma_pad_mask = ATA_DMA_PAD_SZ - 1; /* make room for appending the drain */ - blk_queue_max_segments(q, queue_max_segments(q) - 1); + lim->max_segments--; sdev->dma_drain_len = ATAPI_MAX_DRAIN; sdev->dma_drain_buf = kmalloc(sdev->dma_drain_len, GFP_NOIO); @@ -1077,7 +1110,7 @@ int ata_scsi_dev_config(struct scsi_device *sdev, struct ata_device *dev) "sector_size=%u > PAGE_SIZE, PIO may malfunction\n", sdev->sector_size); - blk_queue_update_dma_alignment(q, sdev->sector_size - 1); + lim->dma_alignment = sdev->sector_size - 1; if (dev->flags & ATA_DFLAG_AN) set_bit(SDEV_EVT_MEDIA_CHANGE, sdev->supported_events); @@ -1095,7 +1128,7 @@ int ata_scsi_dev_config(struct scsi_device *sdev, struct ata_device *dev) } /** - * 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 @@ -1105,7 +1138,7 @@ int ata_scsi_dev_config(struct scsi_device *sdev, struct ata_device *dev) * 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; @@ -1128,11 +1161,12 @@ 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_slave_config - Set SCSI device attributes + * ata_scsi_sdev_configure - Set SCSI device attributes * @sdev: SCSI device to examine + * @lim: queue limits * * This is called before we actually start reading * and writing to the device, to configure certain @@ -1142,20 +1176,20 @@ EXPORT_SYMBOL_GPL(ata_scsi_slave_alloc); * Defined by SCSI layer. We don't really care. */ -int ata_scsi_slave_config(struct scsi_device *sdev) +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); if (dev) - return ata_scsi_dev_config(sdev, dev); + return ata_scsi_dev_config(sdev, lim, dev); return 0; } -EXPORT_SYMBOL_GPL(ata_scsi_slave_config); +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 @@ -1168,7 +1202,7 @@ EXPORT_SYMBOL_GPL(ata_scsi_slave_config); * 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; @@ -1188,7 +1222,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 @@ -1294,17 +1328,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]; } /** @@ -1629,26 +1654,31 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc) { struct scsi_cmnd *cmd = qc->scsicmd; u8 *cdb = cmd->cmnd; - int need_sense = (qc->err_mask != 0) && - !(qc->flags & ATA_QCFLAG_SENSE_VALID); + bool have_sense = qc->flags & ATA_QCFLAG_SENSE_VALID; + bool is_ata_passthru = cdb[0] == ATA_16 || cdb[0] == ATA_12; + bool is_ck_cond_request = cdb[2] & 0x20; + bool is_error = qc->err_mask != 0; /* For ATA pass thru (SAT) commands, generate a sense block if * user mandated it or if there's an error. Note that if we - * generate because the user forced us to [CK_COND =1], a check + * generate because the user forced us to [CK_COND=1], a check * condition is generated and the ATA register values are returned * whether the command completed successfully or not. If there - * was no error, we use the following sense data: + * was no error, and CK_COND=1, we use the following sense data: * sk = RECOVERED ERROR * asc,ascq = ATA PASS-THROUGH INFORMATION AVAILABLE */ - if (((cdb[0] == ATA_16) || (cdb[0] == ATA_12)) && - ((cdb[2] & 0x20) || need_sense)) - ata_gen_passthru_sense(qc); - else if (need_sense) - ata_gen_ata_sense(qc); - else - /* Keep the SCSI ML and status byte, clear host byte. */ - cmd->result &= 0x0000ffff; + if (is_ata_passthru && (is_ck_cond_request || is_error || have_sense)) { + if (!have_sense) + ata_gen_passthru_sense(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) { + if (!have_sense) + ata_gen_ata_sense(qc); + ata_scsi_set_sense_information(qc); + } ata_qc_done(qc); } @@ -1738,15 +1768,10 @@ defer: return SCSI_MLQUEUE_HOST_BUSY; } -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... @@ -1759,30 +1784,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 @@ -1791,7 +1818,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, @@ -1828,44 +1856,49 @@ static unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf) 2 }; - /* set scsi removable (RMB) bit per ata bit, or if the - * AHCI port says it's external (Hotplug-capable, eSATA). + /* + * 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) || - (args->dev->link->ap->pflags & ATA_PFLAG_EXTERNAL)) + 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. @@ -1873,7 +1906,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[] = { @@ -1890,18 +1924,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)) + !(dev->flags & ATA_DFLAG_ZAC)) 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. @@ -1909,7 +1945,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, @@ -1919,14 +1956,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: @@ -1937,7 +1976,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; @@ -1949,7 +1989,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; @@ -1961,31 +2001,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. @@ -1993,7 +2035,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 */ @@ -2014,13 +2057,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; @@ -2033,7 +2088,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]); /* @@ -2045,24 +2100,37 @@ 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->horkage & ATA_HORKAGE_MAX_TRIM_128M) + if (dev->quirks & ATA_QUIRK_MAX_TRIM_128M) max_blocks = 128 << (20 - SECTOR_SHIFT); put_unaligned_be64(max_blocks, &rbuf[36]); 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; @@ -2072,21 +2140,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 (!(dev->flags & ATA_DFLAG_ZAC)) { + ata_scsi_set_invalid_field(dev, cmd, 2, 0xff); + return 0; + } + /* * zbc-r05 SCSI Zoned Block device characteristics VPD page */ @@ -2096,21 +2195,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]); @@ -2122,7 +2239,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; + } } /** @@ -2213,10 +2381,15 @@ static inline u16 ata_xlat_cdl_limit(u8 *buf) static unsigned int ata_msense_control_spgt2(struct ata_device *dev, u8 *buf, u8 spg) { - u8 *b, *cdl = dev->cdl, *desc; + u8 *b, *cdl, *desc; u32 policy; int i; + if (!(dev->flags & ATA_DFLAG_CDL) || !dev->cdl) + return 0; + + cdl = dev->cdl->desc_log_buf; + /* * Fill the subpage. The first four bytes of the T2A/T2B mode pages * are a header. The PAGE LENGTH field is the size of the page @@ -2277,8 +2450,8 @@ static unsigned int ata_msense_control_ata_feature(struct ata_device *dev, */ put_unaligned_be16(ATA_FEATURE_SUB_MPAGE_LEN - 4, &buf[2]); - if (dev->flags & ATA_DFLAG_CDL) - buf[4] = 0x02; /* Support T2A and T2B pages */ + if (dev->flags & ATA_DFLAG_CDL_ENABLED) + buf[4] = 0x02; /* T2A and T2B pages enabled */ else buf[4] = 0; @@ -2313,7 +2486,7 @@ static unsigned int ata_msense_control(struct ata_device *dev, u8 *buf, case ALL_SUB_MPAGES: n = ata_msense_control_spg0(dev, buf, changeable); n += ata_msense_control_spgt2(dev, buf + n, CDL_T2A_SUB_MPAGE); - n += ata_msense_control_spgt2(dev, buf + n, CDL_T2A_SUB_MPAGE); + n += ata_msense_control_spgt2(dev, buf + n, CDL_T2B_SUB_MPAGE); n += ata_msense_control_ata_feature(dev, buf + n); return n; default: @@ -2340,7 +2513,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 @@ -2350,10 +2524,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, @@ -2418,17 +2592,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 */ @@ -2446,29 +2620,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. @@ -2476,9 +2654,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; @@ -2488,7 +2667,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; @@ -2503,48 +2682,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->horkage & ATA_HORKAGE_NOTRIM)) { - rbuf[14] |= 0x80; /* LBPME */ - - if (ata_id_has_zero_after_trim(args->id) && - dev->horkage & ATA_HORKAGE_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. @@ -2552,11 +2742,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; } /* @@ -2587,14 +2778,8 @@ static void atapi_qc_complete(struct ata_queued_cmd *qc) /* handle completion from EH */ if (unlikely(err_mask || qc->flags & ATA_QCFLAG_SENSE_VALID)) { - if (!(qc->flags & ATA_QCFLAG_SENSE_VALID)) { - /* FIXME: not quite right; we don't want the - * translation of taskfile registers into a - * sense descriptors, since that's only - * correct for ATA, not ATAPI - */ + if (!(qc->flags & ATA_QCFLAG_SENSE_VALID)) ata_gen_passthru_sense(qc); - } /* SCSI EH automatically locks door if sdev->locked is * set. Sometimes door lock request continues to @@ -3200,8 +3385,7 @@ static unsigned int ata_scsi_write_same_xlat(struct ata_queued_cmd *qc) } scsi_16_lba_len(cdb, &block, &n_block); - if (!unmap || - (dev->horkage & ATA_HORKAGE_NOTRIM) || + if (!unmap || (dev->quirks & ATA_QUIRK_NOTRIM) || !ata_id_has_trim(dev->id)) { fp = 1; bp = 3; @@ -3271,7 +3455,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() @@ -3279,17 +3464,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]) { @@ -3357,11 +3546,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; } /** @@ -3693,12 +3883,11 @@ static int ata_mselect_control_spg0(struct ata_queued_cmd *qc, } /* - * Translate MODE SELECT control mode page, sub-pages f2h (ATA feature mode + * Translate MODE SELECT control mode page, sub-page f2h (ATA feature mode * page) into a SET FEATURES command. */ -static unsigned int ata_mselect_control_ata_feature(struct ata_queued_cmd *qc, - const u8 *buf, int len, - u16 *fp) +static int ata_mselect_control_ata_feature(struct ata_queued_cmd *qc, + const u8 *buf, int len, u16 *fp) { struct ata_device *dev = qc->dev; struct ata_taskfile *tf = &qc->tf; @@ -3716,17 +3905,27 @@ static unsigned int ata_mselect_control_ata_feature(struct ata_queued_cmd *qc, /* Check cdl_ctrl */ switch (buf[0] & 0x03) { case 0: - /* Disable CDL */ + /* Disable CDL if it is enabled */ + if (!(dev->flags & ATA_DFLAG_CDL_ENABLED)) + return 0; + ata_dev_dbg(dev, "Disabling CDL\n"); cdl_action = 0; dev->flags &= ~ATA_DFLAG_CDL_ENABLED; break; case 0x02: - /* Enable CDL T2A/T2B: NCQ priority must be disabled */ + /* + * Enable CDL if not already enabled. Since this is mutually + * exclusive with NCQ priority, allow this only if NCQ priority + * is disabled. + */ + if (dev->flags & ATA_DFLAG_CDL_ENABLED) + return 0; if (dev->flags & ATA_DFLAG_NCQ_PRIO_ENABLED) { ata_dev_err(dev, "NCQ priority must be disabled to enable CDL\n"); return -EINVAL; } + ata_dev_dbg(dev, "Enabling CDL\n"); cdl_action = 1; dev->flags |= ATA_DFLAG_CDL_ENABLED; break; @@ -4221,78 +4420,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: @@ -4320,10 +4467,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 */ @@ -4577,16 +4721,15 @@ static void ata_scsi_handle_link_detach(struct ata_link *link) ata_for_each_dev(dev, link, ALL) { unsigned long flags; - if (!(dev->flags & ATA_DFLAG_DETACHED)) + spin_lock_irqsave(ap->lock, flags); + if (!(dev->flags & ATA_DFLAG_DETACHED)) { + spin_unlock_irqrestore(ap->lock, flags); continue; + } - spin_lock_irqsave(ap->lock, flags); dev->flags &= ~ATA_DFLAG_DETACHED; spin_unlock_irqrestore(ap->lock, flags); - if (zpodd_dev_enabled(dev)) - zpodd_exit(dev); - ata_scsi_remove_dev(dev); } } |