Skip to content

Commit

Permalink
libata: Support for an ATA PASS-THROUGH(32) command.
Browse files Browse the repository at this point in the history
SAT-4(SCSI/ATA Translation) supports for an ata pass-thru(32).
This patch will allow to translate an ata pass-thru(32) SCSI cmd
to an ATA cmd.

Signed-off-by: Minwoo Im <dn3108@gmail.com>
Reviewed-by: Bart Van Assche <bart.vanassche@wdc.com>
Signed-off-by: Tejun Heo <tj@kernel.org>
  • Loading branch information
Minwoo Im authored and Tejun Heo committed Jun 27, 2017
1 parent 0ce968f commit b1ffbf8
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 6 deletions.
2 changes: 1 addition & 1 deletion drivers/ata/libata-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -2661,7 +2661,7 @@ int ata_dev_configure(struct ata_device *dev)
ata_dev_config_sense_reporting(dev);
ata_dev_config_zac(dev);
ata_dev_config_trusted(dev);
dev->cdb_len = 16;
dev->cdb_len = 32;
}

/* ATAPI-specific feature tests */
Expand Down
72 changes: 67 additions & 5 deletions drivers/ata/libata-scsi.c
Original file line number Diff line number Diff line change
Expand Up @@ -3126,7 +3126,7 @@ ata_scsi_map_proto(u8 byte1)
* ata_scsi_pass_thru - convert ATA pass-thru CDB to taskfile
* @qc: command structure to be initialized
*
* Handles either 12 or 16-byte versions of the CDB.
* Handles either 12, 16, or 32-byte versions of the CDB.
*
* RETURNS:
* Zero on success, non-zero on failure.
Expand All @@ -3138,13 +3138,19 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc)
struct ata_device *dev = qc->dev;
const u8 *cdb = scmd->cmnd;
u16 fp;
u16 cdb_offset = 0;

if ((tf->protocol = ata_scsi_map_proto(cdb[1])) == ATA_PROT_UNKNOWN) {
/* 7Fh variable length cmd means a ata pass-thru(32) */
if (cdb[0] == VARIABLE_LENGTH_CMD)
cdb_offset = 9;

tf->protocol = ata_scsi_map_proto(cdb[1 + cdb_offset]);
if (tf->protocol == ATA_PROT_UNKNOWN) {
fp = 1;
goto invalid_fld;
}

if (ata_is_ncq(tf->protocol) && (cdb[2] & 0x3) == 0)
if (ata_is_ncq(tf->protocol) && (cdb[2 + cdb_offset] & 0x3) == 0)
tf->protocol = ATA_PROT_NCQ_NODATA;

/* enable LBA */
Expand Down Expand Up @@ -3180,7 +3186,7 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc)
tf->lbah = cdb[12];
tf->device = cdb[13];
tf->command = cdb[14];
} else {
} else if (cdb[0] == ATA_12) {
/*
* 12-byte CDB - incapable of extended commands.
*/
Expand All @@ -3193,6 +3199,30 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc)
tf->lbah = cdb[7];
tf->device = cdb[8];
tf->command = cdb[9];
} else {
/*
* 32-byte CDB - may contain extended command fields.
*
* If that is the case, copy the upper byte register values.
*/
if (cdb[10] & 0x01) {
tf->hob_feature = cdb[20];
tf->hob_nsect = cdb[22];
tf->hob_lbal = cdb[16];
tf->hob_lbam = cdb[15];
tf->hob_lbah = cdb[14];
tf->flags |= ATA_TFLAG_LBA48;
} else
tf->flags &= ~ATA_TFLAG_LBA48;

tf->feature = cdb[21];
tf->nsect = cdb[23];
tf->lbal = cdb[19];
tf->lbam = cdb[18];
tf->lbah = cdb[17];
tf->device = cdb[24];
tf->command = cdb[25];
tf->auxiliary = get_unaligned_be32(&cdb[28]);
}

/* For NCQ commands copy the tag value */
Expand Down Expand Up @@ -4137,6 +4167,35 @@ static unsigned int ata_scsi_security_inout_xlat(struct ata_queued_cmd *qc)
return 0;
}

/**
* ata_scsi_var_len_cdb_xlat - SATL variable length CDB to Handler
* @qc: Command to be translated
*
* Translate a SCSI variable length CDB to specified commands.
* It checks a service action value in CDB to call corresponding handler.
*
* RETURNS:
* Zero on success, non-zero on failure
*
*/
static unsigned int ata_scsi_var_len_cdb_xlat(struct ata_queued_cmd *qc)
{
struct scsi_cmnd *scmd = qc->scsicmd;
const u8 *cdb = scmd->cmnd;
const u16 sa = get_unaligned_be16(&cdb[8]);

/*
* if service action represents a ata pass-thru(32) command,
* then pass it to ata_scsi_pass_thru handler.
*/
if (sa == ATA_32)
return ata_scsi_pass_thru(qc);

unspprt_sa:
/* unsupported service action */
return 1;
}

/**
* ata_get_xlat_func - check if SCSI to ATA translation is possible
* @dev: ATA device
Expand Down Expand Up @@ -4177,6 +4236,9 @@ static inline ata_xlat_func_t ata_get_xlat_func(struct ata_device *dev, u8 cmd)
case ATA_16:
return ata_scsi_pass_thru;

case VARIABLE_LENGTH_CMD:
return ata_scsi_var_len_cdb_xlat;

case MODE_SELECT:
case MODE_SELECT_10:
return ata_scsi_mode_select_xlat;
Expand Down Expand Up @@ -4461,7 +4523,7 @@ int ata_scsi_add_hosts(struct ata_host *host, struct scsi_host_template *sht)
shost->max_id = 16;
shost->max_lun = 1;
shost->max_channel = 1;
shost->max_cmd_len = 16;
shost->max_cmd_len = 32;

/* Schedule policy is determined by ->qc_defer()
* callback and it needs to see every deferred qc.
Expand Down
1 change: 1 addition & 0 deletions include/scsi/scsi_proto.h
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@
#define VERIFY_32 0x0a
#define WRITE_32 0x0b
#define WRITE_SAME_32 0x0d
#define ATA_32 0x1ff0

/* Values for T10/04-262r7 */
#define ATA_16 0x85 /* 16-byte pass-thru */
Expand Down

0 comments on commit b1ffbf8

Please sign in to comment.