xref: /openbmc/qemu/pc-bios/s390-ccw/scsi.h (revision f791561476e19516385bf13c5a8f885c9bebe81d)
1*f7915614SEugene (jno) Dvurechenski /*
2*f7915614SEugene (jno) Dvurechenski  * SCSI definitions for s390 machine loader for qemu
3*f7915614SEugene (jno) Dvurechenski  *
4*f7915614SEugene (jno) Dvurechenski  * Copyright 2015 IBM Corp.
5*f7915614SEugene (jno) Dvurechenski  * Author: Eugene "jno" Dvurechenski <jno@linux.vnet.ibm.com>
6*f7915614SEugene (jno) Dvurechenski  *
7*f7915614SEugene (jno) Dvurechenski  * This work is licensed under the terms of the GNU GPL, version 2 or (at
8*f7915614SEugene (jno) Dvurechenski  * your option) any later version. See the COPYING file in the top-level
9*f7915614SEugene (jno) Dvurechenski  * directory.
10*f7915614SEugene (jno) Dvurechenski  */
11*f7915614SEugene (jno) Dvurechenski 
12*f7915614SEugene (jno) Dvurechenski #ifndef SCSI_H
13*f7915614SEugene (jno) Dvurechenski #define SCSI_H
14*f7915614SEugene (jno) Dvurechenski 
15*f7915614SEugene (jno) Dvurechenski #include "s390-ccw.h"
16*f7915614SEugene (jno) Dvurechenski 
17*f7915614SEugene (jno) Dvurechenski #define SCSI_DEFAULT_CDB_SIZE                   32
18*f7915614SEugene (jno) Dvurechenski #define SCSI_DEFAULT_SENSE_SIZE                 96
19*f7915614SEugene (jno) Dvurechenski 
20*f7915614SEugene (jno) Dvurechenski #define CDB_STATUS_GOOD                         0
21*f7915614SEugene (jno) Dvurechenski #define CDB_STATUS_CHECK_CONDITION              0x02U
22*f7915614SEugene (jno) Dvurechenski #define CDB_STATUS_VALID(status)    (((status) & ~0x3eU) == 0)
23*f7915614SEugene (jno) Dvurechenski 
24*f7915614SEugene (jno) Dvurechenski #define SCSI_SENSE_CODE_MASK                    0x7fU
25*f7915614SEugene (jno) Dvurechenski #define SCSI_SENSE_KEY_MASK                     0x0fU
26*f7915614SEugene (jno) Dvurechenski #define SCSI_SENSE_KEY_NO_SENSE                 0
27*f7915614SEugene (jno) Dvurechenski #define SCSI_SENSE_KEY_UNIT_ATTENTION           6
28*f7915614SEugene (jno) Dvurechenski 
29*f7915614SEugene (jno) Dvurechenski union ScsiLun {
30*f7915614SEugene (jno) Dvurechenski     uint64_t v64;        /* numeric shortcut                             */
31*f7915614SEugene (jno) Dvurechenski     uint8_t  v8[8];      /* generic 8 bytes representation               */
32*f7915614SEugene (jno) Dvurechenski     uint16_t v16[4];     /* 4-level big-endian LUN as specified by SAM-2 */
33*f7915614SEugene (jno) Dvurechenski };
34*f7915614SEugene (jno) Dvurechenski typedef union ScsiLun ScsiLun;
35*f7915614SEugene (jno) Dvurechenski 
36*f7915614SEugene (jno) Dvurechenski struct ScsiSense70 {
37*f7915614SEugene (jno) Dvurechenski     uint8_t b0;         /* b0 & 7f = resp code (0x70 or 0x71)   */
38*f7915614SEugene (jno) Dvurechenski     uint8_t b1, b2;     /* b2 & 0f = sense key                  */
39*f7915614SEugene (jno) Dvurechenski     uint8_t u1[1 * 4 + 1 + 1 * 4];   /* b7 = N - 7                  */
40*f7915614SEugene (jno) Dvurechenski     uint8_t additional_sense_code;              /* b12          */
41*f7915614SEugene (jno) Dvurechenski     uint8_t additional_sense_code_qualifier;    /* b13          */
42*f7915614SEugene (jno) Dvurechenski     uint8_t u2[1 + 3 + 0];           /* up to N (<=252) bytes       */
43*f7915614SEugene (jno) Dvurechenski } __attribute__((packed));
44*f7915614SEugene (jno) Dvurechenski typedef struct ScsiSense70 ScsiSense70;
45*f7915614SEugene (jno) Dvurechenski 
46*f7915614SEugene (jno) Dvurechenski /* don't confuse with virtio-scsi response/status fields! */
47*f7915614SEugene (jno) Dvurechenski 
48*f7915614SEugene (jno) Dvurechenski static inline uint8_t scsi_sense_response(const void *p)
49*f7915614SEugene (jno) Dvurechenski {
50*f7915614SEugene (jno) Dvurechenski     return ((const ScsiSense70 *)p)->b0 & SCSI_SENSE_CODE_MASK;
51*f7915614SEugene (jno) Dvurechenski }
52*f7915614SEugene (jno) Dvurechenski 
53*f7915614SEugene (jno) Dvurechenski static inline uint8_t scsi_sense_key(const void *p)
54*f7915614SEugene (jno) Dvurechenski {
55*f7915614SEugene (jno) Dvurechenski     return ((const ScsiSense70 *)p)->b2 & SCSI_SENSE_KEY_MASK;
56*f7915614SEugene (jno) Dvurechenski }
57*f7915614SEugene (jno) Dvurechenski 
58*f7915614SEugene (jno) Dvurechenski #define SCSI_INQ_RDT_CDROM                      0x05
59*f7915614SEugene (jno) Dvurechenski 
60*f7915614SEugene (jno) Dvurechenski struct ScsiInquiryStd {
61*f7915614SEugene (jno) Dvurechenski     uint8_t peripheral_qdt; /* b0, use (b0 & 0x1f) to get SCSI_INQ_RDT  */
62*f7915614SEugene (jno) Dvurechenski     uint8_t b1;             /* Removable Media Bit = b1 & 0x80          */
63*f7915614SEugene (jno) Dvurechenski     uint8_t spc_version;    /* b2                                       */
64*f7915614SEugene (jno) Dvurechenski     uint8_t b3;             /* b3 & 0x0f == resp_data_fmt == 2, must!   */
65*f7915614SEugene (jno) Dvurechenski     uint8_t u1[1 + 1 + 1 + 1 + 8];  /* b4..b15 unused, b4 = (N - 1)     */
66*f7915614SEugene (jno) Dvurechenski     char prod_id[16];       /* "QEMU CD-ROM" is here                    */
67*f7915614SEugene (jno) Dvurechenski     uint8_t u2[4            /* b32..b35 unused, mandatory               */
68*f7915614SEugene (jno) Dvurechenski               + 8 + 12 + 1 + 1 + 8 * 2 + 22  /* b36..95 unused, optional*/
69*f7915614SEugene (jno) Dvurechenski               + 0];          /* b96..bN unused, vendor specific          */
70*f7915614SEugene (jno) Dvurechenski     /* byte N                                                           */
71*f7915614SEugene (jno) Dvurechenski }  __attribute__((packed));
72*f7915614SEugene (jno) Dvurechenski typedef struct ScsiInquiryStd ScsiInquiryStd;
73*f7915614SEugene (jno) Dvurechenski 
74*f7915614SEugene (jno) Dvurechenski struct ScsiCdbInquiry {
75*f7915614SEugene (jno) Dvurechenski     uint8_t command;     /* b0, == 0x12         */
76*f7915614SEugene (jno) Dvurechenski     uint8_t b1;          /* b1, |= 0x01 (evpd)  */
77*f7915614SEugene (jno) Dvurechenski     uint8_t b2;          /* b2; if evpd==1      */
78*f7915614SEugene (jno) Dvurechenski     uint16_t alloc_len;  /* b3, b4              */
79*f7915614SEugene (jno) Dvurechenski     uint8_t control;     /* b5                  */
80*f7915614SEugene (jno) Dvurechenski }  __attribute__((packed));
81*f7915614SEugene (jno) Dvurechenski typedef struct ScsiCdbInquiry ScsiCdbInquiry;
82*f7915614SEugene (jno) Dvurechenski 
83*f7915614SEugene (jno) Dvurechenski struct ScsiCdbRead10 {
84*f7915614SEugene (jno) Dvurechenski     uint8_t command;    /* =0x28    */
85*f7915614SEugene (jno) Dvurechenski     uint8_t b1;
86*f7915614SEugene (jno) Dvurechenski     uint32_t lba;
87*f7915614SEugene (jno) Dvurechenski     uint8_t b6;
88*f7915614SEugene (jno) Dvurechenski     uint16_t xfer_length;
89*f7915614SEugene (jno) Dvurechenski     uint8_t control;
90*f7915614SEugene (jno) Dvurechenski }  __attribute__((packed));
91*f7915614SEugene (jno) Dvurechenski typedef struct ScsiCdbRead10 ScsiCdbRead10;
92*f7915614SEugene (jno) Dvurechenski 
93*f7915614SEugene (jno) Dvurechenski struct ScsiCdbTestUnitReady {
94*f7915614SEugene (jno) Dvurechenski     uint8_t command;    /* =0x00    */
95*f7915614SEugene (jno) Dvurechenski     uint8_t b1_b4[4];
96*f7915614SEugene (jno) Dvurechenski     uint8_t control;
97*f7915614SEugene (jno) Dvurechenski } __attribute__((packed));
98*f7915614SEugene (jno) Dvurechenski typedef struct ScsiCdbTestUnitReady ScsiCdbTestUnitReady;
99*f7915614SEugene (jno) Dvurechenski 
100*f7915614SEugene (jno) Dvurechenski struct ScsiCdbReportLuns {
101*f7915614SEugene (jno) Dvurechenski     uint8_t command;        /* =0xa0        */
102*f7915614SEugene (jno) Dvurechenski     uint8_t b1;
103*f7915614SEugene (jno) Dvurechenski     uint8_t select_report;  /* =0x02, "all" */
104*f7915614SEugene (jno) Dvurechenski     uint8_t b3_b5[3];
105*f7915614SEugene (jno) Dvurechenski     uint32_t alloc_len;
106*f7915614SEugene (jno) Dvurechenski     uint8_t b10;
107*f7915614SEugene (jno) Dvurechenski     uint8_t control;
108*f7915614SEugene (jno) Dvurechenski } __attribute__((packed));
109*f7915614SEugene (jno) Dvurechenski typedef struct ScsiCdbReportLuns ScsiCdbReportLuns;
110*f7915614SEugene (jno) Dvurechenski 
111*f7915614SEugene (jno) Dvurechenski struct ScsiLunReport {
112*f7915614SEugene (jno) Dvurechenski     uint32_t lun_list_len;
113*f7915614SEugene (jno) Dvurechenski     uint32_t b4_b7;
114*f7915614SEugene (jno) Dvurechenski     ScsiLun lun[1];   /* space for at least 1 lun must be allocated */
115*f7915614SEugene (jno) Dvurechenski } __attribute__((packed));
116*f7915614SEugene (jno) Dvurechenski typedef struct ScsiLunReport ScsiLunReport;
117*f7915614SEugene (jno) Dvurechenski 
118*f7915614SEugene (jno) Dvurechenski struct ScsiCdbReadCapacity16 {
119*f7915614SEugene (jno) Dvurechenski     uint8_t command;        /* =0x9e = "service action in 16"       */
120*f7915614SEugene (jno) Dvurechenski     uint8_t service_action; /* 5 bits, =0x10 = "read capacity 16"   */
121*f7915614SEugene (jno) Dvurechenski     uint64_t b2_b9;
122*f7915614SEugene (jno) Dvurechenski     uint32_t alloc_len;
123*f7915614SEugene (jno) Dvurechenski     uint8_t b14;
124*f7915614SEugene (jno) Dvurechenski     uint8_t control;
125*f7915614SEugene (jno) Dvurechenski } __attribute__((packed));
126*f7915614SEugene (jno) Dvurechenski typedef struct ScsiCdbReadCapacity16 ScsiCdbReadCapacity16;
127*f7915614SEugene (jno) Dvurechenski 
128*f7915614SEugene (jno) Dvurechenski struct ScsiReadCapacity16Data {
129*f7915614SEugene (jno) Dvurechenski     uint64_t ret_lba;             /* get it, 0..7     */
130*f7915614SEugene (jno) Dvurechenski     uint32_t lb_len;              /* bytes, 8..11     */
131*f7915614SEugene (jno) Dvurechenski     uint8_t u1[2 + 1 * 2 + 16];   /* b12..b31, unused */
132*f7915614SEugene (jno) Dvurechenski } __attribute__((packed));
133*f7915614SEugene (jno) Dvurechenski typedef struct ScsiReadCapacity16Data ScsiReadCapacity16Data;
134*f7915614SEugene (jno) Dvurechenski 
135*f7915614SEugene (jno) Dvurechenski static inline ScsiLun make_lun(uint16_t channel, uint16_t target, uint32_t lun)
136*f7915614SEugene (jno) Dvurechenski {
137*f7915614SEugene (jno) Dvurechenski     ScsiLun r = { .v64 = 0 };
138*f7915614SEugene (jno) Dvurechenski 
139*f7915614SEugene (jno) Dvurechenski     /* See QEMU code to choose the way to handle LUNs.
140*f7915614SEugene (jno) Dvurechenski      *
141*f7915614SEugene (jno) Dvurechenski      * So, a valid LUN must have (always channel #0):
142*f7915614SEugene (jno) Dvurechenski      *  lun[0] == 1
143*f7915614SEugene (jno) Dvurechenski      *  lun[1] - target, any value
144*f7915614SEugene (jno) Dvurechenski      *  lun[2] == 0 or (LUN, MSB, 0x40 set, 0x80 clear)
145*f7915614SEugene (jno) Dvurechenski      *  lun[3] - LUN, LSB, any value
146*f7915614SEugene (jno) Dvurechenski      */
147*f7915614SEugene (jno) Dvurechenski     r.v8[0] = 1;
148*f7915614SEugene (jno) Dvurechenski     r.v8[1] = target & 0xffU;
149*f7915614SEugene (jno) Dvurechenski     r.v8[2] = (lun >> 8) & 0x3fU;
150*f7915614SEugene (jno) Dvurechenski     if (r.v8[2]) {
151*f7915614SEugene (jno) Dvurechenski         r.v8[2] |= 0x40;
152*f7915614SEugene (jno) Dvurechenski     }
153*f7915614SEugene (jno) Dvurechenski     r.v8[3] = lun & 0xffU;
154*f7915614SEugene (jno) Dvurechenski 
155*f7915614SEugene (jno) Dvurechenski     return r;
156*f7915614SEugene (jno) Dvurechenski }
157*f7915614SEugene (jno) Dvurechenski 
158*f7915614SEugene (jno) Dvurechenski static inline const char *scsi_cdb_status_msg(uint8_t status)
159*f7915614SEugene (jno) Dvurechenski {
160*f7915614SEugene (jno) Dvurechenski     static char err_msg[] = "STATUS=XX";
161*f7915614SEugene (jno) Dvurechenski     uint8_t v = status & 0x3eU;
162*f7915614SEugene (jno) Dvurechenski 
163*f7915614SEugene (jno) Dvurechenski     fill_hex_val(err_msg + 7, &v, 1);
164*f7915614SEugene (jno) Dvurechenski     return err_msg;
165*f7915614SEugene (jno) Dvurechenski }
166*f7915614SEugene (jno) Dvurechenski 
167*f7915614SEugene (jno) Dvurechenski static inline const char *scsi_cdb_asc_msg(const void *s)
168*f7915614SEugene (jno) Dvurechenski {
169*f7915614SEugene (jno) Dvurechenski     static char err_msg[] = "RSPN=XX KEY=XX CODE=XX QLFR=XX";
170*f7915614SEugene (jno) Dvurechenski     const ScsiSense70 *p = s;
171*f7915614SEugene (jno) Dvurechenski     uint8_t sr = scsi_sense_response(s);
172*f7915614SEugene (jno) Dvurechenski     uint8_t sk = scsi_sense_key(s);
173*f7915614SEugene (jno) Dvurechenski     uint8_t ac = p->additional_sense_code;
174*f7915614SEugene (jno) Dvurechenski     uint8_t cq = p->additional_sense_code_qualifier;
175*f7915614SEugene (jno) Dvurechenski 
176*f7915614SEugene (jno) Dvurechenski     fill_hex_val(err_msg + 5, &sr, 1);
177*f7915614SEugene (jno) Dvurechenski     fill_hex_val(err_msg + 12, &sk, 1);
178*f7915614SEugene (jno) Dvurechenski     fill_hex_val(err_msg + 20, &ac, 1);
179*f7915614SEugene (jno) Dvurechenski     fill_hex_val(err_msg + 28, &cq, 1);
180*f7915614SEugene (jno) Dvurechenski 
181*f7915614SEugene (jno) Dvurechenski     return err_msg;
182*f7915614SEugene (jno) Dvurechenski }
183*f7915614SEugene (jno) Dvurechenski 
184*f7915614SEugene (jno) Dvurechenski #endif /* SCSI_H */
185