xref: /minix/minix/drivers/usb/usb_storage/scsi.c (revision 00b67f09)
1 /*
2  * SCSI commands related implementation
3  */
4 
5 #include <minix/blockdriver.h>				/* SECTOR_SIZE */
6 
7 #include <assert.h>
8 #include <string.h>					/* strncpy */
9 
10 #include "common.h"
11 #include "scsi.h"
12 
13 /*---------------------------*
14  *    declared functions     *
15  *---------------------------*/
16 /* To work correctly cbw->CBWCB must be zeroed before calling these: */
17 static int create_inquiry_scsi_cmd(mass_storage_cbw *);
18 static int create_test_scsi_cmd(mass_storage_cbw *);
19 static int create_read_capacity_scsi_cmd(mass_storage_cbw *);
20 static int create_write_scsi_cmd(mass_storage_cbw *, scsi_transfer *);
21 static int create_read_scsi_cmd(mass_storage_cbw *, scsi_transfer *);
22 static int create_mode_sense_scsi_cmd(mass_storage_cbw *);
23 static int create_request_sense_scsi_cmd(mass_storage_cbw *);
24 
25 /*---------------------------*
26  *    defined functions      *
27  *---------------------------*/
28 /*===========================================================================*
29  *    create_scsi_cmd                                                        *
30  *===========================================================================*/
31 int
32 create_scsi_cmd(mass_storage_cbw * cbw, int cmd, scsi_transfer * info)
33 {
34 	MASS_DEBUG_DUMP;
35 
36 	assert(NULL != cbw);
37 
38 	switch (cmd) {
39 		case SCSI_INQUIRY:
40 			return create_inquiry_scsi_cmd(cbw);
41 		case SCSI_TEST_UNIT_READY:
42 			return create_test_scsi_cmd(cbw);
43 		case SCSI_READ_CAPACITY:
44 			return create_read_capacity_scsi_cmd(cbw);
45 		case SCSI_WRITE:
46 			return create_write_scsi_cmd(cbw, info);
47 		case SCSI_READ:
48 			return create_read_scsi_cmd(cbw, info);
49 		case SCSI_MODE_SENSE:
50 			return create_mode_sense_scsi_cmd(cbw);
51 		case SCSI_REQUEST_SENSE:
52 			return create_request_sense_scsi_cmd(cbw);
53 		default:
54 			MASS_MSG("Invalid SCSI command!");
55 			return EXIT_FAILURE;
56 	}
57 }
58 
59 
60 /*===========================================================================*
61  *    create_inquiry_scsi_cmd                                                *
62  *===========================================================================*/
63 static int
64 create_inquiry_scsi_cmd(mass_storage_cbw * cbw)
65 {
66 	MASS_DEBUG_DUMP;
67 
68 	cbw->dCBWDataTransferLength = SCSI_INQUIRY_DATA_LEN;
69 	cbw->bCBWFlags = CBW_FLAGS_IN;
70 	cbw->bCDBLength = SCSI_INQUIRY_CMD_LEN;
71 
72 	SCSI_SET_INQUIRY_OP_CODE(cbw->CBWCB);
73 	SCSI_SET_INQUIRY_PAGE_CODE(cbw->CBWCB, 0);
74 	SCSI_SET_INQUIRY_ALLOC_LEN(cbw->CBWCB, SCSI_INQUIRY_DATA_LEN);
75 
76 	return EXIT_SUCCESS;
77 }
78 
79 
80 /*===========================================================================*
81  *    create_test_scsi_cmd                                                   *
82  *===========================================================================*/
83 static int
84 create_test_scsi_cmd(mass_storage_cbw * cbw)
85 {
86 	MASS_DEBUG_DUMP;
87 
88 	cbw->bCDBLength = SCSI_TEST_CMD_LEN;
89 
90 	SCSI_SET_TEST_OP_CODE(cbw->CBWCB);
91 
92 	return EXIT_SUCCESS;
93 }
94 
95 
96 /*===========================================================================*
97  *    create_read_capacity_scsi_cmd                                          *
98  *===========================================================================*/
99 static int
100 create_read_capacity_scsi_cmd(mass_storage_cbw * cbw)
101 {
102 	MASS_DEBUG_DUMP;
103 
104 	cbw->dCBWDataTransferLength = SCSI_READ_CAPACITY_DATA_LEN;
105 	cbw->bCBWFlags = CBW_FLAGS_IN;
106 	cbw->bCDBLength = SCSI_READ_CAPACITY_CMD_LEN;
107 
108 	SCSI_SET_READ_CAPACITY_OP_CODE(cbw->CBWCB);
109 	SCSI_SET_READ_CAPACITY_LBA(cbw->CBWCB, 0x00);
110 
111 	return EXIT_SUCCESS;
112 }
113 
114 
115 /*===========================================================================*
116  *    create_write_scsi_cmd                                                  *
117  *===========================================================================*/
118 static int
119 create_write_scsi_cmd(mass_storage_cbw * cbw, scsi_transfer * info)
120 {
121 	MASS_DEBUG_DUMP;
122 
123 	assert(NULL != info);
124 	assert(0 == (info->length % SECTOR_SIZE));
125 
126 	cbw->dCBWDataTransferLength = info->length;
127 	cbw->bCBWFlags = CBW_FLAGS_OUT;
128 	cbw->bCDBLength = SCSI_WRITE_CMD_LEN;
129 
130 	SCSI_SET_WRITE_OP_CODE(cbw->CBWCB);
131 	SCSI_SET_WRITE_LBA(cbw->CBWCB, info->lba);
132 	SCSI_SET_WRITE_BLEN(cbw->CBWCB, info->length / SECTOR_SIZE);
133 
134 	return EXIT_SUCCESS;
135 }
136 
137 
138 /*===========================================================================*
139  *    create_read_scsi_cmd                                                   *
140  *===========================================================================*/
141 static int
142 create_read_scsi_cmd(mass_storage_cbw * cbw, scsi_transfer * info)
143 {
144 	MASS_DEBUG_DUMP;
145 
146 	assert(NULL != info);
147 	assert(0 == (info->length % SECTOR_SIZE));
148 
149 	cbw->dCBWDataTransferLength = info->length;
150 	cbw->bCBWFlags = CBW_FLAGS_IN;
151 	cbw->bCDBLength = SCSI_READ_CMD_LEN;
152 
153 	SCSI_SET_READ_OP_CODE(cbw->CBWCB);
154 	SCSI_SET_READ_LBA(cbw->CBWCB, info->lba);
155 	SCSI_SET_READ_BLEN(cbw->CBWCB, info->length / SECTOR_SIZE);
156 
157 	return EXIT_SUCCESS;
158 }
159 
160 
161 /*===========================================================================*
162  *    create_mode_sense_scsi_cmd                                             *
163  *===========================================================================*/
164 static int
165 create_mode_sense_scsi_cmd(mass_storage_cbw * cbw)
166 {
167 	MASS_DEBUG_DUMP;
168 
169 	cbw->dCBWDataTransferLength = SCSI_MODE_SENSE_FLEX_DATA_LEN;
170 	cbw->bCBWFlags = CBW_FLAGS_IN;
171 	cbw->bCDBLength = SCSI_MODE_SENSE_CMD_LEN;
172 
173 	SCSI_SET_MODE_SENSE_OP_CODE(cbw->CBWCB);
174 	SCSI_SET_MODE_SENSE_PAGE_CODE(cbw->CBWCB,
175 					SCSI_MODE_SENSE_FLEXIBLE_DISK_PAGE);
176 
177 	return EXIT_SUCCESS;
178 }
179 
180 
181 /*===========================================================================*
182  *    create_request_sense_scsi_cmd                                          *
183  *===========================================================================*/
184 static int
185 create_request_sense_scsi_cmd(mass_storage_cbw * cbw)
186 {
187 	MASS_DEBUG_DUMP;
188 
189 	cbw->dCBWDataTransferLength = SCSI_REQUEST_SENSE_DATA_LEN;
190 	cbw->bCBWFlags = CBW_FLAGS_IN;
191 	cbw->bCDBLength = SCSI_REQUEST_SENSE_CMD_LEN;
192 
193 	SCSI_SET_REQUEST_SENSE_OP_CODE(cbw->CBWCB);
194 	SCSI_SET_REQUEST_SENSE_ALLOC(cbw->CBWCB, SCSI_REQUEST_SENSE_DATA_LEN);
195 
196 	return EXIT_SUCCESS;
197 }
198 
199 
200 /*===========================================================================*
201  *    check_inquiry_reply                                                    *
202  *===========================================================================*/
203 int
204 check_inquiry_reply(uint8_t * scsi_reply)
205 {
206 	char vendor_name[SCSI_INQUIRY_VENDOR_NAME_LEN + 1];
207 	char product_name[SCSI_INQUIRY_PRODUCT_NAME_LEN + 1];
208 
209 	MASS_DEBUG_DUMP;
210 
211 	/* Stop condition for printing as strncpy() does not add it */
212 	vendor_name[SCSI_INQUIRY_VENDOR_NAME_LEN] = '\0';
213 	product_name[SCSI_INQUIRY_PRODUCT_NAME_LEN] = '\0';
214 
215 	if (SCSI_GET_INQUIRY_PERIPH_QUALIF(scsi_reply)) {
216 		MASS_MSG("Device not connected");
217 		return EXIT_FAILURE;
218 	}
219 
220 	strncpy(vendor_name, SCSI_GET_INQUIRY_VENDOR_NAME(scsi_reply),
221 		SCSI_INQUIRY_VENDOR_NAME_LEN);
222 	strncpy(product_name, SCSI_GET_INQUIRY_PRODUCT_NAME(scsi_reply),
223 		SCSI_INQUIRY_PRODUCT_NAME_LEN);
224 
225 	MASS_DEBUG_MSG("Vendor name: %s", vendor_name);
226 	MASS_DEBUG_MSG("Product name %s", product_name);
227 
228 	return EXIT_SUCCESS;
229 }
230 
231 
232 /*===========================================================================*
233  *    check_read_capacity_reply                                              *
234  *===========================================================================*/
235 int
236 check_read_capacity_reply(uint8_t * scsi_reply, uint32_t * lba, uint32_t * blen)
237 {
238 	MASS_DEBUG_DUMP;
239 
240 	*lba = SCSI_GET_READ_CAPACITY_LBA(scsi_reply);
241 	*blen = SCSI_GET_READ_CAPACITY_BLEN(scsi_reply);
242 
243 	return EXIT_SUCCESS;
244 }
245 
246 
247 /*===========================================================================*
248  *    check_mode_sense_reply                                                 *
249  *===========================================================================*/
250 int
251 check_mode_sense_reply(uint8_t * scsi_reply, unsigned * cyl,
252 			unsigned * head, unsigned * sect)
253 {
254 	MASS_DEBUG_DUMP;
255 
256 	*cyl = SCSI_GET_MODE_SENSE_CYLINDERS(scsi_reply);
257 	*head = SCSI_GET_MODE_SENSE_HEADS(scsi_reply);
258 	*sect = SCSI_GET_MODE_SENSE_SECTORS(scsi_reply);
259 
260 	return EXIT_SUCCESS;
261 }
262 
263 
264 /*===========================================================================*
265  *    check_csw                                                              *
266  *===========================================================================*/
267 int
268 check_csw(mass_storage_csw * csw, unsigned int tag)
269 {
270 	MASS_DEBUG_DUMP;
271 
272 	if (csw->dCSWTag != tag) {
273 		MASS_MSG("CSW tag mismatch!");
274 		return EXIT_FAILURE;
275 	}
276 
277 	if (CSW_SIGNATURE != csw->dCSWSignature) {
278 		MASS_MSG("CSW signature mismatch!");
279 		return EXIT_FAILURE;
280 	}
281 
282 	if (CSW_STATUS_GOOD != csw->bCSWStatus) {
283 		MASS_MSG("CSW status error (0x%02X)!", csw->bCSWStatus);
284 		return EXIT_FAILURE;
285 	}
286 
287 	return EXIT_SUCCESS;
288 }
289