Skip to content

Commit 673b2fe

Browse files
damien-lemoalmartinkpetersen
authored andcommitted
scsi: ata: libata-scsi: Add support for CDL pages mode sense
Modify ata_scsiop_mode_sense() and ata_msense_control() to support mode sense access to the T2A and T2B sub-pages of the control mode page. ata_msense_control() is modified to support sub-pages. The T2A sub-page is generated using the read descriptors of the command duration limits log page 18h. The T2B sub-page is generated using the write descriptors of the same log page. With the addition of these sub-pages, getting all sub-pages of the control mode page is also supported by increasing the value of ATA_SCSI_RBUF_SIZE from 576B up to 2048B to ensure that all sub-pages fit in the fill buffer. Signed-off-by: Damien Le Moal <[email protected]> Reviewed-by: Hannes Reinecke <[email protected]> Reviewed-by: Christoph Hellwig <[email protected]> Co-developed-by: Niklas Cassel <[email protected]> Signed-off-by: Niklas Cassel <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Martin K. Petersen <[email protected]>
1 parent 0de5580 commit 673b2fe

File tree

1 file changed

+128
-22
lines changed

1 file changed

+128
-22
lines changed

drivers/ata/libata-scsi.c

Lines changed: 128 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
#include "libata.h"
3838
#include "libata-transport.h"
3939

40-
#define ATA_SCSI_RBUF_SIZE 576
40+
#define ATA_SCSI_RBUF_SIZE 2048
4141

