xref: /minix3/minix/drivers/usb/usb_storage/scsi.c (revision 2d64210c1dbcd340904718f2d4e9e81adeab3c7d)
1433d6423SLionel Sambuc /*
2433d6423SLionel Sambuc  * SCSI commands related implementation
3433d6423SLionel Sambuc  */
4433d6423SLionel Sambuc 
5433d6423SLionel Sambuc #include <minix/blockdriver.h>				/* SECTOR_SIZE */
6433d6423SLionel Sambuc 
7433d6423SLionel Sambuc #include <assert.h>
8433d6423SLionel Sambuc #include <string.h>					/* strncpy */
9433d6423SLionel Sambuc 
10433d6423SLionel Sambuc #include "common.h"
11433d6423SLionel Sambuc #include "scsi.h"
12433d6423SLionel Sambuc 
13433d6423SLionel Sambuc /*---------------------------*
14433d6423SLionel Sambuc  *    declared functions     *
15433d6423SLionel Sambuc  *---------------------------*/
16433d6423SLionel Sambuc /* To work correctly cbw->CBWCB must be zeroed before calling these: */
17433d6423SLionel Sambuc static int create_inquiry_scsi_cmd(mass_storage_cbw *);
18433d6423SLionel Sambuc static int create_test_scsi_cmd(mass_storage_cbw *);
19433d6423SLionel Sambuc static int create_read_capacity_scsi_cmd(mass_storage_cbw *);
20433d6423SLionel Sambuc static int create_write_scsi_cmd(mass_storage_cbw *, scsi_transfer *);
21433d6423SLionel Sambuc static int create_read_scsi_cmd(mass_storage_cbw *, scsi_transfer *);
22433d6423SLionel Sambuc static int create_mode_sense_scsi_cmd(mass_storage_cbw *);
23*2d64210cSWojciech Zajac static int create_request_sense_scsi_cmd(mass_storage_cbw *);
24433d6423SLionel Sambuc 
25433d6423SLionel Sambuc /*---------------------------*
26433d6423SLionel Sambuc  *    defined functions      *
27433d6423SLionel Sambuc  *---------------------------*/
28433d6423SLionel Sambuc /*===========================================================================*
29433d6423SLionel Sambuc  *    create_scsi_cmd                                                        *
30433d6423SLionel Sambuc  *===========================================================================*/
31433d6423SLionel Sambuc int
create_scsi_cmd(mass_storage_cbw * cbw,int cmd,scsi_transfer * info)32433d6423SLionel Sambuc create_scsi_cmd(mass_storage_cbw * cbw, int cmd, scsi_transfer * info)
33433d6423SLionel Sambuc {
34433d6423SLionel Sambuc 	MASS_DEBUG_DUMP;
35433d6423SLionel Sambuc 
36433d6423SLionel Sambuc 	assert(NULL != cbw);
37433d6423SLionel Sambuc 
38433d6423SLionel Sambuc 	switch (cmd) {
39433d6423SLionel Sambuc 		case SCSI_INQUIRY:
40433d6423SLionel Sambuc 			return create_inquiry_scsi_cmd(cbw);
41433d6423SLionel Sambuc 		case SCSI_TEST_UNIT_READY:
42433d6423SLionel Sambuc 			return create_test_scsi_cmd(cbw);
43433d6423SLionel Sambuc 		case SCSI_READ_CAPACITY:
44433d6423SLionel Sambuc 			return create_read_capacity_scsi_cmd(cbw);
45433d6423SLionel Sambuc 		case SCSI_WRITE:
46433d6423SLionel Sambuc 			return create_write_scsi_cmd(cbw, info);
47433d6423SLionel Sambuc 		case SCSI_READ:
48433d6423SLionel Sambuc 			return create_read_scsi_cmd(cbw, info);
49433d6423SLionel Sambuc 		case SCSI_MODE_SENSE:
50433d6423SLionel Sambuc 			return create_mode_sense_scsi_cmd(cbw);
51*2d64210cSWojciech Zajac 		case SCSI_REQUEST_SENSE:
52*2d64210cSWojciech Zajac 			return create_request_sense_scsi_cmd(cbw);
53433d6423SLionel Sambuc 		default:
54433d6423SLionel Sambuc 			MASS_MSG("Invalid SCSI command!");
55433d6423SLionel Sambuc 			return EXIT_FAILURE;
56433d6423SLionel Sambuc 	}
57433d6423SLionel Sambuc }
58433d6423SLionel Sambuc 
59433d6423SLionel Sambuc 
60433d6423SLionel Sambuc /*===========================================================================*
61433d6423SLionel Sambuc  *    create_inquiry_scsi_cmd                                                *
62433d6423SLionel Sambuc  *===========================================================================*/
63433d6423SLionel Sambuc static int
create_inquiry_scsi_cmd(mass_storage_cbw * cbw)64433d6423SLionel Sambuc create_inquiry_scsi_cmd(mass_storage_cbw * cbw)
65433d6423SLionel Sambuc {
66433d6423SLionel Sambuc 	MASS_DEBUG_DUMP;
67433d6423SLionel Sambuc 
68433d6423SLionel Sambuc 	cbw->dCBWDataTransferLength = SCSI_INQUIRY_DATA_LEN;
69433d6423SLionel Sambuc 	cbw->bCBWFlags = CBW_FLAGS_IN;
70433d6423SLionel Sambuc 	cbw->bCDBLength = SCSI_INQUIRY_CMD_LEN;
71433d6423SLionel Sambuc 
72433d6423SLionel Sambuc 	SCSI_SET_INQUIRY_OP_CODE(cbw->CBWCB);
73433d6423SLionel Sambuc 	SCSI_SET_INQUIRY_PAGE_CODE(cbw->CBWCB, 0);
74433d6423SLionel Sambuc 	SCSI_SET_INQUIRY_ALLOC_LEN(cbw->CBWCB, SCSI_INQUIRY_DATA_LEN);
75433d6423SLionel Sambuc 
76433d6423SLionel Sambuc 	return EXIT_SUCCESS;
77433d6423SLionel Sambuc }
78433d6423SLionel Sambuc 
79433d6423SLionel Sambuc 
80433d6423SLionel Sambuc /*===========================================================================*
81433d6423SLionel Sambuc  *    create_test_scsi_cmd                                                   *
82433d6423SLionel Sambuc  *===========================================================================*/
83433d6423SLionel Sambuc static int
create_test_scsi_cmd(mass_storage_cbw * cbw)84433d6423SLionel Sambuc create_test_scsi_cmd(mass_storage_cbw * cbw)
85433d6423SLionel Sambuc {
86433d6423SLionel Sambuc 	MASS_DEBUG_DUMP;
87433d6423SLionel Sambuc 
88433d6423SLionel Sambuc 	cbw->bCDBLength = SCSI_TEST_CMD_LEN;
89433d6423SLionel Sambuc 
90433d6423SLionel Sambuc 	SCSI_SET_TEST_OP_CODE(cbw->CBWCB);
91433d6423SLionel Sambuc 
92433d6423SLionel Sambuc 	return EXIT_SUCCESS;
93433d6423SLionel Sambuc }
94433d6423SLionel Sambuc 
95433d6423SLionel Sambuc 
96433d6423SLionel Sambuc /*===========================================================================*
97433d6423SLionel Sambuc  *    create_read_capacity_scsi_cmd                                          *
98433d6423SLionel Sambuc  *===========================================================================*/
99433d6423SLionel Sambuc static int
create_read_capacity_scsi_cmd(mass_storage_cbw * cbw)100433d6423SLionel Sambuc create_read_capacity_scsi_cmd(mass_storage_cbw * cbw)
101433d6423SLionel Sambuc {
102433d6423SLionel Sambuc 	MASS_DEBUG_DUMP;
103433d6423SLionel Sambuc 
104433d6423SLionel Sambuc 	cbw->dCBWDataTransferLength = SCSI_READ_CAPACITY_DATA_LEN;
105433d6423SLionel Sambuc 	cbw->bCBWFlags = CBW_FLAGS_IN;
106433d6423SLionel Sambuc 	cbw->bCDBLength = SCSI_READ_CAPACITY_CMD_LEN;
107433d6423SLionel Sambuc 
108433d6423SLionel Sambuc 	SCSI_SET_READ_CAPACITY_OP_CODE(cbw->CBWCB);
109433d6423SLionel Sambuc 	SCSI_SET_READ_CAPACITY_LBA(cbw->CBWCB, 0x00);
110433d6423SLionel Sambuc 
111433d6423SLionel Sambuc 	return EXIT_SUCCESS;
112433d6423SLionel Sambuc }
113433d6423SLionel Sambuc 
114433d6423SLionel Sambuc 
115433d6423SLionel Sambuc /*===========================================================================*
116433d6423SLionel Sambuc  *    create_write_scsi_cmd                                                  *
117433d6423SLionel Sambuc  *===========================================================================*/
118433d6423SLionel Sambuc static int
create_write_scsi_cmd(mass_storage_cbw * cbw,scsi_transfer * info)119433d6423SLionel Sambuc create_write_scsi_cmd(mass_storage_cbw * cbw, scsi_transfer * info)
120433d6423SLionel Sambuc {
121433d6423SLionel Sambuc 	MASS_DEBUG_DUMP;
122433d6423SLionel Sambuc 
123433d6423SLionel Sambuc 	assert(NULL != info);
124433d6423SLionel Sambuc 	assert(0 == (info->length % SECTOR_SIZE));
125433d6423SLionel Sambuc 
126433d6423SLionel Sambuc 	cbw->dCBWDataTransferLength = info->length;
127433d6423SLionel Sambuc 	cbw->bCBWFlags = CBW_FLAGS_OUT;
128433d6423SLionel Sambuc 	cbw->bCDBLength = SCSI_WRITE_CMD_LEN;
129433d6423SLionel Sambuc 
130433d6423SLionel Sambuc 	SCSI_SET_WRITE_OP_CODE(cbw->CBWCB);
131433d6423SLionel Sambuc 	SCSI_SET_WRITE_LBA(cbw->CBWCB, info->lba);
132433d6423SLionel Sambuc 	SCSI_SET_WRITE_BLEN(cbw->CBWCB, info->length / SECTOR_SIZE);
133433d6423SLionel Sambuc 
134433d6423SLionel Sambuc 	return EXIT_SUCCESS;
135433d6423SLionel Sambuc }
136433d6423SLionel Sambuc 
137433d6423SLionel Sambuc 
138433d6423SLionel Sambuc /*===========================================================================*
139433d6423SLionel Sambuc  *    create_read_scsi_cmd                                                   *
140433d6423SLionel Sambuc  *===========================================================================*/
141433d6423SLionel Sambuc static int
create_read_scsi_cmd(mass_storage_cbw * cbw,scsi_transfer * info)142433d6423SLionel Sambuc create_read_scsi_cmd(mass_storage_cbw * cbw, scsi_transfer * info)
143433d6423SLionel Sambuc {
144433d6423SLionel Sambuc 	MASS_DEBUG_DUMP;
145433d6423SLionel Sambuc 
146433d6423SLionel Sambuc 	assert(NULL != info);
147433d6423SLionel Sambuc 	assert(0 == (info->length % SECTOR_SIZE));
148433d6423SLionel Sambuc 
149433d6423SLionel Sambuc 	cbw->dCBWDataTransferLength = info->length;
150433d6423SLionel Sambuc 	cbw->bCBWFlags = CBW_FLAGS_IN;
151433d6423SLionel Sambuc 	cbw->bCDBLength = SCSI_READ_CMD_LEN;
152433d6423SLionel Sambuc 
153433d6423SLionel Sambuc 	SCSI_SET_READ_OP_CODE(cbw->CBWCB);
154433d6423SLionel Sambuc 	SCSI_SET_READ_LBA(cbw->CBWCB, info->lba);
155433d6423SLionel Sambuc 	SCSI_SET_READ_BLEN(cbw->CBWCB, info->length / SECTOR_SIZE);
156433d6423SLionel Sambuc 
157433d6423SLionel Sambuc 	return EXIT_SUCCESS;
158433d6423SLionel Sambuc }
159433d6423SLionel Sambuc 
160433d6423SLionel Sambuc 
161433d6423SLionel Sambuc /*===========================================================================*
162433d6423SLionel Sambuc  *    create_mode_sense_scsi_cmd                                             *
163433d6423SLionel Sambuc  *===========================================================================*/
164433d6423SLionel Sambuc static int
create_mode_sense_scsi_cmd(mass_storage_cbw * cbw)165433d6423SLionel Sambuc create_mode_sense_scsi_cmd(mass_storage_cbw * cbw)
166433d6423SLionel Sambuc {
167433d6423SLionel Sambuc 	MASS_DEBUG_DUMP;
168433d6423SLionel Sambuc 
169433d6423SLionel Sambuc 	cbw->dCBWDataTransferLength = SCSI_MODE_SENSE_FLEX_DATA_LEN;
170433d6423SLionel Sambuc 	cbw->bCBWFlags = CBW_FLAGS_IN;
171433d6423SLionel Sambuc 	cbw->bCDBLength = SCSI_MODE_SENSE_CMD_LEN;
172433d6423SLionel Sambuc 
173433d6423SLionel Sambuc 	SCSI_SET_MODE_SENSE_OP_CODE(cbw->CBWCB);
174433d6423SLionel Sambuc 	SCSI_SET_MODE_SENSE_PAGE_CODE(cbw->CBWCB,
175433d6423SLionel Sambuc 					SCSI_MODE_SENSE_FLEXIBLE_DISK_PAGE);
176433d6423SLionel Sambuc 
177433d6423SLionel Sambuc 	return EXIT_SUCCESS;
178433d6423SLionel Sambuc }
179433d6423SLionel Sambuc 
180433d6423SLionel Sambuc 
181433d6423SLionel Sambuc /*===========================================================================*
182*2d64210cSWojciech Zajac  *    create_request_sense_scsi_cmd                                          *
183*2d64210cSWojciech Zajac  *===========================================================================*/
184*2d64210cSWojciech Zajac static int
create_request_sense_scsi_cmd(mass_storage_cbw * cbw)185*2d64210cSWojciech Zajac create_request_sense_scsi_cmd(mass_storage_cbw * cbw)
186*2d64210cSWojciech Zajac {
187*2d64210cSWojciech Zajac 	MASS_DEBUG_DUMP;
188*2d64210cSWojciech Zajac 
189*2d64210cSWojciech Zajac 	cbw->dCBWDataTransferLength = SCSI_REQUEST_SENSE_DATA_LEN;
190*2d64210cSWojciech Zajac 	cbw->bCBWFlags = CBW_FLAGS_IN;
191*2d64210cSWojciech Zajac 	cbw->bCDBLength = SCSI_REQUEST_SENSE_CMD_LEN;
192*2d64210cSWojciech Zajac 
193*2d64210cSWojciech Zajac 	SCSI_SET_REQUEST_SENSE_OP_CODE(cbw->CBWCB);
194*2d64210cSWojciech Zajac 	SCSI_SET_REQUEST_SENSE_ALLOC(cbw->CBWCB, SCSI_REQUEST_SENSE_DATA_LEN);
195*2d64210cSWojciech Zajac 
196*2d64210cSWojciech Zajac 	return EXIT_SUCCESS;
197*2d64210cSWojciech Zajac }
198*2d64210cSWojciech Zajac 
199*2d64210cSWojciech Zajac 
200*2d64210cSWojciech Zajac /*===========================================================================*
201433d6423SLionel Sambuc  *    check_inquiry_reply                                                    *
202433d6423SLionel Sambuc  *===========================================================================*/
203433d6423SLionel Sambuc int
check_inquiry_reply(uint8_t * scsi_reply)204433d6423SLionel Sambuc check_inquiry_reply(uint8_t * scsi_reply)
205433d6423SLionel Sambuc {
206433d6423SLionel Sambuc 	char vendor_name[SCSI_INQUIRY_VENDOR_NAME_LEN + 1];
207433d6423SLionel Sambuc 	char product_name[SCSI_INQUIRY_PRODUCT_NAME_LEN + 1];
208433d6423SLionel Sambuc 
209433d6423SLionel Sambuc 	MASS_DEBUG_DUMP;
210433d6423SLionel Sambuc 
211433d6423SLionel Sambuc 	/* Stop condition for printing as strncpy() does not add it */
212433d6423SLionel Sambuc 	vendor_name[SCSI_INQUIRY_VENDOR_NAME_LEN] = '\0';
213433d6423SLionel Sambuc 	product_name[SCSI_INQUIRY_PRODUCT_NAME_LEN] = '\0';
214433d6423SLionel Sambuc 
215433d6423SLionel Sambuc 	if (SCSI_GET_INQUIRY_PERIPH_QUALIF(scsi_reply)) {
216433d6423SLionel Sambuc 		MASS_MSG("Device not connected");
217433d6423SLionel Sambuc 		return EXIT_FAILURE;
218433d6423SLionel Sambuc 	}
219433d6423SLionel Sambuc 
220433d6423SLionel Sambuc 	strncpy(vendor_name, SCSI_GET_INQUIRY_VENDOR_NAME(scsi_reply),
221433d6423SLionel Sambuc 		SCSI_INQUIRY_VENDOR_NAME_LEN);
222433d6423SLionel Sambuc 	strncpy(product_name, SCSI_GET_INQUIRY_PRODUCT_NAME(scsi_reply),
223433d6423SLionel Sambuc 		SCSI_INQUIRY_PRODUCT_NAME_LEN);
224433d6423SLionel Sambuc 
225433d6423SLionel Sambuc 	MASS_DEBUG_MSG("Vendor name: %s", vendor_name);
226433d6423SLionel Sambuc 	MASS_DEBUG_MSG("Product name %s", product_name);
227433d6423SLionel Sambuc 
228433d6423SLionel Sambuc 	return EXIT_SUCCESS;
229433d6423SLionel Sambuc }
230433d6423SLionel Sambuc 
231433d6423SLionel Sambuc 
232433d6423SLionel Sambuc /*===========================================================================*
233433d6423SLionel Sambuc  *    check_read_capacity_reply                                              *
234433d6423SLionel Sambuc  *===========================================================================*/
235433d6423SLionel Sambuc int
check_read_capacity_reply(uint8_t * scsi_reply,uint32_t * lba,uint32_t * blen)236433d6423SLionel Sambuc check_read_capacity_reply(uint8_t * scsi_reply, uint32_t * lba, uint32_t * blen)
237433d6423SLionel Sambuc {
238433d6423SLionel Sambuc 	MASS_DEBUG_DUMP;
239433d6423SLionel Sambuc 
240433d6423SLionel Sambuc 	*lba = SCSI_GET_READ_CAPACITY_LBA(scsi_reply);
241433d6423SLionel Sambuc 	*blen = SCSI_GET_READ_CAPACITY_BLEN(scsi_reply);
242433d6423SLionel Sambuc 
243433d6423SLionel Sambuc 	return EXIT_SUCCESS;
244433d6423SLionel Sambuc }
245433d6423SLionel Sambuc 
246433d6423SLionel Sambuc 
247433d6423SLionel Sambuc /*===========================================================================*
248433d6423SLionel Sambuc  *    check_mode_sense_reply                                                 *
249433d6423SLionel Sambuc  *===========================================================================*/
250433d6423SLionel Sambuc int
check_mode_sense_reply(uint8_t * scsi_reply,unsigned * cyl,unsigned * head,unsigned * sect)251433d6423SLionel Sambuc check_mode_sense_reply(uint8_t * scsi_reply, unsigned * cyl,
252433d6423SLionel Sambuc 			unsigned * head, unsigned * sect)
253433d6423SLionel Sambuc {
254433d6423SLionel Sambuc 	MASS_DEBUG_DUMP;
255433d6423SLionel Sambuc 
256433d6423SLionel Sambuc 	*cyl = SCSI_GET_MODE_SENSE_CYLINDERS(scsi_reply);
257433d6423SLionel Sambuc 	*head = SCSI_GET_MODE_SENSE_HEADS(scsi_reply);
258433d6423SLionel Sambuc 	*sect = SCSI_GET_MODE_SENSE_SECTORS(scsi_reply);
259433d6423SLionel Sambuc 
260433d6423SLionel Sambuc 	return EXIT_SUCCESS;
261433d6423SLionel Sambuc }
262433d6423SLionel Sambuc 
263433d6423SLionel Sambuc 
264433d6423SLionel Sambuc /*===========================================================================*
265433d6423SLionel Sambuc  *    check_csw                                                              *
266433d6423SLionel Sambuc  *===========================================================================*/
267433d6423SLionel Sambuc int
check_csw(mass_storage_csw * csw,unsigned int tag)268433d6423SLionel Sambuc check_csw(mass_storage_csw * csw, unsigned int tag)
269433d6423SLionel Sambuc {
270433d6423SLionel Sambuc 	MASS_DEBUG_DUMP;
271433d6423SLionel Sambuc 
272433d6423SLionel Sambuc 	if (csw->dCSWTag != tag) {
273433d6423SLionel Sambuc 		MASS_MSG("CSW tag mismatch!");
274433d6423SLionel Sambuc 		return EXIT_FAILURE;
275433d6423SLionel Sambuc 	}
276433d6423SLionel Sambuc 
277433d6423SLionel Sambuc 	if (CSW_SIGNATURE != csw->dCSWSignature) {
278433d6423SLionel Sambuc 		MASS_MSG("CSW signature mismatch!");
279433d6423SLionel Sambuc 		return EXIT_FAILURE;
280433d6423SLionel Sambuc 	}
281433d6423SLionel Sambuc 
282433d6423SLionel Sambuc 	if (CSW_STATUS_GOOD != csw->bCSWStatus) {
283433d6423SLionel Sambuc 		MASS_MSG("CSW status error (0x%02X)!", csw->bCSWStatus);
284433d6423SLionel Sambuc 		return EXIT_FAILURE;
285433d6423SLionel Sambuc 	}
286433d6423SLionel Sambuc 
287433d6423SLionel Sambuc 	return EXIT_SUCCESS;
288433d6423SLionel Sambuc }
289