1*44704f69SBart Van Assche /*
2*44704f69SBart Van Assche * Copyright (c) 2009-2022 Douglas Gilbert.
3*44704f69SBart Van Assche * All rights reserved.
4*44704f69SBart Van Assche * Use of this source code is governed by a BSD-style
5*44704f69SBart Van Assche * license that can be found in the BSD_LICENSE file.
6*44704f69SBart Van Assche *
7*44704f69SBart Van Assche * SPDX-License-Identifier: BSD-2-Clause
8*44704f69SBart Van Assche */
9*44704f69SBart Van Assche
10*44704f69SBart Van Assche #include <stdio.h>
11*44704f69SBart Van Assche #include <stdlib.h>
12*44704f69SBart Van Assche #include <stdarg.h>
13*44704f69SBart Van Assche #include <stdbool.h>
14*44704f69SBart Van Assche #include <string.h>
15*44704f69SBart Van Assche #include <ctype.h>
16*44704f69SBart Van Assche #define __STDC_FORMAT_MACROS 1
17*44704f69SBart Van Assche #include <inttypes.h>
18*44704f69SBart Van Assche
19*44704f69SBart Van Assche
20*44704f69SBart Van Assche #ifdef HAVE_CONFIG_H
21*44704f69SBart Van Assche #include "config.h"
22*44704f69SBart Van Assche #endif
23*44704f69SBart Van Assche
24*44704f69SBart Van Assche #include "sg_lib.h"
25*44704f69SBart Van Assche #include "sg_pt.h"
26*44704f69SBart Van Assche #include "sg_unaligned.h"
27*44704f69SBart Van Assche #include "sg_pr2serr.h"
28*44704f69SBart Van Assche #include "sg_pr2serr.h"
29*44704f69SBart Van Assche
30*44704f69SBart Van Assche #if (HAVE_NVME && (! IGNORE_NVME))
31*44704f69SBart Van Assche #include "sg_pt_nvme.h"
32*44704f69SBart Van Assche #endif
33*44704f69SBart Van Assche
34*44704f69SBart Van Assche static const char * scsi_pt_version_str = "3.19 20220127";
35*44704f69SBart Van Assche
36*44704f69SBart Van Assche /* List of external functions that need to be defined for each OS are
37*44704f69SBart Van Assche * listed at the top of sg_pt_dummy.c */
38*44704f69SBart Van Assche
39*44704f69SBart Van Assche const char *
scsi_pt_version()40*44704f69SBart Van Assche scsi_pt_version()
41*44704f69SBart Van Assche {
42*44704f69SBart Van Assche return scsi_pt_version_str;
43*44704f69SBart Van Assche }
44*44704f69SBart Van Assche
45*44704f69SBart Van Assche const char *
sg_pt_version()46*44704f69SBart Van Assche sg_pt_version()
47*44704f69SBart Van Assche {
48*44704f69SBart Van Assche return scsi_pt_version_str;
49*44704f69SBart Van Assche }
50*44704f69SBart Van Assche
51*44704f69SBart Van Assche
52*44704f69SBart Van Assche #if (HAVE_NVME && (! IGNORE_NVME))
53*44704f69SBart Van Assche /* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ */
54*44704f69SBart Van Assche
55*44704f69SBart Van Assche #define SAVING_PARAMS_UNSUP 0x39
56*44704f69SBart Van Assche #define INVALID_FIELD_IN_CDB 0x24
57*44704f69SBart Van Assche #define INVALID_FIELD_IN_PARAM_LIST 0x26
58*44704f69SBart Van Assche #define PARAMETER_LIST_LENGTH_ERR 0x1a
59*44704f69SBart Van Assche
60*44704f69SBart Van Assche static const char * nvme_scsi_vendor_str = "NVMe ";
61*44704f69SBart Van Assche
62*44704f69SBart Van Assche
63*44704f69SBart Van Assche #define F_SA_LOW 0x80 /* cdb byte 1, bits 4 to 0 */
64*44704f69SBart Van Assche #define F_SA_HIGH 0x100 /* as used by variable length cdbs */
65*44704f69SBart Van Assche #define FF_SA (F_SA_HIGH | F_SA_LOW)
66*44704f69SBart Van Assche #define F_INV_OP 0x200
67*44704f69SBart Van Assche
68*44704f69SBart Van Assche /* Table of SCSI operation code (opcodes) supported by SNTL */
69*44704f69SBart Van Assche static struct sg_opcode_info_t sg_opcode_info_arr[] =
70*44704f69SBart Van Assche {
71*44704f69SBart Van Assche {0x0, 0, 0, {6, /* TEST UNIT READY */
72*44704f69SBart Van Assche 0, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
73*44704f69SBart Van Assche {0x3, 0, 0, {6, /* REQUEST SENSE */
74*44704f69SBart Van Assche 0xe1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
75*44704f69SBart Van Assche {0x12, 0, 0, {6, /* INQUIRY */
76*44704f69SBart Van Assche 0xe3, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
77*44704f69SBart Van Assche {0x1b, 0, 0, {6, /* START STOP UNIT */
78*44704f69SBart Van Assche 0x1, 0, 0xf, 0xf7, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
79*44704f69SBart Van Assche {0x1c, 0, 0, {6, /* RECEIVE DIAGNOSTIC RESULTS */
80*44704f69SBart Van Assche 0x1, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
81*44704f69SBart Van Assche {0x1d, 0, 0, {6, /* SEND DIAGNOSTIC */
82*44704f69SBart Van Assche 0xf7, 0x0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
83*44704f69SBart Van Assche {0x25, 0, 0, {10, /* READ CAPACITY(10) */
84*44704f69SBart Van Assche 0x1, 0xff, 0xff, 0xff, 0xff, 0, 0, 0x1, 0xc7, 0, 0, 0, 0, 0, 0} },
85*44704f69SBart Van Assche {0x28, 0, 0, {10, /* READ(10) */
86*44704f69SBart Van Assche 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 0, 0,
87*44704f69SBart Van Assche 0, 0} },
88*44704f69SBart Van Assche {0x2a, 0, 0, {10, /* WRITE(10) */
89*44704f69SBart Van Assche 0xfb, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 0, 0,
90*44704f69SBart Van Assche 0, 0} },
91*44704f69SBart Van Assche {0x2f, 0, 0, {10, /* VERIFY(10) */
92*44704f69SBart Van Assche 0xf6, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 0, 0,
93*44704f69SBart Van Assche 0, 0} },
94*44704f69SBart Van Assche {0x35, 0, 0, {10, /* SYNCHRONIZE CACHE(10) */
95*44704f69SBart Van Assche 0x7, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 0, 0,
96*44704f69SBart Van Assche 0, 0} },
97*44704f69SBart Van Assche {0x41, 0, 0, {10, /* WRITE SAME(10) */
98*44704f69SBart Van Assche 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 0, 0,
99*44704f69SBart Van Assche 0, 0} },
100*44704f69SBart Van Assche {0x55, 0, 0, {10, /* MODE SELECT(10) */
101*44704f69SBart Van Assche 0x13, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
102*44704f69SBart Van Assche {0x5a, 0, 0, {10, /* MODE SENSE(10) */
103*44704f69SBart Van Assche 0x18, 0xff, 0xff, 0x0, 0x0, 0x0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
104*44704f69SBart Van Assche {0x88, 0, 0, {16, /* READ(16) */
105*44704f69SBart Van Assche 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
106*44704f69SBart Van Assche 0xff, 0xff, 0xff, 0xc7} },
107*44704f69SBart Van Assche {0x8a, 0, 0, {16, /* WRITE(16) */
108*44704f69SBart Van Assche 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
109*44704f69SBart Van Assche 0xff, 0xff, 0xff, 0xc7} },
110*44704f69SBart Van Assche {0x8f, 0, 0, {16, /* VERIFY(16) */
111*44704f69SBart Van Assche 0xf6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
112*44704f69SBart Van Assche 0xff, 0xff, 0x3f, 0xc7} },
113*44704f69SBart Van Assche {0x91, 0, 0, {16, /* SYNCHRONIZE CACHE(16) */
114*44704f69SBart Van Assche 0x7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
115*44704f69SBart Van Assche 0xff, 0xff, 0x3f, 0xc7} },
116*44704f69SBart Van Assche {0x93, 0, 0, {16, /* WRITE SAME(16) */
117*44704f69SBart Van Assche 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
118*44704f69SBart Van Assche 0xff, 0xff, 0x3f, 0xc7} },
119*44704f69SBart Van Assche {0x9e, 0x10, F_SA_LOW, {16, /* READ CAPACITY(16) [service action in] */
120*44704f69SBart Van Assche 0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
121*44704f69SBart Van Assche 0xff, 0xff, 0x1, 0xc7} },
122*44704f69SBart Van Assche {0xa0, 0, 0, {12, /* REPORT LUNS */
123*44704f69SBart Van Assche 0xe3, 0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0, 0, 0} },
124*44704f69SBart Van Assche {0xa3, 0xc, F_SA_LOW, {12, /* REPORT SUPPORTED OPERATION CODES */
125*44704f69SBart Van Assche 0xc, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0, 0,
126*44704f69SBart Van Assche 0} },
127*44704f69SBart Van Assche {0xa3, 0xd, F_SA_LOW, {12, /* REPORT SUPPORTED TASK MAN. FUNCTIONS */
128*44704f69SBart Van Assche 0xd, 0x80, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0, 0, 0} },
129*44704f69SBart Van Assche
130*44704f69SBart Van Assche {0xff, 0xffff, 0xffff, {0, /* Sentinel, keep as last element */
131*44704f69SBart Van Assche 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
132*44704f69SBart Van Assche };
133*44704f69SBart Van Assche
134*44704f69SBart Van Assche /* Returns pointer to array of struct sg_opcode_info_t of SCSI commands
135*44704f69SBart Van Assche * translated to NVMe. */
136*44704f69SBart Van Assche const struct sg_opcode_info_t *
sg_get_opcode_translation(void)137*44704f69SBart Van Assche sg_get_opcode_translation(void)
138*44704f69SBart Van Assche {
139*44704f69SBart Van Assche return sg_opcode_info_arr;
140*44704f69SBart Van Assche }
141*44704f69SBart Van Assche
142*44704f69SBart Van Assche /* Given the NVMe Identify controller response and optionally the NVMe
143*44704f69SBart Van Assche * Identify namespace response (NULL otherwise), generate the SCSI VPD
144*44704f69SBart Van Assche * page 0x83 (device identification) descriptor(s) in dop. Return the
145*44704f69SBart Van Assche * number of bytes written which will not exceed max_do_len. Probably use
146*44704f69SBart Van Assche * Peripheral Device Type (pdt) of 0 (disk) for don't know. Transport
147*44704f69SBart Van Assche * protocol (tproto) should be -1 if not known, else SCSI value.
148*44704f69SBart Van Assche * N.B. Does not write total VPD page length into dop[2:3] . */
149*44704f69SBart Van Assche int
sg_make_vpd_devid_for_nvme(const uint8_t * nvme_id_ctl_p,const uint8_t * nvme_id_ns_p,int pdt,int tproto,uint8_t * dop,int max_do_len)150*44704f69SBart Van Assche sg_make_vpd_devid_for_nvme(const uint8_t * nvme_id_ctl_p,
151*44704f69SBart Van Assche const uint8_t * nvme_id_ns_p, int pdt,
152*44704f69SBart Van Assche int tproto, uint8_t * dop, int max_do_len)
153*44704f69SBart Van Assche {
154*44704f69SBart Van Assche bool have_nguid, have_eui64;
155*44704f69SBart Van Assche int k, n;
156*44704f69SBart Van Assche char b[4];
157*44704f69SBart Van Assche
158*44704f69SBart Van Assche if ((NULL == nvme_id_ctl_p) || (NULL == dop) || (max_do_len < 56))
159*44704f69SBart Van Assche return 0;
160*44704f69SBart Van Assche
161*44704f69SBart Van Assche memset(dop, 0, max_do_len);
162*44704f69SBart Van Assche dop[0] = 0x1f & pdt; /* (PQ=0)<<5 | (PDT=pdt); 0 or 0xd (SES) */
163*44704f69SBart Van Assche dop[1] = 0x83; /* Device Identification VPD page number */
164*44704f69SBart Van Assche /* Build a T10 Vendor ID based designator (desig_id=1) for controller */
165*44704f69SBart Van Assche if (tproto >= 0) {
166*44704f69SBart Van Assche dop[4] = ((0xf & tproto) << 4) | 0x2;
167*44704f69SBart Van Assche dop[5] = 0xa1; /* PIV=1, ASSOC=2 (target device), desig_id=1 */
168*44704f69SBart Van Assche } else {
169*44704f69SBart Van Assche dop[4] = 0x2; /* Prococol id=0, code_set=2 (ASCII) */
170*44704f69SBart Van Assche dop[5] = 0x21; /* PIV=0, ASSOC=2 (target device), desig_id=1 */
171*44704f69SBart Van Assche }
172*44704f69SBart Van Assche memcpy(dop + 8, nvme_scsi_vendor_str, 8); /* N.B. this is "NVMe " */
173*44704f69SBart Van Assche memcpy(dop + 16, nvme_id_ctl_p + 24, 40); /* MN */
174*44704f69SBart Van Assche for (k = 40; k > 0; --k) {
175*44704f69SBart Van Assche if (' ' == dop[15 + k])
176*44704f69SBart Van Assche dop[15 + k] = '_'; /* convert trailing spaces */
177*44704f69SBart Van Assche else
178*44704f69SBart Van Assche break;
179*44704f69SBart Van Assche }
180*44704f69SBart Van Assche if (40 == k)
181*44704f69SBart Van Assche --k;
182*44704f69SBart Van Assche n = 16 + 1 + k;
183*44704f69SBart Van Assche if (max_do_len < (n + 20))
184*44704f69SBart Van Assche return 0;
185*44704f69SBart Van Assche memcpy(dop + n, nvme_id_ctl_p + 4, 20); /* SN */
186*44704f69SBart Van Assche for (k = 20; k > 0; --k) { /* trim trailing spaces */
187*44704f69SBart Van Assche if (' ' == dop[n + k - 1])
188*44704f69SBart Van Assche dop[n + k - 1] = '\0';
189*44704f69SBart Van Assche else
190*44704f69SBart Van Assche break;
191*44704f69SBart Van Assche }
192*44704f69SBart Van Assche n += k;
193*44704f69SBart Van Assche if (0 != (n % 4))
194*44704f69SBart Van Assche n = ((n / 4) + 1) * 4; /* round up to next modulo 4 */
195*44704f69SBart Van Assche dop[7] = n - 8;
196*44704f69SBart Van Assche if (NULL == nvme_id_ns_p)
197*44704f69SBart Van Assche return n;
198*44704f69SBart Van Assche
199*44704f69SBart Van Assche /* Look for NGUID (16 byte identifier) or EUI64 (8 byte) fields in
200*44704f69SBart Van Assche * NVME Identify for namespace. If found form a EUI and a SCSI string
201*44704f69SBart Van Assche * descriptor for non-zero NGUID or EUI64 (prefer NGUID if both). */
202*44704f69SBart Van Assche have_nguid = ! sg_all_zeros(nvme_id_ns_p + 104, 16);
203*44704f69SBart Van Assche have_eui64 = ! sg_all_zeros(nvme_id_ns_p + 120, 8);
204*44704f69SBart Van Assche if ((! have_nguid) && (! have_eui64))
205*44704f69SBart Van Assche return n;
206*44704f69SBart Van Assche if (have_nguid) {
207*44704f69SBart Van Assche if (max_do_len < (n + 20))
208*44704f69SBart Van Assche return n;
209*44704f69SBart Van Assche dop[n + 0] = 0x1; /* Prococol id=0, code_set=1 (binary) */
210*44704f69SBart Van Assche dop[n + 1] = 0x02; /* PIV=0, ASSOC=0 (lu), desig_id=2 (eui) */
211*44704f69SBart Van Assche dop[n + 3] = 16;
212*44704f69SBart Van Assche memcpy(dop + n + 4, nvme_id_ns_p + 104, 16);
213*44704f69SBart Van Assche n += 20;
214*44704f69SBart Van Assche if (max_do_len < (n + 40))
215*44704f69SBart Van Assche return n;
216*44704f69SBart Van Assche dop[n + 0] = 0x3; /* Prococol id=0, code_set=3 (utf8) */
217*44704f69SBart Van Assche dop[n + 1] = 0x08; /* PIV=0, ASSOC=0 (lu), desig_id=8 (scsi string) */
218*44704f69SBart Van Assche dop[n + 3] = 36;
219*44704f69SBart Van Assche memcpy(dop + n + 4, "eui.", 4);
220*44704f69SBart Van Assche for (k = 0; k < 16; ++k) {
221*44704f69SBart Van Assche snprintf(b, sizeof(b), "%02X", nvme_id_ns_p[104 + k]);
222*44704f69SBart Van Assche memcpy(dop + n + 8 + (2 * k), b, 2);
223*44704f69SBart Van Assche }
224*44704f69SBart Van Assche return n + 40;
225*44704f69SBart Van Assche } else { /* have_eui64 is true, 8 byte identifier */
226*44704f69SBart Van Assche if (max_do_len < (n + 12))
227*44704f69SBart Van Assche return n;
228*44704f69SBart Van Assche dop[n + 0] = 0x1; /* Prococol id=0, code_set=1 (binary) */
229*44704f69SBart Van Assche dop[n + 1] = 0x02; /* PIV=0, ASSOC=0 (lu), desig_id=2 (eui) */
230*44704f69SBart Van Assche dop[n + 3] = 8;
231*44704f69SBart Van Assche memcpy(dop + n + 4, nvme_id_ns_p + 120, 8);
232*44704f69SBart Van Assche n += 12;
233*44704f69SBart Van Assche if (max_do_len < (n + 24))
234*44704f69SBart Van Assche return n;
235*44704f69SBart Van Assche dop[n + 0] = 0x3; /* Prococol id=0, code_set=3 (utf8) */
236*44704f69SBart Van Assche dop[n + 1] = 0x08; /* PIV=0, ASSOC=0 (lu), desig_id=8 (scsi string) */
237*44704f69SBart Van Assche dop[n + 3] = 20;
238*44704f69SBart Van Assche memcpy(dop + n + 4, "eui.", 4);
239*44704f69SBart Van Assche for (k = 0; k < 8; ++k) {
240*44704f69SBart Van Assche snprintf(b, sizeof(b), "%02X", nvme_id_ns_p[120 + k]);
241*44704f69SBart Van Assche memcpy(dop + n + 8 + (2 * k), b, 2);
242*44704f69SBart Van Assche }
243*44704f69SBart Van Assche return n + 24;
244*44704f69SBart Van Assche }
245*44704f69SBart Van Assche }
246*44704f69SBart Van Assche
247*44704f69SBart Van Assche /* Disconnect-Reconnect page for mode_sense */
248*44704f69SBart Van Assche static int
resp_disconnect_pg(uint8_t * p,int pcontrol)249*44704f69SBart Van Assche resp_disconnect_pg(uint8_t * p, int pcontrol)
250*44704f69SBart Van Assche {
251*44704f69SBart Van Assche uint8_t disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
252*44704f69SBart Van Assche 0, 0, 0, 0, 0, 0, 0, 0};
253*44704f69SBart Van Assche
254*44704f69SBart Van Assche memcpy(p, disconnect_pg, sizeof(disconnect_pg));
255*44704f69SBart Van Assche if (1 == pcontrol)
256*44704f69SBart Van Assche memset(p + 2, 0, sizeof(disconnect_pg) - 2);
257*44704f69SBart Van Assche return sizeof(disconnect_pg);
258*44704f69SBart Van Assche }
259*44704f69SBart Van Assche
260*44704f69SBart Van Assche static uint8_t caching_m_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
261*44704f69SBart Van Assche 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,
262*44704f69SBart Van Assche 0, 0, 0, 0};
263*44704f69SBart Van Assche
264*44704f69SBart Van Assche /* Control mode page (SBC) for mode_sense */
265*44704f69SBart Van Assche static int
resp_caching_m_pg(unsigned char * p,int pcontrol,bool wce)266*44704f69SBart Van Assche resp_caching_m_pg(unsigned char *p, int pcontrol, bool wce)
267*44704f69SBart Van Assche { /* Caching page for mode_sense */
268*44704f69SBart Van Assche uint8_t ch_caching_m_pg[] = {/* 0x8, 18, */ 0x4, 0, 0, 0, 0, 0,
269*44704f69SBart Van Assche 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
270*44704f69SBart Van Assche uint8_t d_caching_m_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
271*44704f69SBart Van Assche 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0};
272*44704f69SBart Van Assche
273*44704f69SBart Van Assche // if (SDEBUG_OPT_N_WCE & sdebug_opts)
274*44704f69SBart Van Assche caching_m_pg[2] &= ~0x4; /* set WCE=0 (default WCE=1) */
275*44704f69SBart Van Assche if ((0 == pcontrol) || (3 == pcontrol)) {
276*44704f69SBart Van Assche if (wce)
277*44704f69SBart Van Assche caching_m_pg[2] |= 0x4;
278*44704f69SBart Van Assche else
279*44704f69SBart Van Assche caching_m_pg[2] &= ~0x4;
280*44704f69SBart Van Assche }
281*44704f69SBart Van Assche memcpy(p, caching_m_pg, sizeof(caching_m_pg));
282*44704f69SBart Van Assche if (1 == pcontrol) {
283*44704f69SBart Van Assche if (wce)
284*44704f69SBart Van Assche ch_caching_m_pg[2] |= 0x4;
285*44704f69SBart Van Assche else
286*44704f69SBart Van Assche ch_caching_m_pg[2] &= ~0x4;
287*44704f69SBart Van Assche memcpy(p + 2, ch_caching_m_pg, sizeof(ch_caching_m_pg));
288*44704f69SBart Van Assche }
289*44704f69SBart Van Assche else if (2 == pcontrol) {
290*44704f69SBart Van Assche if (wce)
291*44704f69SBart Van Assche d_caching_m_pg[2] |= 0x4;
292*44704f69SBart Van Assche else
293*44704f69SBart Van Assche d_caching_m_pg[2] &= ~0x4;
294*44704f69SBart Van Assche memcpy(p, d_caching_m_pg, sizeof(d_caching_m_pg));
295*44704f69SBart Van Assche }
296*44704f69SBart Van Assche return sizeof(caching_m_pg);
297*44704f69SBart Van Assche }
298*44704f69SBart Van Assche
299*44704f69SBart Van Assche static uint8_t ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
300*44704f69SBart Van Assche 0, 0, 0x2, 0x4b};
301*44704f69SBart Van Assche
302*44704f69SBart Van Assche /* Control mode page for mode_sense */
303*44704f69SBart Van Assche static int
resp_ctrl_m_pg(uint8_t * p,int pcontrol)304*44704f69SBart Van Assche resp_ctrl_m_pg(uint8_t *p, int pcontrol)
305*44704f69SBart Van Assche {
306*44704f69SBart Van Assche uint8_t ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
307*44704f69SBart Van Assche 0, 0, 0, 0};
308*44704f69SBart Van Assche uint8_t d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
309*44704f69SBart Van Assche 0, 0, 0x2, 0x4b};
310*44704f69SBart Van Assche
311*44704f69SBart Van Assche memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
312*44704f69SBart Van Assche if (1 == pcontrol)
313*44704f69SBart Van Assche memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
314*44704f69SBart Van Assche else if (2 == pcontrol)
315*44704f69SBart Van Assche memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
316*44704f69SBart Van Assche return sizeof(ctrl_m_pg);
317*44704f69SBart Van Assche }
318*44704f69SBart Van Assche
319*44704f69SBart Van Assche static uint8_t ctrl_ext_m_pg[] = {0x4a, 0x1, 0, 0x1c, 0, 0, 0x40, 0,
320*44704f69SBart Van Assche 0, 0, 0, 0, 0, 0, 0, 0,
321*44704f69SBart Van Assche 0, 0, 0, 0, 0, 0, 0, 0,
322*44704f69SBart Van Assche 0, 0, 0, 0, 0, 0, 0, 0, };
323*44704f69SBart Van Assche
324*44704f69SBart Van Assche /* Control Extension mode page [0xa,0x1] for mode_sense */
325*44704f69SBart Van Assche static int
resp_ctrl_ext_m_pg(uint8_t * p,int pcontrol)326*44704f69SBart Van Assche resp_ctrl_ext_m_pg(uint8_t *p, int pcontrol)
327*44704f69SBart Van Assche {
328*44704f69SBart Van Assche uint8_t ch_ctrl_ext_m_pg[] = {/* 0x4a, 0x1, 0, 0x1c, */ 0, 0, 0, 0,
329*44704f69SBart Van Assche 0, 0, 0, 0, 0, 0, 0, 0,
330*44704f69SBart Van Assche 0, 0, 0, 0, 0, 0, 0, 0,
331*44704f69SBart Van Assche 0, 0, 0, 0, 0, 0, 0, 0, };
332*44704f69SBart Van Assche uint8_t d_ctrl_ext_m_pg[] = {0x4a, 0x1, 0, 0x1c, 0, 0, 0x40, 0,
333*44704f69SBart Van Assche 0, 0, 0, 0, 0, 0, 0, 0,
334*44704f69SBart Van Assche 0, 0, 0, 0, 0, 0, 0, 0,
335*44704f69SBart Van Assche 0, 0, 0, 0, 0, 0, 0, 0, };
336*44704f69SBart Van Assche
337*44704f69SBart Van Assche memcpy(p, ctrl_ext_m_pg, sizeof(ctrl_ext_m_pg));
338*44704f69SBart Van Assche if (1 == pcontrol)
339*44704f69SBart Van Assche memcpy(p + 4, ch_ctrl_ext_m_pg, sizeof(ch_ctrl_ext_m_pg));
340*44704f69SBart Van Assche else if (2 == pcontrol)
341*44704f69SBart Van Assche memcpy(p, d_ctrl_ext_m_pg, sizeof(d_ctrl_ext_m_pg));
342*44704f69SBart Van Assche return sizeof(ctrl_ext_m_pg);
343*44704f69SBart Van Assche }
344*44704f69SBart Van Assche
345*44704f69SBart Van Assche static uint8_t iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0, 0, 0, 0x0, 0x0};
346*44704f69SBart Van Assche
347*44704f69SBart Van Assche /* Informational Exceptions control mode page for mode_sense */
348*44704f69SBart Van Assche static int
resp_iec_m_pg(uint8_t * p,int pcontrol)349*44704f69SBart Van Assche resp_iec_m_pg(uint8_t *p, int pcontrol)
350*44704f69SBart Van Assche {
351*44704f69SBart Van Assche uint8_t ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0, 0, 0,
352*44704f69SBart Van Assche 0x0, 0x0};
353*44704f69SBart Van Assche uint8_t d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0, 0, 0, 0x0, 0x0};
354*44704f69SBart Van Assche
355*44704f69SBart Van Assche memcpy(p, iec_m_pg, sizeof(iec_m_pg));
356*44704f69SBart Van Assche if (1 == pcontrol)
357*44704f69SBart Van Assche memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
358*44704f69SBart Van Assche else if (2 == pcontrol)
359*44704f69SBart Van Assche memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
360*44704f69SBart Van Assche return sizeof(iec_m_pg);
361*44704f69SBart Van Assche }
362*44704f69SBart Van Assche
363*44704f69SBart Van Assche static uint8_t vs_ua_m_pg[] = {0x0, 0xe, 0, 0, 0, 0, 0, 0,
364*44704f69SBart Van Assche 0, 0, 0, 0, 0, 0, 0};
365*44704f69SBart Van Assche
366*44704f69SBart Van Assche /* Vendor specific Unit Attention mode page for mode_sense */
367*44704f69SBart Van Assche static int
resp_vs_ua_m_pg(uint8_t * p,int pcontrol)368*44704f69SBart Van Assche resp_vs_ua_m_pg(uint8_t *p, int pcontrol)
369*44704f69SBart Van Assche {
370*44704f69SBart Van Assche uint8_t ch_vs_ua_m_pg[] = {/* 0x0, 0xe, */ 0xff, 0, 0, 0, 0, 0,
371*44704f69SBart Van Assche 0, 0, 0, 0, 0, 0, 0, 0};
372*44704f69SBart Van Assche uint8_t d_vs_ua_m_pg[] = {0x0, 0xe, 0, 0, 0, 0, 0, 0,
373*44704f69SBart Van Assche 0, 0, 0, 0, 0, 0, 0, 0};
374*44704f69SBart Van Assche
375*44704f69SBart Van Assche memcpy(p, vs_ua_m_pg, sizeof(vs_ua_m_pg));
376*44704f69SBart Van Assche if (1 == pcontrol)
377*44704f69SBart Van Assche memcpy(p + 2, ch_vs_ua_m_pg, sizeof(ch_vs_ua_m_pg));
378*44704f69SBart Van Assche else if (2 == pcontrol)
379*44704f69SBart Van Assche memcpy(p, d_vs_ua_m_pg, sizeof(d_vs_ua_m_pg));
380*44704f69SBart Van Assche return sizeof(vs_ua_m_pg);
381*44704f69SBart Van Assche }
382*44704f69SBart Van Assche
383*44704f69SBart Van Assche void
sntl_init_dev_stat(struct sg_sntl_dev_state_t * dsp)384*44704f69SBart Van Assche sntl_init_dev_stat(struct sg_sntl_dev_state_t * dsp)
385*44704f69SBart Van Assche {
386*44704f69SBart Van Assche if (dsp) {
387*44704f69SBart Van Assche dsp->scsi_dsense = !! (0x4 & ctrl_m_pg[2]);
388*44704f69SBart Van Assche dsp->enclosure_override = vs_ua_m_pg[2];
389*44704f69SBart Van Assche }
390*44704f69SBart Van Assche }
391*44704f69SBart Van Assche
392*44704f69SBart Van Assche
393*44704f69SBart Van Assche #define SDEBUG_MAX_MSENSE_SZ 256
394*44704f69SBart Van Assche
395*44704f69SBart Van Assche /* Only support MODE SENSE(10). Returns the number of bytes written to dip,
396*44704f69SBart Van Assche * or -1 if error info placed in resp. */
397*44704f69SBart Van Assche int
sntl_resp_mode_sense10(const struct sg_sntl_dev_state_t * dsp,const uint8_t * cdbp,uint8_t * dip,int mx_di_len,struct sg_sntl_result_t * resp)398*44704f69SBart Van Assche sntl_resp_mode_sense10(const struct sg_sntl_dev_state_t * dsp,
399*44704f69SBart Van Assche const uint8_t * cdbp, uint8_t * dip, int mx_di_len,
400*44704f69SBart Van Assche struct sg_sntl_result_t * resp)
401*44704f69SBart Van Assche {
402*44704f69SBart Van Assche bool dbd, llbaa, is_disk, bad_pcode;
403*44704f69SBart Van Assche int pcontrol, pcode, subpcode, bd_len, alloc_len, offset, len;
404*44704f69SBart Van Assche const uint32_t num_blocks = 0x100000; /* made up */
405*44704f69SBart Van Assche const uint32_t lb_size = 512; /* guess */
406*44704f69SBart Van Assche uint8_t dev_spec;
407*44704f69SBart Van Assche uint8_t * ap;
408*44704f69SBart Van Assche uint8_t arr[SDEBUG_MAX_MSENSE_SZ];
409*44704f69SBart Van Assche
410*44704f69SBart Van Assche memset(resp, 0, sizeof(*resp));
411*44704f69SBart Van Assche dbd = !! (cdbp[1] & 0x8); /* disable block descriptors */
412*44704f69SBart Van Assche pcontrol = (cdbp[2] & 0xc0) >> 6;
413*44704f69SBart Van Assche pcode = cdbp[2] & 0x3f;
414*44704f69SBart Van Assche subpcode = cdbp[3];
415*44704f69SBart Van Assche llbaa = !!(cdbp[1] & 0x10);
416*44704f69SBart Van Assche is_disk = sg_pdt_s_eq(sg_lib_pdt_decay(dsp->pdt), PDT_DISK_ZBC);
417*44704f69SBart Van Assche if (is_disk && !dbd)
418*44704f69SBart Van Assche bd_len = llbaa ? 16 : 8;
419*44704f69SBart Van Assche else
420*44704f69SBart Van Assche bd_len = 0;
421*44704f69SBart Van Assche alloc_len = sg_get_unaligned_be16(cdbp + 7);
422*44704f69SBart Van Assche memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
423*44704f69SBart Van Assche if (0x3 == pcontrol) { /* Saving values not supported */
424*44704f69SBart Van Assche resp->asc = SAVING_PARAMS_UNSUP;
425*44704f69SBart Van Assche goto err_out;
426*44704f69SBart Van Assche }
427*44704f69SBart Van Assche /* for disks set DPOFUA bit and clear write protect (WP) bit */
428*44704f69SBart Van Assche if (is_disk)
429*44704f69SBart Van Assche dev_spec = 0x10; /* =0x90 if WP=1 implies read-only */
430*44704f69SBart Van Assche else
431*44704f69SBart Van Assche dev_spec = 0x0;
432*44704f69SBart Van Assche arr[3] = dev_spec;
433*44704f69SBart Van Assche if (16 == bd_len)
434*44704f69SBart Van Assche arr[4] = 0x1; /* set LONGLBA bit */
435*44704f69SBart Van Assche arr[7] = bd_len; /* assume 255 or less */
436*44704f69SBart Van Assche offset = 8;
437*44704f69SBart Van Assche ap = arr + offset;
438*44704f69SBart Van Assche
439*44704f69SBart Van Assche if (8 == bd_len) {
440*44704f69SBart Van Assche sg_put_unaligned_be32(num_blocks, ap + 0);
441*44704f69SBart Van Assche sg_put_unaligned_be16((uint16_t)lb_size, ap + 6);
442*44704f69SBart Van Assche offset += bd_len;
443*44704f69SBart Van Assche ap = arr + offset;
444*44704f69SBart Van Assche } else if (16 == bd_len) {
445*44704f69SBart Van Assche sg_put_unaligned_be64(num_blocks, ap + 0);
446*44704f69SBart Van Assche sg_put_unaligned_be32(lb_size, ap + 12);
447*44704f69SBart Van Assche offset += bd_len;
448*44704f69SBart Van Assche ap = arr + offset;
449*44704f69SBart Van Assche }
450*44704f69SBart Van Assche bad_pcode = false;
451*44704f69SBart Van Assche
452*44704f69SBart Van Assche switch (pcode) {
453*44704f69SBart Van Assche case 0x2: /* Disconnect-Reconnect page, all devices */
454*44704f69SBart Van Assche if (0x0 == subpcode)
455*44704f69SBart Van Assche len = resp_disconnect_pg(ap, pcontrol);
456*44704f69SBart Van Assche else {
457*44704f69SBart Van Assche len = 0;
458*44704f69SBart Van Assche bad_pcode = true;
459*44704f69SBart Van Assche }
460*44704f69SBart Van Assche offset += len;
461*44704f69SBart Van Assche break;
462*44704f69SBart Van Assche case 0x8: /* Caching Mode page, disk (like) devices */
463*44704f69SBart Van Assche if (! is_disk) {
464*44704f69SBart Van Assche len = 0;
465*44704f69SBart Van Assche bad_pcode = true;
466*44704f69SBart Van Assche } else if (0x0 == subpcode)
467*44704f69SBart Van Assche len = resp_caching_m_pg(ap, pcontrol, dsp->wce);
468*44704f69SBart Van Assche else {
469*44704f69SBart Van Assche len = 0;
470*44704f69SBart Van Assche bad_pcode = true;
471*44704f69SBart Van Assche }
472*44704f69SBart Van Assche offset += len;
473*44704f69SBart Van Assche break;
474*44704f69SBart Van Assche case 0xa: /* Control Mode page, all devices */
475*44704f69SBart Van Assche if (0x0 == subpcode)
476*44704f69SBart Van Assche len = resp_ctrl_m_pg(ap, pcontrol);
477*44704f69SBart Van Assche else if (0x1 == subpcode)
478*44704f69SBart Van Assche len = resp_ctrl_ext_m_pg(ap, pcontrol);
479*44704f69SBart Van Assche else {
480*44704f69SBart Van Assche len = 0;
481*44704f69SBart Van Assche bad_pcode = true;
482*44704f69SBart Van Assche }
483*44704f69SBart Van Assche offset += len;
484*44704f69SBart Van Assche break;
485*44704f69SBart Van Assche case 0x1c: /* Informational Exceptions Mode page, all devices */
486*44704f69SBart Van Assche if (0x0 == subpcode)
487*44704f69SBart Van Assche len = resp_iec_m_pg(ap, pcontrol);
488*44704f69SBart Van Assche else {
489*44704f69SBart Van Assche len = 0;
490*44704f69SBart Van Assche bad_pcode = true;
491*44704f69SBart Van Assche }
492*44704f69SBart Van Assche offset += len;
493*44704f69SBart Van Assche break;
494*44704f69SBart Van Assche case 0x3f: /* Read all Mode pages */
495*44704f69SBart Van Assche if ((0 == subpcode) || (0xff == subpcode)) {
496*44704f69SBart Van Assche len = 0;
497*44704f69SBart Van Assche len = resp_disconnect_pg(ap + len, pcontrol);
498*44704f69SBart Van Assche if (is_disk)
499*44704f69SBart Van Assche len += resp_caching_m_pg(ap + len, pcontrol, dsp->wce);
500*44704f69SBart Van Assche len += resp_ctrl_m_pg(ap + len, pcontrol);
501*44704f69SBart Van Assche if (0xff == subpcode)
502*44704f69SBart Van Assche len += resp_ctrl_ext_m_pg(ap + len, pcontrol);
503*44704f69SBart Van Assche len += resp_iec_m_pg(ap + len, pcontrol);
504*44704f69SBart Van Assche len += resp_vs_ua_m_pg(ap + len, pcontrol);
505*44704f69SBart Van Assche offset += len;
506*44704f69SBart Van Assche } else {
507*44704f69SBart Van Assche resp->asc = INVALID_FIELD_IN_CDB;
508*44704f69SBart Van Assche resp->in_byte = 3;
509*44704f69SBart Van Assche resp->in_bit = 255;
510*44704f69SBart Van Assche goto err_out;
511*44704f69SBart Van Assche }
512*44704f69SBart Van Assche break;
513*44704f69SBart Van Assche case 0x0: /* Vendor specific "Unit Attention" mode page */
514*44704f69SBart Van Assche /* all sub-page codes ?? */
515*44704f69SBart Van Assche len = resp_vs_ua_m_pg(ap, pcontrol);
516*44704f69SBart Van Assche offset += len;
517*44704f69SBart Van Assche break; /* vendor is "NVMe " (from INQUIRY field) */
518*44704f69SBart Van Assche default:
519*44704f69SBart Van Assche bad_pcode = true;
520*44704f69SBart Van Assche break;
521*44704f69SBart Van Assche }
522*44704f69SBart Van Assche if (bad_pcode) {
523*44704f69SBart Van Assche resp->asc = INVALID_FIELD_IN_CDB;
524*44704f69SBart Van Assche resp->in_byte = 2;
525*44704f69SBart Van Assche resp->in_bit = 5;
526*44704f69SBart Van Assche goto err_out;
527*44704f69SBart Van Assche }
528*44704f69SBart Van Assche sg_put_unaligned_be16(offset - 2, arr + 0);
529*44704f69SBart Van Assche len = (alloc_len < offset) ? alloc_len : offset;
530*44704f69SBart Van Assche len = (len < mx_di_len) ? len : mx_di_len;
531*44704f69SBart Van Assche memcpy(dip, arr, len);
532*44704f69SBart Van Assche return len;
533*44704f69SBart Van Assche
534*44704f69SBart Van Assche err_out:
535*44704f69SBart Van Assche resp->sstatus = SAM_STAT_CHECK_CONDITION;
536*44704f69SBart Van Assche resp->sk = SPC_SK_ILLEGAL_REQUEST;
537*44704f69SBart Van Assche return -1;
538*44704f69SBart Van Assche }
539*44704f69SBart Van Assche
540*44704f69SBart Van Assche #define SDEBUG_MAX_MSELECT_SZ 512
541*44704f69SBart Van Assche
542*44704f69SBart Van Assche /* Only support MODE SELECT(10). Returns number of bytes used from dop,
543*44704f69SBart Van Assche * else -1 on error with sense code placed in resp. */
544*44704f69SBart Van Assche int
sntl_resp_mode_select10(struct sg_sntl_dev_state_t * dsp,const uint8_t * cdbp,const uint8_t * dop,int do_len,struct sg_sntl_result_t * resp)545*44704f69SBart Van Assche sntl_resp_mode_select10(struct sg_sntl_dev_state_t * dsp,
546*44704f69SBart Van Assche const uint8_t * cdbp, const uint8_t * dop, int do_len,
547*44704f69SBart Van Assche struct sg_sntl_result_t * resp)
548*44704f69SBart Van Assche {
549*44704f69SBart Van Assche int pf, sp, ps, md_len, bd_len, off, spf, pg_len, rlen, param_len, mpage;
550*44704f69SBart Van Assche int sub_mpage;
551*44704f69SBart Van Assche uint8_t arr[SDEBUG_MAX_MSELECT_SZ];
552*44704f69SBart Van Assche
553*44704f69SBart Van Assche memset(resp, 0, sizeof(*resp));
554*44704f69SBart Van Assche memset(arr, 0, sizeof(arr));
555*44704f69SBart Van Assche pf = cdbp[1] & 0x10;
556*44704f69SBart Van Assche sp = cdbp[1] & 0x1;
557*44704f69SBart Van Assche param_len = sg_get_unaligned_be16(cdbp + 7);
558*44704f69SBart Van Assche if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
559*44704f69SBart Van Assche resp->asc = INVALID_FIELD_IN_CDB;
560*44704f69SBart Van Assche resp->in_byte = 1;
561*44704f69SBart Van Assche if (sp)
562*44704f69SBart Van Assche resp->in_bit = 0;
563*44704f69SBart Van Assche else if (0 == pf)
564*44704f69SBart Van Assche resp->in_bit = 4;
565*44704f69SBart Van Assche else {
566*44704f69SBart Van Assche resp->in_byte = 7;
567*44704f69SBart Van Assche resp->in_bit = 255;
568*44704f69SBart Van Assche }
569*44704f69SBart Van Assche goto err_out;
570*44704f69SBart Van Assche }
571*44704f69SBart Van Assche rlen = (do_len < param_len) ? do_len : param_len;
572*44704f69SBart Van Assche memcpy(arr, dop, rlen);
573*44704f69SBart Van Assche md_len = sg_get_unaligned_be16(arr + 0) + 2;
574*44704f69SBart Van Assche bd_len = sg_get_unaligned_be16(arr + 6);
575*44704f69SBart Van Assche if (md_len > 2) {
576*44704f69SBart Van Assche resp->asc = INVALID_FIELD_IN_PARAM_LIST;
577*44704f69SBart Van Assche resp->in_byte = 0;
578*44704f69SBart Van Assche resp->in_bit = 255;
579*44704f69SBart Van Assche goto err_out;
580*44704f69SBart Van Assche }
581*44704f69SBart Van Assche off = bd_len + 8;
582*44704f69SBart Van Assche mpage = arr[off] & 0x3f;
583*44704f69SBart Van Assche ps = !!(arr[off] & 0x80);
584*44704f69SBart Van Assche if (ps) {
585*44704f69SBart Van Assche resp->asc = INVALID_FIELD_IN_PARAM_LIST;
586*44704f69SBart Van Assche resp->in_byte = off;
587*44704f69SBart Van Assche resp->in_bit = 7;
588*44704f69SBart Van Assche goto err_out;
589*44704f69SBart Van Assche }
590*44704f69SBart Van Assche spf = !!(arr[off] & 0x40);
591*44704f69SBart Van Assche pg_len = spf ? (sg_get_unaligned_be16(arr + off + 2) + 4) :
592*44704f69SBart Van Assche (arr[off + 1] + 2);
593*44704f69SBart Van Assche sub_mpage = spf ? arr[off + 1] : 0;
594*44704f69SBart Van Assche if ((pg_len + off) > param_len) {
595*44704f69SBart Van Assche resp->asc = PARAMETER_LIST_LENGTH_ERR;
596*44704f69SBart Van Assche goto err_out;
597*44704f69SBart Van Assche }
598*44704f69SBart Van Assche switch (mpage) {
599*44704f69SBart Van Assche case 0x8: /* Caching Mode page */
600*44704f69SBart Van Assche if (0x0 == sub_mpage) {
601*44704f69SBart Van Assche if (caching_m_pg[1] == arr[off + 1]) {
602*44704f69SBart Van Assche memcpy(caching_m_pg + 2, arr + off + 2,
603*44704f69SBart Van Assche sizeof(caching_m_pg) - 2);
604*44704f69SBart Van Assche dsp->wce = !!(caching_m_pg[2] & 0x4);
605*44704f69SBart Van Assche dsp->wce_changed = true;
606*44704f69SBart Van Assche break;
607*44704f69SBart Van Assche }
608*44704f69SBart Van Assche }
609*44704f69SBart Van Assche goto def_case;
610*44704f69SBart Van Assche case 0xa: /* Control Mode page */
611*44704f69SBart Van Assche if (0x0 == sub_mpage) {
612*44704f69SBart Van Assche if (ctrl_m_pg[1] == arr[off + 1]) {
613*44704f69SBart Van Assche memcpy(ctrl_m_pg + 2, arr + off + 2,
614*44704f69SBart Van Assche sizeof(ctrl_m_pg) - 2);
615*44704f69SBart Van Assche dsp->scsi_dsense = !!(ctrl_m_pg[2] & 0x4);
616*44704f69SBart Van Assche break;
617*44704f69SBart Van Assche }
618*44704f69SBart Van Assche }
619*44704f69SBart Van Assche goto def_case;
620*44704f69SBart Van Assche case 0x1c: /* Informational Exceptions Mode page (SBC) */
621*44704f69SBart Van Assche if (0x0 == sub_mpage) {
622*44704f69SBart Van Assche if (iec_m_pg[1] == arr[off + 1]) {
623*44704f69SBart Van Assche memcpy(iec_m_pg + 2, arr + off + 2,
624*44704f69SBart Van Assche sizeof(iec_m_pg) - 2);
625*44704f69SBart Van Assche break;
626*44704f69SBart Van Assche }
627*44704f69SBart Van Assche }
628*44704f69SBart Van Assche goto def_case;
629*44704f69SBart Van Assche case 0x0: /* Vendor specific "Unit Attention" mode page */
630*44704f69SBart Van Assche if (vs_ua_m_pg[1] == arr[off + 1]) {
631*44704f69SBart Van Assche memcpy(vs_ua_m_pg + 2, arr + off + 2,
632*44704f69SBart Van Assche sizeof(vs_ua_m_pg) - 2);
633*44704f69SBart Van Assche dsp->enclosure_override = vs_ua_m_pg[2];
634*44704f69SBart Van Assche }
635*44704f69SBart Van Assche break;
636*44704f69SBart Van Assche default:
637*44704f69SBart Van Assche def_case:
638*44704f69SBart Van Assche resp->asc = INVALID_FIELD_IN_PARAM_LIST;
639*44704f69SBart Van Assche resp->in_byte = off;
640*44704f69SBart Van Assche resp->in_bit = 5;
641*44704f69SBart Van Assche goto err_out;
642*44704f69SBart Van Assche }
643*44704f69SBart Van Assche return rlen;
644*44704f69SBart Van Assche
645*44704f69SBart Van Assche err_out:
646*44704f69SBart Van Assche resp->sk = SPC_SK_ILLEGAL_REQUEST;
647*44704f69SBart Van Assche resp->sstatus = SAM_STAT_CHECK_CONDITION;
648*44704f69SBart Van Assche return -1;
649*44704f69SBart Van Assche }
650*44704f69SBart Van Assche
651*44704f69SBart Van Assche #endif /* (HAVE_NVME && (! IGNORE_NVME)) [near line 140] */
652