mirror of
https://github.com/SCST-project/scst.git
synced 2026-05-21 20:51:27 +00:00
scst: Parse ATA pass-through CDBs
Signed-off-by: Bart Van Assche <bvanassche@acm.org> git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@4326 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
@@ -1156,17 +1156,9 @@ static bool vdisk_parse_offset(struct vdisk_cmd_params *p, struct scst_cmd *cmd)
|
||||
TRACE_ENTRY();
|
||||
|
||||
if (unlikely(!(cmd->op_flags & SCST_INFO_VALID))) {
|
||||
/*
|
||||
* Let's ignore reporting T10/04-262r7 16-byte and 12-byte ATA
|
||||
* pass-thru commands to not pollute logs (udev(?) checks them
|
||||
* for some reason). If somebody has their description, please,
|
||||
* update scst_scsi_op_table.
|
||||
*/
|
||||
if ((cmd->cdb[0] != 0x85) && (cmd->cdb[0] != 0xa1))
|
||||
PRINT_ERROR("Unknown opcode 0x%02x", cmd->cdb[0]);
|
||||
else
|
||||
TRACE(TRACE_MINOR, "Unknown opcode 0x%02x", cmd->cdb[0]);
|
||||
scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_invalid_opcode));
|
||||
TRACE(TRACE_MINOR, "Unknown opcode 0x%02x", cmd->cdb[0]);
|
||||
scst_set_cmd_error(cmd,
|
||||
SCST_LOAD_SENSE(scst_sense_invalid_opcode));
|
||||
res = false;
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -138,6 +138,8 @@ static int get_cdb_info_write_same10(struct scst_cmd *cmd,
|
||||
const struct scst_sdbops *sdbops);
|
||||
static int get_cdb_info_write_same16(struct scst_cmd *cmd,
|
||||
const struct scst_sdbops *sdbops);
|
||||
static int get_cdb_info_apt(struct scst_cmd *cmd,
|
||||
const struct scst_sdbops *sdbops);
|
||||
|
||||
/*
|
||||
+=====================================-============-======-
|
||||
@@ -197,6 +199,7 @@ static int scst_scsi_op_list[256];
|
||||
|
||||
#define FLAG_NONE 0
|
||||
|
||||
/* See also http://www.t10.org/lists/op-num.htm */
|
||||
static const struct scst_sdbops scst_scsi_op_table[] = {
|
||||
/*
|
||||
* +-------------------> TYPE_IS_DISK (0)
|
||||
@@ -900,6 +903,12 @@ static const struct scst_sdbops scst_scsi_op_table[] = {
|
||||
.info_op_flags = FLAG_NONE,
|
||||
.info_len_off = 10, .info_len_len = 4,
|
||||
.get_cdb_info = get_cdb_info_len_4},
|
||||
{.ops = 0x85, .devkey = "O O O ",
|
||||
.info_op_name = "ATA PASS-THROUGH(16)",
|
||||
.info_data_direction = SCST_DATA_NONE,
|
||||
.info_op_flags = FLAG_NONE,
|
||||
.info_lba_off = 7, .info_lba_len = 6,
|
||||
.get_cdb_info = get_cdb_info_apt},
|
||||
{.ops = 0x86, .devkey = "OOOOOOOOOO ",
|
||||
.info_op_name = "ACCESS CONTROL IN",
|
||||
.info_data_direction = SCST_DATA_NONE,
|
||||
@@ -1016,6 +1025,12 @@ static const struct scst_sdbops scst_scsi_op_table[] = {
|
||||
SCST_WRITE_EXCL_ALLOWED|SCST_EXCL_ACCESS_ALLOWED,
|
||||
.info_len_off = 6, .info_len_len = 4,
|
||||
.get_cdb_info = get_cdb_info_len_4},
|
||||
{.ops = 0xA1, .devkey = "O O O ",
|
||||
.info_op_name = "ATA PASS-THROUGH(12)",
|
||||
.info_data_direction = SCST_DATA_NONE,
|
||||
.info_op_flags = FLAG_NONE,
|
||||
.info_lba_off = 5, .info_lba_len = 3,
|
||||
.get_cdb_info = get_cdb_info_apt},
|
||||
{.ops = 0xA1, .devkey = " O ",
|
||||
.info_op_name = "BLANK",
|
||||
.info_data_direction = SCST_DATA_NONE,
|
||||
@@ -6300,6 +6315,100 @@ static int get_cdb_info_write_same16(struct scst_cmd *cmd,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* scst_get_cdb_info_apt() - Parse ATA PASS-THROUGH CDB.
|
||||
*
|
||||
* Parse ATA PASS-THROUGH(12) and ATA PASS-THROUGH(16). See also SAT-3 for a
|
||||
* detailed description of these commands.
|
||||
*/
|
||||
static int get_cdb_info_apt(struct scst_cmd *cmd,
|
||||
const struct scst_sdbops *sdbops)
|
||||
{
|
||||
const u8 *const cdb = cmd->cdb;
|
||||
const u8 op = cdb[0];
|
||||
const u8 extend = cdb[1] & 1;
|
||||
const u8 multiple = cdb[1] >> 5;
|
||||
const u8 protocol = (cdb[1] >> 1) & 0xf;
|
||||
const u8 t_type = (cdb[2] >> 4) & 1;
|
||||
const u8 t_dir = (cdb[2] >> 3) & 1;
|
||||
const u8 byte_block = (cdb[2] >> 2) & 1;
|
||||
const u8 t_length = cdb[2] & 3;
|
||||
int bufflen = 0;
|
||||
|
||||
/*
|
||||
* If the PROTOCOL field contains Fh (i.e., Return Response
|
||||
* Information), then the SATL shall ignore all fields in the CDB
|
||||
* except for the PROTOCOL field.
|
||||
*/
|
||||
if (protocol == 0xf)
|
||||
goto out;
|
||||
|
||||
switch (op) {
|
||||
case ATA_12:
|
||||
switch (t_length) {
|
||||
case 0:
|
||||
bufflen = 0;
|
||||
break;
|
||||
case 1:
|
||||
bufflen = cdb[3];
|
||||
break;
|
||||
case 2:
|
||||
bufflen = cdb[4];
|
||||
break;
|
||||
case 3:
|
||||
/*
|
||||
* Not yet implemented: "The transfer length is an
|
||||
* unsigned integer specified in the TPSIU (see
|
||||
* 3.1.97)."
|
||||
*/
|
||||
WARN_ON(true);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case ATA_16:
|
||||
switch (t_length) {
|
||||
case 0:
|
||||
bufflen = 0;
|
||||
break;
|
||||
case 1:
|
||||
bufflen = extend ? get_unaligned_be16(&cdb[3]) : cdb[4];
|
||||
break;
|
||||
case 2:
|
||||
bufflen = extend ? get_unaligned_be16(&cdb[5]) : cdb[6];
|
||||
break;
|
||||
case 3:
|
||||
WARN_ON(true);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* See also "Table 133 - Mapping of BYTE_BLOCK, T_TYPE, and T_LENGTH" */
|
||||
cmd->cdb_len = SCST_GET_CDB_LEN(op);
|
||||
if (t_length != 0 && byte_block != 0) {
|
||||
/*
|
||||
* "The number of ATA logical sector size (see 3.1.16) blocks
|
||||
* to be transferred"
|
||||
*/
|
||||
bufflen *= t_type ? cmd->dev->block_size : 512;
|
||||
}
|
||||
/*
|
||||
* If the T_DIR bit is set to zero, then the SATL shall transfer data
|
||||
* from the application client to the ATA device. If the T_DIR bit is
|
||||
* set to one, then the SATL shall transfer data from the ATA device
|
||||
* to the application client. The SATL shall ignore the T_DIR bit if
|
||||
* the T_LENGTH field is set to zero.
|
||||
*/
|
||||
cmd->data_direction = (t_length == 0 ? SCST_DATA_NONE : t_dir ?
|
||||
SCST_DATA_READ : SCST_DATA_WRITE);
|
||||
cmd->lba = 0;
|
||||
cmd->bufflen = bufflen << multiple;
|
||||
cmd->data_len = cmd->bufflen;
|
||||
out:
|
||||
cmd->op_flags = SCST_INFO_VALID;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* scst_get_cdb_info() - fill various info about the command's CDB
|
||||
*
|
||||
|
||||
@@ -636,17 +636,7 @@ static int scst_parse_cmd(struct scst_cmd *cmd)
|
||||
goto out_done;
|
||||
}
|
||||
#else
|
||||
/*
|
||||
* Let's ignore reporting T10/04-262r7 16-byte and 12-byte ATA
|
||||
* pass-thru commands to not pollute logs (udev(?) checks them
|
||||
* for some reason). If somebody has their description, please,
|
||||
* update scst_scsi_op_table.
|
||||
*/
|
||||
if ((cmd->cdb[0] != 0x85) && (cmd->cdb[0] != 0xa1))
|
||||
PRINT_ERROR("Refusing unknown opcode %x", cmd->cdb[0]);
|
||||
else
|
||||
TRACE(TRACE_MINOR, "Refusing unknown opcode %x",
|
||||
cmd->cdb[0]);
|
||||
PRINT_ERROR("Refusing unknown opcode %x", cmd->cdb[0]);
|
||||
scst_set_cmd_error(cmd,
|
||||
SCST_LOAD_SENSE(scst_sense_invalid_opcode));
|
||||
goto out_done;
|
||||
|
||||
Reference in New Issue
Block a user