4242
static DEFINE_SPINLOCK(ata_scsi_rbuf_lock);
4343
static u8 ata_scsi_rbuf[ATA_SCSI_RBUF_SIZE];
@@ -55,6 +55,9 @@ static struct ata_device *__ata_scsi_find_dev(struct ata_port *ap,
5555
#define CONTROL_MPAGE_LEN 12
5656
#define ALL_MPAGES 0x3f
5757
#define ALL_SUB_MPAGES 0xff
58+
#define CDL_T2A_SUB_MPAGE 0x07
59+
#define CDL_T2B_SUB_MPAGE 0x08
60+
#define CDL_T2_SUB_MPAGE_LEN 232
5861

5962
static const u8 def_rw_recovery_mpage[RW_RECOVERY_MPAGE_LEN] = {
6063
RW_RECOVERY_MPAGE,
@@ -2196,10 +2199,98 @@ static unsigned int ata_msense_caching(u16 *id, u8 *buf, bool changeable)
21962199
return sizeof(def_cache_mpage);
21972200
}
21982201

2202+
/*
2203+
* Simulate MODE SENSE control mode page, sub-page 0.
2204+
*/
2205+
static unsigned int ata_msense_control_spg0(struct ata_device *dev, u8 *buf,
2206+
bool changeable)
2207+
{
2208+
modecpy(buf, def_control_mpage,
2209+
sizeof(def_control_mpage), changeable);
2210+
if (changeable) {
2211+
/* ata_mselect_control() */
2212+
buf[2] |= (1 << 2);
2213+
} else {
2214+
bool d_sense = (dev->flags & ATA_DFLAG_D_SENSE);
2215+
2216+
/* descriptor format sense data */
2217+
buf[2] |= (d_sense << 2);
2218+
}
2219+
2220+
return sizeof(def_control_mpage);
2221+
}
2222+
2223+
/*
2224+
* Translate an ATA duration limit in microseconds to a SCSI duration limit
2225+
* using the t2cdlunits 0xa (10ms). Since the SCSI duration limits are 2-bytes
2226+
* only, take care of overflows.
2227+
*/
2228+
static inline u16 ata_xlat_cdl_limit(u8 *buf)
2229+
{
2230+
u32 limit = get_unaligned_le32(buf);
2231+
2232+
return min_t(u32, limit / 10000, 65535);
2233+
}
2234+
2235+
/*
2236+
* Simulate MODE SENSE control mode page, sub-pages 07h and 08h
2237+
* (command duration limits T2A and T2B mode pages).
2238+
*/
2239+
static unsigned int ata_msense_control_spgt2(struct ata_device *dev, u8 *buf,
2240+
u8 spg)
2241+
{
2242+
u8 *b, *cdl = dev->cdl, *desc;
2243+
u32 policy;
2244+
int i;
2245+
2246+
/*
2247+
* Fill the subpage. The first four bytes of the T2A/T2B mode pages
2248+
* are a header. The PAGE LENGTH field is the size of the page
2249+
* excluding the header.
2250+
*/
2251+
buf[0] = CONTROL_MPAGE;
2252+
buf[1] = spg;
2253+
put_unaligned_be16(CDL_T2_SUB_MPAGE_LEN - 4, &buf[2]);
2254+
if (spg == CDL_T2A_SUB_MPAGE) {
2255+
/*
2256+
* Read descriptors map to the T2A page:
2257+
* set perf_vs_duration_guidleine.
2258+
*/
2259+
buf[7] = (cdl[0] & 0x03) << 4;
2260+
desc = cdl + 64;
2261+
} else {
2262+
/* Write descriptors map to the T2B page */
2263+
desc = cdl + 288;
2264+
}
2265+
2266+
/* Fill the T2 page descriptors */
2267+
b = &buf[8];
2268+
policy = get_unaligned_le32(&cdl[0]);
2269+
for (i = 0; i < 7; i++, b += 32, desc += 32) {
2270+
/* t2cdlunits: fixed to 10ms */
2271+
b[0] = 0x0a;
2272+
2273+
/* Max inactive time and its policy */
2274+
put_unaligned_be16(ata_xlat_cdl_limit(&desc[8]), &b[2]);
2275+
b[6] = ((policy >> 8) & 0x0f) << 4;
2276+
2277+
/* Max active time and its policy */
2278+
put_unaligned_be16(ata_xlat_cdl_limit(&desc[4]), &b[4]);
2279+
b[6] |= (policy >> 4) & 0x0f;
2280+
2281+
/* Command duration guideline and its policy */
2282+
put_unaligned_be16(ata_xlat_cdl_limit(&desc[16]), &b[10]);
2283+
b[14] = policy & 0x0f;
2284+
}
2285+
2286+
return CDL_T2_SUB_MPAGE_LEN;
2287+
}
2288+
21992289
/**
22002290
* ata_msense_control - Simulate MODE SENSE control mode page
22012291
* @dev: ATA device of interest
22022292
* @buf: output buffer
2293+
* @spg: sub-page code
22032294
* @changeable: whether changeable parameters are requested
22042295
*
22052296
* Generate a generic MODE SENSE control mode page.
@@ -2208,17 +2299,24 @@ static unsigned int ata_msense_caching(u16 *id, u8 *buf, bool changeable)
22082299
* None.
22092300
*/
22102301
static unsigned int ata_msense_control(struct ata_device *dev, u8 *buf,
2211-
bool changeable)
2302+
u8 spg, bool changeable)
22122303
{
2213-
modecpy(buf, def_control_mpage, sizeof(def_control_mpage), changeable);
2214-
if (changeable) {
2215-
buf[2] |= (1 << 2); /* ata_mselect_control() */
2216-
} else {
2217-
bool d_sense = (dev->flags & ATA_DFLAG_D_SENSE);
2218-
2219-
buf[2] |= (d_sense << 2); /* descriptor format sense data */
2304+
unsigned int n;
2305+
2306+
switch (spg) {
2307+
case 0:
2308+
return ata_msense_control_spg0(dev, buf, changeable);
2309+
case CDL_T2A_SUB_MPAGE:
2310+
case CDL_T2B_SUB_MPAGE:
2311+
return ata_msense_control_spgt2(dev, buf, spg);
2312+
case ALL_SUB_MPAGES:
2313+
n = ata_msense_control_spg0(dev, buf, changeable);
2314+
n += ata_msense_control_spgt2(dev, buf + n, CDL_T2A_SUB_MPAGE);
2315+
n += ata_msense_control_spgt2(dev, buf + n, CDL_T2A_SUB_MPAGE);
2316+
return n;
2317+
default:
2318+
return 0;
22202319
}
2221-
return sizeof(def_control_mpage);
22222320
}
22232321

22242322
/**
@@ -2291,13 +2389,24 @@ static unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf)
22912389

22922390
pg = scsicmd[2] & 0x3f;
22932391
spg = scsicmd[3];
2392+
22942393
/*
2295-
* No mode subpages supported (yet) but asking for _all_
2296-
* subpages may be valid
2394+
* Supported subpages: all subpages and sub-pages 07h and 08h of
2395+
* the control page.
22972396
*/
2298-
if (spg && (spg != ALL_SUB_MPAGES)) {
2299-
fp = 3;
2300-
goto invalid_fld;
2397+
if (spg) {
2398+
switch (spg) {
2399+
case ALL_SUB_MPAGES:
2400+
break;
2401+
case CDL_T2A_SUB_MPAGE:
2402+
case CDL_T2B_SUB_MPAGE:
2403+
if (dev->flags & ATA_DFLAG_CDL && pg == CONTROL_MPAGE)
2404+
break;
2405+
fallthrough;
2406+
default:
2407+
fp = 3;
2408+
goto invalid_fld;
2409+
}
23012410
}
23022411

23032412
switch(pg) {
@@ -2310,13 +2419,13 @@ static unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf)
23102419
break;
23112420

23122421
case CONTROL_MPAGE:
2313-
p += ata_msense_control(args->dev, p, page_control == 1);
2422+
p += ata_msense_control(args->dev, p, spg, page_control == 1);
23142423
break;
23152424

23162425
case ALL_MPAGES:
23172426
p += ata_msense_rw_recovery(p, page_control == 1);
23182427
p += ata_msense_caching(args->id, p, page_control == 1);
2319-
p += ata_msense_control(args->dev, p, page_control == 1);
2428+
p += ata_msense_control(args->dev, p, spg, page_control == 1);
23202429
break;
23212430

23222431
default: /* invalid page code */
@@ -2335,10 +2444,7 @@ static unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf)
23352444
memcpy(rbuf + 4, sat_blk_desc, sizeof(sat_blk_desc));
23362445
}
23372446
} else {
2338-
unsigned int output_len = p - rbuf - 2;
2339-
2340-
rbuf[0] = output_len >> 8;
2341-
rbuf[1] = output_len;
2447+
put_unaligned_be16(p - rbuf - 2, &rbuf[0]);
23422448
rbuf[3] |= dpofua;
23432449
if (ebd) {
23442450
rbuf[7] = sizeof(sat_blk_desc);
@@ -3637,7 +3743,7 @@ static int ata_mselect_control(struct ata_queued_cmd *qc,
36373743
/*
36383744
* Check that read-only bits are not modified.
36393745
*/
3640-
ata_msense_control(dev, mpage, false);
3746+
ata_msense_control_spg0(dev, mpage, false);
36413747
for (i = 0; i < CONTROL_MPAGE_LEN - 2; i++) {
36423748
if (i == 0)
36433749
continue;

0 commit comments

Comments
 (0)