diff options
Diffstat (limited to 'drivers/ata/libata-scsi.c')
| -rw-r--r-- | drivers/ata/libata-scsi.c | 227 |
1 files changed, 117 insertions, 110 deletions
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 3b65df914ebb..f44612e269a4 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -1649,12 +1649,16 @@ nothing_to_do: return 1; } -static void ata_qc_done(struct ata_queued_cmd *qc) +static void ata_scsi_qc_done(struct ata_queued_cmd *qc, bool set_result, + u32 scmd_result) { struct scsi_cmnd *cmd = qc->scsicmd; void (*done)(struct scsi_cmnd *) = qc->scsidone; ata_qc_free(qc); + + if (set_result) + cmd->result = scmd_result; done(cmd); } @@ -1685,24 +1689,19 @@ void ata_scsi_deferred_qc_work(struct work_struct *work) 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. + * and simply requeue it by completing it with DID_REQUEUE. */ - if (!qc) - return; - - scmd = qc->scsicmd; - ap->deferred_qc = NULL; - cancel_work(&ap->deferred_qc_work); - ata_qc_free(qc); - scmd->result = (DID_SOFT_ERROR << 16); - scsi_done(scmd); + if (qc) { + ap->deferred_qc = NULL; + cancel_work(&ap->deferred_qc_work); + ata_scsi_qc_done(qc, true, DID_REQUEUE << 16); + } } static void ata_scsi_schedule_deferred_qc(struct ata_port *ap) @@ -1758,7 +1757,7 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc) ata_scsi_set_sense_information(qc); } - ata_qc_done(qc); + ata_scsi_qc_done(qc, false, 0); ata_scsi_schedule_deferred_qc(ap); } @@ -2917,17 +2916,15 @@ static void atapi_qc_complete(struct ata_queued_cmd *qc) if (qc->cdb[0] == ALLOW_MEDIUM_REMOVAL && qc->dev->sdev) qc->dev->sdev->locked = 0; - qc->scsicmd->result = SAM_STAT_CHECK_CONDITION; - ata_qc_done(qc); + ata_scsi_qc_done(qc, true, SAM_STAT_CHECK_CONDITION); return; } /* successful completion path */ if (cmd->cmnd[0] == INQUIRY && (cmd->cmnd[1] & 0x03) == 0) atapi_fixup_inquiry(cmd); - cmd->result = SAM_STAT_GOOD; - ata_qc_done(qc); + ata_scsi_qc_done(qc, true, SAM_STAT_GOOD); } /** * atapi_xlat - Initialize PACKET taskfile @@ -3576,28 +3573,13 @@ invalid_opcode: return 1; } -/** - * ata_scsiop_maint_in - Simulate a subset of MAINTENANCE_IN - * @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() - * - * LOCKING: - * spin_lock_irqsave(host lock) - */ -static unsigned int ata_scsiop_maint_in(struct ata_device *dev, - struct scsi_cmnd *cmd, u8 *rbuf) +static unsigned int ata_scsi_report_supported_opcodes(struct ata_device *dev, + struct scsi_cmnd *cmd, + u8 *rbuf) { u8 *cdb = cmd->cmnd; u8 supported = 0, cdlp = 0, rwcdlp = 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]); ata_scsi_set_invalid_field(dev, cmd, 2, 0xff); @@ -3678,6 +3660,32 @@ static unsigned int ata_scsiop_maint_in(struct ata_device *dev, } /** + * ata_scsiop_maint_in - Simulate a subset of MAINTENANCE_IN + * @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() + * + * LOCKING: + * spin_lock_irqsave(host lock) + */ +static unsigned int ata_scsiop_maint_in(struct ata_device *dev, + struct scsi_cmnd *cmd, u8 *rbuf) +{ + u8 *cdb = cmd->cmnd; + u8 service_action = cdb[1] & 0x1f; + + switch (service_action) { + case MI_REPORT_SUPPORTED_OPERATION_CODES: + return ata_scsi_report_supported_opcodes(dev, cmd, rbuf); + default: + ata_scsi_set_invalid_field(dev, cmd, 1, 0xff); + return 0; + } +} + +/** * ata_scsi_report_zones_complete - convert ATA output * @qc: command structure returning the data * @@ -4424,6 +4432,79 @@ static inline ata_xlat_func_t ata_get_xlat_func(struct ata_device *dev, u8 cmd) return NULL; } +/** + * ata_scsi_simulate - simulate SCSI command on ATA device + * @dev: the target device + * @cmd: SCSI command being sent to device. + * + * Interprets and directly executes a select list of SCSI commands + * that can be handled internally. + * + * LOCKING: + * spin_lock_irqsave(host lock) + */ +static void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd) +{ + const u8 *scsicmd = cmd->cmnd; + u8 tmp8; + + switch (scsicmd[0]) { + case INQUIRY: + ata_scsi_rbuf_fill(dev, cmd, ata_scsiop_inquiry); + break; + + case MODE_SENSE: + case MODE_SENSE_10: + ata_scsi_rbuf_fill(dev, cmd, ata_scsiop_mode_sense); + break; + + case READ_CAPACITY: + case SERVICE_ACTION_IN_16: + ata_scsi_rbuf_fill(dev, cmd, ata_scsiop_read_cap); + break; + + case REPORT_LUNS: + ata_scsi_rbuf_fill(dev, cmd, ata_scsiop_report_luns); + break; + + case REQUEST_SENSE: + ata_scsi_set_sense(dev, cmd, 0, 0, 0); + break; + + /* if we reach this, then writeback caching is disabled, + * turning this into a no-op. + */ + case SYNCHRONIZE_CACHE: + case SYNCHRONIZE_CACHE_16: + fallthrough; + + /* no-op's, complete with success */ + case REZERO_UNIT: + case SEEK_6: + case SEEK_10: + case TEST_UNIT_READY: + break; + + case SEND_DIAGNOSTIC: + tmp8 = scsicmd[1] & ~(1 << 3); + if (tmp8 != 0x4 || scsicmd[3] || scsicmd[4]) + ata_scsi_set_invalid_field(dev, cmd, 1, 0xff); + break; + + case MAINTENANCE_IN: + ata_scsi_rbuf_fill(dev, cmd, ata_scsiop_maint_in); + break; + + /* all other commands */ + default: + ata_scsi_set_sense(dev, cmd, ILLEGAL_REQUEST, 0x20, 0x0); + /* "Invalid command operation code" */ + break; + } + + scsi_done(cmd); +} + enum scsi_qc_status __ata_scsi_queuecmd(struct scsi_cmnd *scmd, struct ata_device *dev) { @@ -4526,80 +4607,6 @@ enum scsi_qc_status ata_scsi_queuecmd(struct Scsi_Host *shost, } EXPORT_SYMBOL_GPL(ata_scsi_queuecmd); -/** - * ata_scsi_simulate - simulate SCSI command on ATA device - * @dev: the target device - * @cmd: SCSI command being sent to device. - * - * Interprets and directly executes a select list of SCSI commands - * that can be handled internally. - * - * LOCKING: - * spin_lock_irqsave(host lock) - */ - -void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd) -{ - const u8 *scsicmd = cmd->cmnd; - u8 tmp8; - - switch(scsicmd[0]) { - case INQUIRY: - ata_scsi_rbuf_fill(dev, cmd, ata_scsiop_inquiry); - break; - - case MODE_SENSE: - case MODE_SENSE_10: - ata_scsi_rbuf_fill(dev, cmd, ata_scsiop_mode_sense); - break; - - case READ_CAPACITY: - case SERVICE_ACTION_IN_16: - ata_scsi_rbuf_fill(dev, cmd, ata_scsiop_read_cap); - break; - - case REPORT_LUNS: - ata_scsi_rbuf_fill(dev, cmd, ata_scsiop_report_luns); - break; - - case REQUEST_SENSE: - ata_scsi_set_sense(dev, cmd, 0, 0, 0); - break; - - /* if we reach this, then writeback caching is disabled, - * turning this into a no-op. - */ - case SYNCHRONIZE_CACHE: - case SYNCHRONIZE_CACHE_16: - fallthrough; - - /* no-op's, complete with success */ - case REZERO_UNIT: - case SEEK_6: - case SEEK_10: - case TEST_UNIT_READY: - break; - - case SEND_DIAGNOSTIC: - tmp8 = scsicmd[1] & ~(1 << 3); - if (tmp8 != 0x4 || scsicmd[3] || scsicmd[4]) - ata_scsi_set_invalid_field(dev, cmd, 1, 0xff); - break; - - case MAINTENANCE_IN: - ata_scsi_rbuf_fill(dev, cmd, ata_scsiop_maint_in); - break; - - /* all other commands */ - default: - ata_scsi_set_sense(dev, cmd, ILLEGAL_REQUEST, 0x20, 0x0); - /* "Invalid command operation code" */ - break; - } - - scsi_done(cmd); -} - int ata_scsi_add_hosts(struct ata_host *host, const struct scsi_host_template *sht) { int i, rc; @@ -4617,7 +4624,7 @@ int ata_scsi_add_hosts(struct ata_host *host, const struct scsi_host_template *s *(struct ata_port **)&shost->hostdata[0] = ap; ap->scsi_host = shost; - shost->transportt = ata_scsi_transport_template; + shost->transportt = &ata_scsi_transportt; shost->unique_id = ap->print_id; shost->max_id = 16; shost->max_lun = 1; |
