[libata scsi] MODE SELECT, strengthen mode sense

- move default mode pages to the front of libata-scsi.c
    so various functions can access them
  - partial annotation of these pages, point out divergence
    from sat-r06
  - replace various mode page magic numbers with defines
  - strengthen MODE SENSE command decoding: handle DBD
    bit in cdb, yield block descriptor (per sat-r06) and
    handle mode sub pages

Signed-off-by: Douglas Gilbert <dougg@torque.net>
Signed-off-by: Jeff Garzik <jgarzik@pobox.com>
This commit is contained in:
Douglas Gilbert 2005-10-28 15:58:28 -04:00 committed by Jeff Garzik
parent a21a84a375
commit 00ac37f508

View file

@ -51,6 +51,45 @@ typedef unsigned int (*ata_xlat_func_t)(struct ata_queued_cmd *qc, const u8 *scs
static struct ata_device *
ata_scsi_find_dev(struct ata_port *ap, const struct scsi_device *scsidev);
#define RW_RECOVERY_MPAGE 0x1
#define RW_RECOVERY_MPAGE_LEN 12
#define CACHE_MPAGE 0x8
#define CACHE_MPAGE_LEN 20
#define CONTROL_MPAGE 0xa
#define CONTROL_MPAGE_LEN 12
#define ALL_MPAGES 0x3f
#define ALL_SUB_MPAGES 0xff
static const u8 def_rw_recovery_mpage[] = {
RW_RECOVERY_MPAGE,
RW_RECOVERY_MPAGE_LEN - 2,
(1 << 7) | /* AWRE, sat-r06 say it shall be 0 */
(1 << 6), /* ARRE (auto read reallocation) */
0, /* read retry count */
0, 0, 0, 0,
0, /* write retry count */
0, 0, 0
};
static const u8 def_cache_mpage[CACHE_MPAGE_LEN] = {
CACHE_MPAGE,
CACHE_MPAGE_LEN - 2,
0, /* contains WCE, needs to be 0 for logic */
0, 0, 0, 0, 0, 0, 0, 0, 0,
0, /* contains DRA, needs to be 0 for logic */
0, 0, 0, 0, 0, 0, 0
};
static const u8 def_control_mpage[CONTROL_MPAGE_LEN] = {
CONTROL_MPAGE,
CONTROL_MPAGE_LEN - 2,
2, /* DSENSE=0, GLTSD=1 */
0, /* [QAM+QERR may be 1, see 05-359r1] */
0, 0, 0, 0, 0xff, 0xff,
0, 30 /* extended self test time, see 05-359r1 */
};
static void ata_scsi_invalid_field(struct scsi_cmnd *cmd,
void (*done)(struct scsi_cmnd *))
@ -1583,13 +1622,9 @@ static void ata_msense_push(u8 **ptr_io, const u8 *last,
static unsigned int ata_msense_caching(u16 *id, u8 **ptr_io,
const u8 *last)
{
u8 page[] = {
0x8, /* page code */
0x12, /* page length */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10 zeroes */
0, 0, 0, 0, 0, 0, 0, 0 /* 8 zeroes */
};
u8 page[CACHE_MPAGE_LEN];
memcpy(page, def_cache_mpage, sizeof(page));
if (ata_id_wcache_enabled(id))
page[2] |= (1 << 2); /* write cache enable */
if (!ata_id_rahead_enabled(id))
@ -1613,15 +1648,9 @@ static unsigned int ata_msense_caching(u16 *id, u8 **ptr_io,
static unsigned int ata_msense_ctl_mode(u8 **ptr_io, const u8 *last)
{
const u8 page[] = {0xa, 0xa, 6, 0, 0, 0, 0, 0, 0xff, 0xff, 0, 30};
/* byte 2: set the descriptor format sense data bit (bit 2)
* since we need to support returning this format for SAT
* commands and any SCSI commands against a 48b LBA device.
*/
ata_msense_push(ptr_io, last, page, sizeof(page));
return sizeof(page);
ata_msense_push(ptr_io, last, def_control_mpage,
sizeof(def_control_mpage));
return sizeof(def_control_mpage);
}
/**
@ -1638,15 +1667,10 @@ static unsigned int ata_msense_ctl_mode(u8 **ptr_io, const u8 *last)
static unsigned int ata_msense_rw_recovery(u8 **ptr_io, const u8 *last)
{
const u8 page[] = {
0x1, /* page code */
0xa, /* page length */
(1 << 7) | (1 << 6), /* note auto r/w reallocation */
0, 0, 0, 0, 0, 0, 0, 0, 0 /* 9 zeroes */
};
ata_msense_push(ptr_io, last, page, sizeof(page));
return sizeof(page);
ata_msense_push(ptr_io, last, def_rw_recovery_mpage,
sizeof(def_rw_recovery_mpage));
return sizeof(def_rw_recovery_mpage);
}
/**
@ -1655,7 +1679,9 @@ static unsigned int ata_msense_rw_recovery(u8 **ptr_io, const u8 *last)
* @rbuf: Response buffer, to which simulated SCSI cmd output is sent.
* @buflen: Response buffer length.
*
* Simulate MODE SENSE commands.
* Simulate MODE SENSE commands. Assume this is invoked for direct
* access devices (e.g. disks) only. There should be no block
* descriptor for other device types.
*
* LOCKING:
* spin_lock_irqsave(host_set lock)
@ -1665,15 +1691,22 @@ unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf,
unsigned int buflen)
{
u8 *scsicmd = args->cmd->cmnd, *p, *last;
unsigned int page_control, six_byte, output_len;
const u8 sat_blk_desc[] = {
0, 0, 0, 0, /* number of blocks: sat unspecified */
0,
0, 0x2, 0x0 /* block length: 512 bytes */
};
u8 pg, spg;
unsigned int ebd, page_control, six_byte, output_len, alloc_len, minlen;
VPRINTK("ENTER\n");
six_byte = (scsicmd[0] == MODE_SENSE);
/* we only support saved and current values (which we treat
* in the same manner)
ebd = !(scsicmd[1] & 0x8); /* dbd bit inverted == edb */
/*
* LLBA bit in msense(10) ignored (compliant)
*/
page_control = scsicmd[2] >> 6;
switch (page_control) {
case 0: /* current */
@ -1686,29 +1719,42 @@ unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf,
goto invalid_fld;
}
if (six_byte)
output_len = 4;
else
output_len = 8;
if (six_byte) {
output_len = 4 + (ebd ? 8 : 0);
alloc_len = scsicmd[4];
} else {
output_len = 8 + (ebd ? 8 : 0);
alloc_len = (scsicmd[7] << 8) + scsicmd[8];
}
minlen = (alloc_len < buflen) ? alloc_len : buflen;
p = rbuf + output_len;
last = rbuf + buflen - 1;
last = rbuf + minlen - 1;
switch(scsicmd[2] & 0x3f) {
case 0x01: /* r/w error recovery */
pg = scsicmd[2] & 0x3f;
spg = scsicmd[3];
/*
* No mode subpages supported (yet) but asking for _all_
* subpages may be valid
*/
if (spg && (spg != ALL_SUB_MPAGES))
goto invalid_fld;
switch(pg) {
case RW_RECOVERY_MPAGE:
output_len += ata_msense_rw_recovery(&p, last);
break;
case 0x08: /* caching */
case CACHE_MPAGE:
output_len += ata_msense_caching(args->id, &p, last);
break;
case 0x0a: { /* control mode */
case CONTROL_MPAGE: {
output_len += ata_msense_ctl_mode(&p, last);
break;
}
case 0x3f: /* all pages */
case ALL_MPAGES:
output_len += ata_msense_rw_recovery(&p, last);
output_len += ata_msense_caching(args->id, &p, last);
output_len += ata_msense_ctl_mode(&p, last);
@ -1718,15 +1764,31 @@ unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf,
goto invalid_fld;
}
if (minlen < 1)
return 0;
if (six_byte) {
output_len--;
rbuf[0] = output_len;
if (ebd) {
if (minlen > 3)
rbuf[3] = sizeof(sat_blk_desc);
if (minlen > 11)
memcpy(rbuf + 4, sat_blk_desc,
sizeof(sat_blk_desc));
}
} else {
output_len -= 2;
rbuf[0] = output_len >> 8;
rbuf[1] = output_len;
if (minlen > 1)
rbuf[1] = output_len;
if (ebd) {
if (minlen > 7)
rbuf[7] = sizeof(sat_blk_desc);
if (minlen > 15)
memcpy(rbuf + 8, sat_blk_desc,
sizeof(sat_blk_desc));
}
}
return 0;
invalid_fld:
@ -2156,7 +2218,7 @@ ata_scsi_map_proto(u8 byte1)
* Zero on success, non-zero on failure.
*/
static unsigned int
ata_scsi_pass_thru(struct ata_queued_cmd *qc, u8 *scsicmd)
ata_scsi_pass_thru(struct ata_queued_cmd *qc, const u8 *scsicmd)
{
struct ata_taskfile *tf = &(qc->tf);
struct scsi_cmnd *cmd = qc->scsicmd;