1/*
2 * Copyright 2017, Data61
3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO)
4 * ABN 41 687 119 230.
5 *
6 * This software may be distributed and modified according to the terms of
7 * the BSD 2-Clause license. Note that NO WARRANTY is provided.
8 * See "LICENSE_BSD2.txt" for details.
9 *
10 * @TAG(DATA61_BSD)
11 */
12
13/**
14 * @brief UFI Command implementation for USB Mass Storage Class
15 * @see USB Mass Storage Class UFI Command Spec
16 */
17#include <platsupport/delay.h>
18#include <string.h>
19#include <usb/drivers/ufi.h>
20
21#include "storage.h"
22
23/* Operation Code */
24#define TEST_UNIT_READY    0x00
25#define REZERO_UNIT        0x01
26#define REQUEST_SENSE      0x03
27#define FORMAT_UNIT        0x04
28
29#define INQUIRY            0x12
30#define START_STOP         0x1B
31#define SEND_DIAGNOSTIC    0x1D
32#define ALLOW_REMOVAL      0x1E
33
34#define READ_FORMAT_CAP    0x23
35#define READ_CAPACITY      0x25
36#define READ_10            0x28
37#define WRITE_10           0x2A
38#define SEEK               0x2B
39#define WRITE_VERIFY       0x2E
40#define VERIFY             0x2F
41
42#define MODE_SELECT        0x55
43#define MODE_SENSE         0x5A
44#define READ_12            0xA8
45#define WRITE_12           0xAA
46
47
48#define UFI_OUTPUT  0
49#define UFI_INPUT   1
50
51#define UFI_LBA_SHF   16
52#define UFI_SENSE_LEN 18
53#define UFI_INQ_LEN   36
54#define UFI_MODE_SENSE_LEN 192
55#define UFI_MODE_PAGE_ALL 0x3F
56#define UFI_BLK_SIZE  512
57
58/* Command Descriptor Block */
59struct ufi_cdb {
60	uint8_t opcode;
61	uint8_t lun;
62	uint32_t lba;
63	uint32_t length;
64	uint16_t reserved;
65} __attribute__((packed));
66
67static void ufi_format_unit()
68{
69	ZF_LOGF("Not implemented\n");
70}
71
72static void ufi_test_unit_ready(usb_dev_t *udev)
73{
74	int err;
75	struct ufi_cdb cdb;
76
77	memset(&cdb, 0, sizeof(struct ufi_cdb));
78
79	/* Fill in the command */
80	cdb.opcode = TEST_UNIT_READY;
81
82	err = usb_storage_xfer(udev, &cdb, sizeof(struct ufi_cdb),
83			NULL, 0, UFI_OUTPUT);
84	if (err) {
85		ZF_LOGF("Transfer error\n");
86	}
87}
88
89static void ufi_request_sense(usb_dev_t *udev)
90{
91	int err;
92	struct ufi_cdb cdb;
93	struct xact data;
94
95	memset(&cdb, 0, sizeof(struct ufi_cdb));
96
97	/* Fill in the command */
98	cdb.opcode = REQUEST_SENSE;
99	cdb.lba = UFI_SENSE_LEN << UFI_LBA_SHF;
100
101	data.type = PID_IN;
102	data.len = UFI_SENSE_LEN;
103	err = usb_alloc_xact(udev->dman, &data, 1);
104	if (err) {
105		ZF_LOGF("Out of DMA memory\n");
106	}
107	err = usb_storage_xfer(udev, &cdb, sizeof(struct ufi_cdb),
108			&data, 1, UFI_INPUT);
109	if (err) {
110		ZF_LOGF("Transfer error\n");
111	}
112	usb_destroy_xact(udev->dman, &data, 1);
113}
114
115static void ufi_inquiry(usb_dev_t *udev)
116{
117	int err;
118	struct ufi_cdb cdb;
119	struct xact data;
120
121	memset(&cdb, 0, sizeof(struct ufi_cdb));
122
123	/* Inquiry UFI disk */
124	cdb.opcode = INQUIRY;
125	cdb.lba = UFI_INQ_LEN << UFI_LBA_SHF;
126
127	data.type = PID_IN;
128	data.len = UFI_INQ_LEN;
129	err = usb_alloc_xact(udev->dman, &data, 1);
130	if (err) {
131		ZF_LOGF("Out of DMA memory\n");
132	}
133
134	err = usb_storage_xfer(udev, &cdb, sizeof(struct ufi_cdb),
135			&data, 1, UFI_INPUT);
136	if (err) {
137		ZF_LOGF("Transfer error\n");
138	}
139
140	usb_destroy_xact(udev->dman, &data, 1);
141}
142
143static void ufi_prevent_allow_medium_removal(usb_dev_t *udev, int enable)
144{
145	int err;
146	struct ufi_cdb cdb;
147
148	memset(&cdb, 0, sizeof(struct ufi_cdb));
149
150	cdb.opcode = ALLOW_REMOVAL;
151	cdb.lba = enable << 8;
152
153	err = usb_storage_xfer(udev, &cdb, sizeof(struct ufi_cdb),
154			NULL, 0, UFI_OUTPUT);
155	if (err) {
156		ZF_LOGF("Transfer error\n");
157	}
158}
159
160uint32_t ufi_read_capacity(usb_dev_t *udev)
161{
162	int err;
163	uint32_t ret;
164	struct ufi_cdb cdb;
165	struct xact data;
166
167	memset(&cdb, 0, sizeof(struct ufi_cdb));
168
169	cdb.opcode = READ_CAPACITY;
170
171	data.type = PID_IN;
172	data.len = 8;
173	err = usb_alloc_xact(udev->dman, &data, 1);
174	if (err) {
175		ZF_LOGF("Out of DMA memory\n");
176	}
177
178	err = usb_storage_xfer(udev, &cdb, sizeof(struct ufi_cdb),
179				&data, 1, UFI_INPUT);
180	if (err) {
181		ZF_LOGF("Transfer error\n");
182	}
183
184	ret = *(uint32_t*)data.vaddr;
185	usb_destroy_xact(udev->dman, &data, 1);
186
187	return ret;
188}
189
190static void ufi_mode_sense(usb_dev_t *udev)
191{
192	int err;
193	struct ufi_cdb cdb;
194	struct xact data;
195
196	memset(&cdb, 0, sizeof(struct ufi_cdb));
197
198	cdb.opcode = MODE_SENSE;
199	cdb.lba = UFI_MODE_PAGE_ALL;
200	cdb.length = UFI_MODE_SENSE_LEN << UFI_LBA_SHF;
201
202	data.type = PID_IN;
203	data.len = UFI_MODE_SENSE_LEN;
204	err = usb_alloc_xact(udev->dman, &data, 1);
205	if (err) {
206		ZF_LOGF("Out of DMA memory\n");
207	}
208
209	err = usb_storage_xfer(udev, &cdb, sizeof(struct ufi_cdb),
210				&data, 1, UFI_INPUT);
211	if (err) {
212		ZF_LOGF("Transfer error\n");
213	}
214
215	usb_destroy_xact(udev->dman, &data, 1);
216}
217
218static void ufi_read10(usb_dev_t *udev, uint32_t lba, uint16_t count)
219{
220	int err;
221	struct ufi_cdb cdb;
222	struct xact data;
223
224	memset(&cdb, 0, sizeof(struct ufi_cdb));
225
226	cdb.opcode = READ_10;
227	cdb.lba = __builtin_bswap32(lba);
228	cdb.length = __builtin_bswap16(count) << 8;
229
230	data.type = PID_IN;
231	data.len = UFI_BLK_SIZE * count;
232
233	err = usb_alloc_xact(udev->dman, &data, 1);
234	if (err) {
235		ZF_LOGF("Out of DMA memory\n");
236	}
237
238	err = usb_storage_xfer(udev, &cdb, sizeof(struct ufi_cdb),
239				&data, 1, UFI_INPUT);
240	if (err) {
241		ZF_LOGF("Transfer error\n");
242	}
243
244	usb_destroy_xact(udev->dman, &data, 1);
245}
246
247static void ufi_read12(usb_dev_t *udev, uint32_t lba, uint32_t count)
248{
249	int err;
250	struct ufi_cdb cdb;
251	struct xact data;
252
253	memset(&cdb, 0, sizeof(struct ufi_cdb));
254
255	cdb.opcode = READ_12;
256	cdb.lba = __builtin_bswap32(lba);
257	cdb.length = __builtin_bswap16(count);
258
259	data.type = PID_IN;
260	data.len = UFI_BLK_SIZE * count;
261
262	err = usb_alloc_xact(udev->dman, &data, 1);
263	if (err) {
264		ZF_LOGF("Out of DMA memory\n");
265	}
266
267	err = usb_storage_xfer(udev, &cdb, sizeof(struct ufi_cdb),
268				&data, 1, UFI_INPUT);
269	if (err) {
270		ZF_LOGF("Transfer error\n");
271	}
272
273	usb_destroy_xact(udev->dman, &data, 1);
274}
275
276int
277ufi_init_disk(usb_dev_t *udev)
278{
279	usb_storage_bind(udev);
280
281	ufi_inquiry(udev);
282	ufi_test_unit_ready(udev);
283
284	ufi_request_sense(udev);
285	ufi_test_unit_ready(udev);
286
287	ufi_read_capacity(udev);
288	ufi_mode_sense(udev);
289	ufi_test_unit_ready(udev);
290
291	ufi_prevent_allow_medium_removal(udev, 0);
292	ufi_request_sense(udev);
293	ufi_test_unit_ready(udev);
294
295	return 0;
296}
297
298