ustorage_fs.c revision 192984
1184610Salfred/* $FreeBSD: head/sys/dev/usb/storage/ustorage_fs.c 192984 2009-05-28 17:36:36Z thompsa $ */
2184610Salfred/*-
3184610Salfred * Copyright (C) 2003-2005 Alan Stern
4184610Salfred * Copyright (C) 2008 Hans Petter Selasky
5184610Salfred * All rights reserved.
6184610Salfred *
7184610Salfred * Redistribution and use in source and binary forms, with or without
8184610Salfred * modification, are permitted provided that the following conditions
9184610Salfred * are met:
10184610Salfred * 1. Redistributions of source code must retain the above copyright
11184610Salfred *    notice, this list of conditions, and the following disclaimer,
12184610Salfred *    without modification.
13184610Salfred * 2. Redistributions in binary form must reproduce the above copyright
14184610Salfred *    notice, this list of conditions and the following disclaimer in the
15184610Salfred *    documentation and/or other materials provided with the distribution.
16184610Salfred * 3. The names of the above-listed copyright holders may not be used
17184610Salfred *    to endorse or promote products derived from this software without
18184610Salfred *    specific prior written permission.
19184610Salfred *
20184610Salfred *
21184610Salfred * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
22184610Salfred * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
23184610Salfred * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24184610Salfred * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
25184610Salfred * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26184610Salfred * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27184610Salfred * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
28184610Salfred * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29184610Salfred * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30184610Salfred * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31184610Salfred * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32184610Salfred */
33184610Salfred
34184610Salfred/*
35184610Salfred * NOTE: Much of the SCSI statemachine handling code derives from the
36184610Salfred * Linux USB gadget stack.
37184610Salfred */
38188746Sthompsa#include "usbdevs.h"
39188942Sthompsa#include <dev/usb/usb.h>
40188942Sthompsa#include <dev/usb/usb_mfunc.h>
41188942Sthompsa#include <dev/usb/usb_error.h>
42184610Salfred
43184610Salfred#define	USB_DEBUG_VAR ustorage_fs_debug
44184610Salfred
45188942Sthompsa#include <dev/usb/usb_core.h>
46188942Sthompsa#include <dev/usb/usb_util.h>
47188942Sthompsa#include <dev/usb/usb_busdma.h>
48188942Sthompsa#include <dev/usb/usb_debug.h>
49188942Sthompsa#include <dev/usb/usb_process.h>
50188942Sthompsa#include <dev/usb/usb_device.h>
51184610Salfred
52184610Salfred#if USB_DEBUG
53184610Salfredstatic int ustorage_fs_debug = 0;
54184610Salfred
55192502SthompsaSYSCTL_NODE(_hw_usb, OID_AUTO, ustorage_fs, CTLFLAG_RW, 0, "USB ustorage_fs");
56192502SthompsaSYSCTL_INT(_hw_usb_ustorage_fs, OID_AUTO, debug, CTLFLAG_RW,
57184610Salfred    &ustorage_fs_debug, 0, "ustorage_fs debug level");
58184610Salfred#endif
59184610Salfred
60184610Salfred/* Define some limits */
61184610Salfred
62190181Sthompsa#ifndef USTORAGE_FS_BULK_SIZE
63190719Sthompsa#define	USTORAGE_FS_BULK_SIZE (1UL << 17)	/* bytes */
64190181Sthompsa#endif
65184610Salfred
66190733Sthompsa#ifndef	USTORAGE_FS_MAX_LUN
67190733Sthompsa#define	USTORAGE_FS_MAX_LUN	8	/* units */
68190733Sthompsa#endif
69190181Sthompsa
70190733Sthompsa#ifndef USTORAGE_QDATA_MAX
71190733Sthompsa#define	USTORAGE_QDATA_MAX	40	/* bytes */
72190733Sthompsa#endif
73190733Sthompsa
74190733Sthompsa#define sc_cmd_data sc_cbw.CBWCDB
75190733Sthompsa
76190173Sthompsa/*
77190173Sthompsa * The SCSI ID string must be exactly 28 characters long
78190173Sthompsa * exluding the terminating zero.
79190173Sthompsa */
80190173Sthompsa#ifndef USTORAGE_FS_ID_STRING
81190173Sthompsa#define	USTORAGE_FS_ID_STRING \
82190173Sthompsa	"FreeBSD " /* 8 */ \
83190173Sthompsa	"File-Stor Gadget" /* 16 */ \
84190173Sthompsa	"0101" /* 4 */
85190173Sthompsa#endif
86190173Sthompsa
87190173Sthompsa/*
88190173Sthompsa * The following macro defines the number of
89190173Sthompsa * sectors to be allocated for the RAM disk:
90190173Sthompsa */
91190173Sthompsa#ifndef USTORAGE_FS_RAM_SECT
92190173Sthompsa#define	USTORAGE_FS_RAM_SECT (1UL << 13)
93190173Sthompsa#endif
94190173Sthompsa
95184610Salfredstatic uint8_t *ustorage_fs_ramdisk;
96184610Salfred
97184610Salfred/* USB transfer definitions */
98184610Salfred
99184610Salfred#define	USTORAGE_FS_T_BBB_COMMAND     0
100184610Salfred#define	USTORAGE_FS_T_BBB_DATA_DUMP   1
101184610Salfred#define	USTORAGE_FS_T_BBB_DATA_READ   2
102184610Salfred#define	USTORAGE_FS_T_BBB_DATA_WRITE  3
103184610Salfred#define	USTORAGE_FS_T_BBB_STATUS      4
104184610Salfred#define	USTORAGE_FS_T_BBB_MAX         5
105184610Salfred
106184610Salfred/* USB data stage direction */
107184610Salfred
108184610Salfred#define	DIR_NONE	0
109184610Salfred#define	DIR_READ	1
110184610Salfred#define	DIR_WRITE	2
111184610Salfred
112184610Salfred/* USB interface specific control request */
113184610Salfred
114184610Salfred#define	UR_BBB_RESET		0xff	/* Bulk-Only reset */
115184610Salfred#define	UR_BBB_GET_MAX_LUN	0xfe	/* Get maximum lun */
116184610Salfred
117184610Salfred/* Command Block Wrapper */
118184610Salfredtypedef struct {
119184610Salfred	uDWord	dCBWSignature;
120184610Salfred#define	CBWSIGNATURE	0x43425355
121184610Salfred	uDWord	dCBWTag;
122184610Salfred	uDWord	dCBWDataTransferLength;
123184610Salfred	uByte	bCBWFlags;
124184610Salfred#define	CBWFLAGS_OUT	0x00
125184610Salfred#define	CBWFLAGS_IN	0x80
126184610Salfred	uByte	bCBWLUN;
127184610Salfred	uByte	bCDBLength;
128184610Salfred#define	CBWCDBLENGTH	16
129184610Salfred	uByte	CBWCDB[CBWCDBLENGTH];
130184610Salfred} __packed ustorage_fs_bbb_cbw_t;
131184610Salfred
132184610Salfred#define	USTORAGE_FS_BBB_CBW_SIZE	31
133184610Salfred
134184610Salfred/* Command Status Wrapper */
135184610Salfredtypedef struct {
136184610Salfred	uDWord	dCSWSignature;
137184610Salfred#define	CSWSIGNATURE	0x53425355
138184610Salfred	uDWord	dCSWTag;
139184610Salfred	uDWord	dCSWDataResidue;
140184610Salfred	uByte	bCSWStatus;
141184610Salfred#define	CSWSTATUS_GOOD	0x0
142184610Salfred#define	CSWSTATUS_FAILED	0x1
143184610Salfred#define	CSWSTATUS_PHASE	0x2
144184610Salfred} __packed ustorage_fs_bbb_csw_t;
145184610Salfred
146184610Salfred#define	USTORAGE_FS_BBB_CSW_SIZE	13
147184610Salfred
148184610Salfredstruct ustorage_fs_lun {
149184610Salfred
150190181Sthompsa	uint8_t	*memory_image;
151184610Salfred
152184610Salfred	uint32_t num_sectors;
153184610Salfred	uint32_t sense_data;
154184610Salfred	uint32_t sense_data_info;
155184610Salfred	uint32_t unit_attention_data;
156184610Salfred
157184610Salfred	uint8_t	read_only:1;
158184610Salfred	uint8_t	prevent_medium_removal:1;
159184610Salfred	uint8_t	info_valid:1;
160184610Salfred	uint8_t	removable:1;
161184610Salfred};
162184610Salfred
163184610Salfredstruct ustorage_fs_softc {
164184610Salfred
165184610Salfred	ustorage_fs_bbb_cbw_t sc_cbw;	/* Command Wrapper Block */
166184610Salfred	ustorage_fs_bbb_csw_t sc_csw;	/* Command Status Block */
167184610Salfred
168184610Salfred	struct mtx sc_mtx;
169184610Salfred
170184610Salfred	struct ustorage_fs_lun sc_lun[USTORAGE_FS_MAX_LUN];
171184610Salfred
172184610Salfred	struct {
173184610Salfred		uint8_t *data_ptr;
174184610Salfred		struct ustorage_fs_lun *currlun;
175184610Salfred
176184610Salfred		uint32_t data_rem;	/* bytes, as reported by the command
177184610Salfred					 * block wrapper */
178184610Salfred		uint32_t offset;	/* bytes */
179184610Salfred
180184610Salfred		uint8_t	cbw_dir;
181184610Salfred		uint8_t	cmd_dir;
182184610Salfred		uint8_t	lun;
183184610Salfred		uint8_t	cmd_len;
184184610Salfred		uint8_t	data_short:1;
185184610Salfred		uint8_t	data_error:1;
186184610Salfred	}	sc_transfer;
187184610Salfred
188184610Salfred	device_t sc_dev;
189192984Sthompsa	struct usb_device *sc_udev;
190192984Sthompsa	struct usb_xfer *sc_xfer[USTORAGE_FS_T_BBB_MAX];
191184610Salfred
192184610Salfred	uint8_t	sc_iface_no;		/* interface number */
193184610Salfred	uint8_t	sc_last_lun;
194184610Salfred	uint8_t	sc_last_xfer_index;
195190733Sthompsa	uint8_t	sc_qdata[USTORAGE_QDATA_MAX];
196184610Salfred};
197184610Salfred
198184610Salfred/* prototypes */
199184610Salfred
200184610Salfredstatic device_probe_t ustorage_fs_probe;
201184610Salfredstatic device_attach_t ustorage_fs_attach;
202184610Salfredstatic device_detach_t ustorage_fs_detach;
203184610Salfredstatic device_suspend_t ustorage_fs_suspend;
204184610Salfredstatic device_resume_t ustorage_fs_resume;
205188942Sthompsastatic usb_handle_request_t ustorage_fs_handle_request;
206184610Salfred
207184610Salfredstatic usb2_callback_t ustorage_fs_t_bbb_command_callback;
208184610Salfredstatic usb2_callback_t ustorage_fs_t_bbb_data_dump_callback;
209184610Salfredstatic usb2_callback_t ustorage_fs_t_bbb_data_read_callback;
210184610Salfredstatic usb2_callback_t ustorage_fs_t_bbb_data_write_callback;
211184610Salfredstatic usb2_callback_t ustorage_fs_t_bbb_status_callback;
212184610Salfred
213184610Salfredstatic void ustorage_fs_transfer_start(struct ustorage_fs_softc *sc, uint8_t xfer_index);
214184610Salfredstatic void ustorage_fs_transfer_stop(struct ustorage_fs_softc *sc);
215184610Salfred
216184610Salfredstatic uint8_t ustorage_fs_verify(struct ustorage_fs_softc *sc);
217184610Salfredstatic uint8_t ustorage_fs_inquiry(struct ustorage_fs_softc *sc);
218184610Salfredstatic uint8_t ustorage_fs_request_sense(struct ustorage_fs_softc *sc);
219184610Salfredstatic uint8_t ustorage_fs_read_capacity(struct ustorage_fs_softc *sc);
220184610Salfredstatic uint8_t ustorage_fs_mode_sense(struct ustorage_fs_softc *sc);
221184610Salfredstatic uint8_t ustorage_fs_start_stop(struct ustorage_fs_softc *sc);
222184610Salfredstatic uint8_t ustorage_fs_prevent_allow(struct ustorage_fs_softc *sc);
223184610Salfredstatic uint8_t ustorage_fs_read_format_capacities(struct ustorage_fs_softc *sc);
224184610Salfredstatic uint8_t ustorage_fs_mode_select(struct ustorage_fs_softc *sc);
225184610Salfredstatic uint8_t ustorage_fs_min_len(struct ustorage_fs_softc *sc, uint32_t len, uint32_t mask);
226184610Salfredstatic uint8_t ustorage_fs_read(struct ustorage_fs_softc *sc);
227184610Salfredstatic uint8_t ustorage_fs_write(struct ustorage_fs_softc *sc);
228184610Salfredstatic uint8_t ustorage_fs_check_cmd(struct ustorage_fs_softc *sc, uint8_t cmd_size, uint16_t mask, uint8_t needs_medium);
229184610Salfredstatic uint8_t ustorage_fs_do_cmd(struct ustorage_fs_softc *sc);
230184610Salfred
231184610Salfredstatic device_method_t ustorage_fs_methods[] = {
232184610Salfred	/* USB interface */
233188942Sthompsa	DEVMETHOD(usb_handle_request, ustorage_fs_handle_request),
234184610Salfred
235184610Salfred	/* Device interface */
236184610Salfred	DEVMETHOD(device_probe, ustorage_fs_probe),
237184610Salfred	DEVMETHOD(device_attach, ustorage_fs_attach),
238184610Salfred	DEVMETHOD(device_detach, ustorage_fs_detach),
239184610Salfred	DEVMETHOD(device_suspend, ustorage_fs_suspend),
240184610Salfred	DEVMETHOD(device_resume, ustorage_fs_resume),
241184610Salfred
242184610Salfred	{0, 0}
243184610Salfred};
244184610Salfred
245184610Salfredstatic driver_t ustorage_fs_driver = {
246184610Salfred	.name = "ustorage_fs",
247184610Salfred	.methods = ustorage_fs_methods,
248184610Salfred	.size = sizeof(struct ustorage_fs_softc),
249184610Salfred};
250184610Salfred
251184610Salfredstatic devclass_t ustorage_fs_devclass;
252184610Salfred
253189275SthompsaDRIVER_MODULE(ustorage_fs, uhub, ustorage_fs_driver, ustorage_fs_devclass, NULL, 0);
254184610SalfredMODULE_VERSION(ustorage_fs, 0);
255188942SthompsaMODULE_DEPEND(ustorage_fs, usb, 1, 1, 1);
256184610Salfred
257192984Sthompsastruct usb_config ustorage_fs_bbb_config[USTORAGE_FS_T_BBB_MAX] = {
258184610Salfred
259184610Salfred	[USTORAGE_FS_T_BBB_COMMAND] = {
260184610Salfred		.type = UE_BULK,
261184610Salfred		.endpoint = UE_ADDR_ANY,
262184610Salfred		.direction = UE_DIR_OUT,
263190733Sthompsa		.bufsize = sizeof(ustorage_fs_bbb_cbw_t),
264190733Sthompsa		.flags = {.ext_buffer = 1,},
265190733Sthompsa		.callback = &ustorage_fs_t_bbb_command_callback,
266190733Sthompsa		.usb_mode = USB_MODE_DEVICE,
267184610Salfred	},
268184610Salfred
269184610Salfred	[USTORAGE_FS_T_BBB_DATA_DUMP] = {
270184610Salfred		.type = UE_BULK,
271184610Salfred		.endpoint = UE_ADDR_ANY,
272184610Salfred		.direction = UE_DIR_OUT,
273190733Sthompsa		.bufsize = 0,	/* use wMaxPacketSize */
274190733Sthompsa		.flags = {.proxy_buffer = 1,.short_xfer_ok = 1,},
275190733Sthompsa		.callback = &ustorage_fs_t_bbb_data_dump_callback,
276190733Sthompsa		.usb_mode = USB_MODE_DEVICE,
277184610Salfred	},
278184610Salfred
279184610Salfred	[USTORAGE_FS_T_BBB_DATA_READ] = {
280184610Salfred		.type = UE_BULK,
281184610Salfred		.endpoint = UE_ADDR_ANY,
282184610Salfred		.direction = UE_DIR_OUT,
283190733Sthompsa		.bufsize = USTORAGE_FS_BULK_SIZE,
284190733Sthompsa		.flags = {.proxy_buffer = 1,.short_xfer_ok = 1,.ext_buffer = 1},
285190733Sthompsa		.callback = &ustorage_fs_t_bbb_data_read_callback,
286190733Sthompsa		.usb_mode = USB_MODE_DEVICE,
287184610Salfred	},
288184610Salfred
289184610Salfred	[USTORAGE_FS_T_BBB_DATA_WRITE] = {
290184610Salfred		.type = UE_BULK,
291184610Salfred		.endpoint = UE_ADDR_ANY,
292184610Salfred		.direction = UE_DIR_IN,
293190733Sthompsa		.bufsize = USTORAGE_FS_BULK_SIZE,
294190733Sthompsa		.flags = {.proxy_buffer = 1,.short_xfer_ok = 1,.ext_buffer = 1},
295190733Sthompsa		.callback = &ustorage_fs_t_bbb_data_write_callback,
296190733Sthompsa		.usb_mode = USB_MODE_DEVICE,
297184610Salfred	},
298184610Salfred
299184610Salfred	[USTORAGE_FS_T_BBB_STATUS] = {
300184610Salfred		.type = UE_BULK,
301184610Salfred		.endpoint = UE_ADDR_ANY,
302184610Salfred		.direction = UE_DIR_IN,
303190733Sthompsa		.bufsize = sizeof(ustorage_fs_bbb_csw_t),
304190733Sthompsa		.flags = {.short_xfer_ok = 1,.ext_buffer = 1,},
305190733Sthompsa		.callback = &ustorage_fs_t_bbb_status_callback,
306190733Sthompsa		.usb_mode = USB_MODE_DEVICE,
307184610Salfred	},
308184610Salfred};
309184610Salfred
310184610Salfred/*
311184610Salfred * USB device probe/attach/detach
312184610Salfred */
313184610Salfred
314184610Salfredstatic int
315184610Salfredustorage_fs_probe(device_t dev)
316184610Salfred{
317192984Sthompsa	struct usb_attach_arg *uaa = device_get_ivars(dev);
318192984Sthompsa	struct usb_interface_descriptor *id;
319184610Salfred
320192499Sthompsa	if (uaa->usb_mode != USB_MODE_DEVICE) {
321184610Salfred		return (ENXIO);
322184610Salfred	}
323184610Salfred	if (uaa->use_generic == 0) {
324184610Salfred		/* give other drivers a try first */
325184610Salfred		return (ENXIO);
326184610Salfred	}
327184610Salfred	/* Check for a standards compliant device */
328184610Salfred	id = usb2_get_interface_descriptor(uaa->iface);
329184610Salfred	if ((id == NULL) ||
330184610Salfred	    (id->bInterfaceClass != UICLASS_MASS) ||
331184610Salfred	    (id->bInterfaceSubClass != UISUBCLASS_SCSI) ||
332184610Salfred	    (id->bInterfaceProtocol != UIPROTO_MASS_BBB)) {
333184610Salfred		return (ENXIO);
334184610Salfred	}
335184610Salfred	return (0);
336184610Salfred}
337184610Salfred
338184610Salfredstatic int
339184610Salfredustorage_fs_attach(device_t dev)
340184610Salfred{
341184610Salfred	struct ustorage_fs_softc *sc = device_get_softc(dev);
342192984Sthompsa	struct usb_attach_arg *uaa = device_get_ivars(dev);
343192984Sthompsa	struct usb_interface_descriptor *id;
344184610Salfred	int err;
345190733Sthompsa	int unit;
346184610Salfred
347184610Salfred	/*
348184610Salfred	 * NOTE: the softc struct is bzero-ed in device_set_driver.
349184610Salfred	 * We can safely call ustorage_fs_detach without specifically
350184610Salfred	 * initializing the struct.
351184610Salfred	 */
352184610Salfred
353184610Salfred	sc->sc_dev = dev;
354184610Salfred	sc->sc_udev = uaa->device;
355190733Sthompsa	unit = device_get_unit(dev);
356184610Salfred
357190733Sthompsa	if (unit == 0) {
358184610Salfred		if (ustorage_fs_ramdisk == NULL) {
359184610Salfred			/*
360184610Salfred			 * allocate a memory image for our ramdisk until
361184610Salfred			 * further
362184610Salfred			 */
363184610Salfred			ustorage_fs_ramdisk =
364184610Salfred			    malloc(USTORAGE_FS_RAM_SECT << 9, M_USB, M_ZERO | M_WAITOK);
365184610Salfred			if (ustorage_fs_ramdisk == NULL) {
366184610Salfred				return (ENOMEM);
367184610Salfred			}
368184610Salfred		}
369184610Salfred		sc->sc_lun[0].memory_image = ustorage_fs_ramdisk;
370184610Salfred		sc->sc_lun[0].num_sectors = USTORAGE_FS_RAM_SECT;
371184610Salfred		sc->sc_lun[0].removable = 1;
372184610Salfred	}
373184610Salfred
374184610Salfred	device_set_usb2_desc(dev);
375184610Salfred
376184610Salfred	mtx_init(&sc->sc_mtx, "USTORAGE_FS lock",
377184610Salfred	    NULL, (MTX_DEF | MTX_RECURSE));
378184610Salfred
379184610Salfred	/* get interface index */
380184610Salfred
381184610Salfred	id = usb2_get_interface_descriptor(uaa->iface);
382184610Salfred	if (id == NULL) {
383184610Salfred		device_printf(dev, "failed to get "
384184610Salfred		    "interface number\n");
385184610Salfred		goto detach;
386184610Salfred	}
387184610Salfred	sc->sc_iface_no = id->bInterfaceNumber;
388184610Salfred
389184610Salfred	err = usb2_transfer_setup(uaa->device,
390184610Salfred	    &uaa->info.bIfaceIndex, sc->sc_xfer, ustorage_fs_bbb_config,
391184610Salfred	    USTORAGE_FS_T_BBB_MAX, sc, &sc->sc_mtx);
392184610Salfred	if (err) {
393184610Salfred		device_printf(dev, "could not setup required "
394184610Salfred		    "transfers, %s\n", usb2_errstr(err));
395184610Salfred		goto detach;
396184610Salfred	}
397184610Salfred	/* start Mass Storage State Machine */
398184610Salfred
399184610Salfred	mtx_lock(&sc->sc_mtx);
400184610Salfred	ustorage_fs_transfer_start(sc, USTORAGE_FS_T_BBB_COMMAND);
401184610Salfred	mtx_unlock(&sc->sc_mtx);
402184610Salfred
403184610Salfred	return (0);			/* success */
404184610Salfred
405184610Salfreddetach:
406184610Salfred	ustorage_fs_detach(dev);
407184610Salfred	return (ENXIO);			/* failure */
408184610Salfred}
409184610Salfred
410184610Salfredstatic int
411184610Salfredustorage_fs_detach(device_t dev)
412184610Salfred{
413184610Salfred	struct ustorage_fs_softc *sc = device_get_softc(dev);
414184610Salfred
415184610Salfred	/* teardown our statemachine */
416184610Salfred
417184610Salfred	usb2_transfer_unsetup(sc->sc_xfer, USTORAGE_FS_T_BBB_MAX);
418184610Salfred
419184610Salfred	mtx_destroy(&sc->sc_mtx);
420184610Salfred
421184610Salfred	return (0);			/* success */
422184610Salfred}
423184610Salfred
424184610Salfredstatic int
425184610Salfredustorage_fs_suspend(device_t dev)
426184610Salfred{
427184610Salfred	device_printf(dev, "suspending\n");
428184610Salfred	return (0);			/* success */
429184610Salfred}
430184610Salfred
431184610Salfredstatic int
432184610Salfredustorage_fs_resume(device_t dev)
433184610Salfred{
434184610Salfred	device_printf(dev, "resuming\n");
435184610Salfred	return (0);			/* success */
436184610Salfred}
437184610Salfred
438184610Salfred/*
439184610Salfred * Generic functions to handle transfers
440184610Salfred */
441184610Salfred
442184610Salfredstatic void
443184610Salfredustorage_fs_transfer_start(struct ustorage_fs_softc *sc, uint8_t xfer_index)
444184610Salfred{
445184610Salfred	if (sc->sc_xfer[xfer_index]) {
446184610Salfred		sc->sc_last_xfer_index = xfer_index;
447184610Salfred		usb2_transfer_start(sc->sc_xfer[xfer_index]);
448184610Salfred	}
449184610Salfred}
450184610Salfred
451184610Salfredstatic void
452184610Salfredustorage_fs_transfer_stop(struct ustorage_fs_softc *sc)
453184610Salfred{
454184610Salfred	usb2_transfer_stop(sc->sc_xfer[sc->sc_last_xfer_index]);
455184610Salfred	mtx_unlock(&sc->sc_mtx);
456184610Salfred	usb2_transfer_drain(sc->sc_xfer[sc->sc_last_xfer_index]);
457184610Salfred	mtx_lock(&sc->sc_mtx);
458184610Salfred}
459184610Salfred
460184610Salfredstatic int
461184610Salfredustorage_fs_handle_request(device_t dev,
462184610Salfred    const void *preq, void **pptr, uint16_t *plen,
463184610Salfred    uint16_t offset, uint8_t is_complete)
464184610Salfred{
465184610Salfred	struct ustorage_fs_softc *sc = device_get_softc(dev);
466192984Sthompsa	const struct usb_device_request *req = preq;
467184610Salfred
468184610Salfred	if (!is_complete) {
469192057Sthompsa		if ((req->bmRequestType == UT_WRITE_CLASS_INTERFACE) &&
470192057Sthompsa		    (req->bRequest == UR_BBB_RESET)) {
471184610Salfred			*plen = 0;
472184610Salfred			mtx_lock(&sc->sc_mtx);
473184610Salfred			ustorage_fs_transfer_stop(sc);
474184610Salfred			sc->sc_transfer.data_error = 1;
475184610Salfred			ustorage_fs_transfer_start(sc,
476184610Salfred			    USTORAGE_FS_T_BBB_COMMAND);
477184610Salfred			mtx_unlock(&sc->sc_mtx);
478184610Salfred			return (0);
479192057Sthompsa		} else if ((req->bmRequestType == UT_READ_CLASS_INTERFACE) &&
480192057Sthompsa			   (req->bRequest == UR_BBB_GET_MAX_LUN)) {
481184610Salfred			if (offset == 0) {
482184610Salfred				*plen = 1;
483184610Salfred				*pptr = &sc->sc_last_lun;
484184610Salfred			} else {
485184610Salfred				*plen = 0;
486184610Salfred			}
487184610Salfred			return (0);
488184610Salfred		}
489184610Salfred	}
490184610Salfred	return (ENXIO);			/* use builtin handler */
491184610Salfred}
492184610Salfred
493184610Salfredstatic void
494192984Sthompsaustorage_fs_t_bbb_command_callback(struct usb_xfer *xfer)
495184610Salfred{
496184610Salfred	struct ustorage_fs_softc *sc = xfer->priv_sc;
497184610Salfred	uint32_t tag;
498184610Salfred	uint8_t error = 0;
499184610Salfred
500184610Salfred	DPRINTF("\n");
501184610Salfred
502184610Salfred	switch (USB_GET_STATE(xfer)) {
503184610Salfred	case USB_ST_TRANSFERRED:
504184610Salfred
505184610Salfred		tag = UGETDW(sc->sc_cbw.dCBWSignature);
506184610Salfred
507184610Salfred		if (tag != CBWSIGNATURE) {
508184610Salfred			/* do nothing */
509184610Salfred			DPRINTF("invalid signature 0x%08x\n", tag);
510184610Salfred			break;
511184610Salfred		}
512184610Salfred		tag = UGETDW(sc->sc_cbw.dCBWTag);
513184610Salfred
514184610Salfred		/* echo back tag */
515184610Salfred		USETDW(sc->sc_csw.dCSWTag, tag);
516184610Salfred
517184610Salfred		/* reset status */
518184610Salfred		sc->sc_csw.bCSWStatus = 0;
519184610Salfred
520184610Salfred		/* reset data offset, data length and data remainder */
521184610Salfred		sc->sc_transfer.offset = 0;
522184610Salfred		sc->sc_transfer.data_rem =
523184610Salfred		    UGETDW(sc->sc_cbw.dCBWDataTransferLength);
524184610Salfred
525184610Salfred		/* reset data flags */
526184610Salfred		sc->sc_transfer.data_short = 0;
527184610Salfred
528184610Salfred		/* extract LUN */
529184610Salfred		sc->sc_transfer.lun = sc->sc_cbw.bCBWLUN;
530184610Salfred
531184610Salfred		if (sc->sc_transfer.data_rem == 0) {
532184610Salfred			sc->sc_transfer.cbw_dir = DIR_NONE;
533184610Salfred		} else {
534184610Salfred			if (sc->sc_cbw.bCBWFlags & CBWFLAGS_IN) {
535184610Salfred				sc->sc_transfer.cbw_dir = DIR_WRITE;
536184610Salfred			} else {
537184610Salfred				sc->sc_transfer.cbw_dir = DIR_READ;
538184610Salfred			}
539184610Salfred		}
540184610Salfred
541184610Salfred		sc->sc_transfer.cmd_len = sc->sc_cbw.bCDBLength;
542184610Salfred		if ((sc->sc_transfer.cmd_len > sizeof(sc->sc_cbw.CBWCDB)) ||
543184610Salfred		    (sc->sc_transfer.cmd_len == 0)) {
544184610Salfred			/* just halt - this is invalid */
545184610Salfred			DPRINTF("invalid command length %d bytes\n",
546184610Salfred			    sc->sc_transfer.cmd_len);
547184610Salfred			break;
548184610Salfred		}
549184610Salfred
550184610Salfred		error = ustorage_fs_do_cmd(sc);
551184610Salfred		if (error) {
552184610Salfred			/* got an error */
553184610Salfred			DPRINTF("command failed\n");
554184610Salfred			break;
555184610Salfred		}
556184610Salfred		if ((sc->sc_transfer.data_rem > 0) &&
557184610Salfred		    (sc->sc_transfer.cbw_dir != sc->sc_transfer.cmd_dir)) {
558184610Salfred			/* contradicting data transfer direction */
559184610Salfred			error = 1;
560184610Salfred			DPRINTF("data direction mismatch\n");
561184610Salfred			break;
562184610Salfred		}
563184610Salfred		switch (sc->sc_transfer.cbw_dir) {
564184610Salfred		case DIR_READ:
565184610Salfred			ustorage_fs_transfer_start(sc, USTORAGE_FS_T_BBB_DATA_READ);
566184610Salfred			break;
567184610Salfred		case DIR_WRITE:
568184610Salfred			ustorage_fs_transfer_start(sc, USTORAGE_FS_T_BBB_DATA_WRITE);
569184610Salfred			break;
570184610Salfred		default:
571184610Salfred			ustorage_fs_transfer_start(sc,
572184610Salfred			    USTORAGE_FS_T_BBB_STATUS);
573184610Salfred			break;
574184610Salfred		}
575184610Salfred		break;
576184610Salfred
577184610Salfred	case USB_ST_SETUP:
578184610Salfredtr_setup:
579184610Salfred		if (sc->sc_transfer.data_error) {
580184610Salfred			sc->sc_transfer.data_error = 0;
581184610Salfred			xfer->flags.stall_pipe = 1;
582184610Salfred			DPRINTF("stall pipe\n");
583184610Salfred		} else {
584184610Salfred			xfer->flags.stall_pipe = 0;
585184610Salfred		}
586184610Salfred
587184610Salfred		xfer->frlengths[0] = sizeof(sc->sc_cbw);
588184610Salfred		usb2_set_frame_data(xfer, &sc->sc_cbw, 0);
589184610Salfred		usb2_start_hardware(xfer);
590184610Salfred		break;
591184610Salfred
592184610Salfred	default:			/* Error */
593184610Salfred		DPRINTF("error\n");
594184610Salfred		if (xfer->error == USB_ERR_CANCELLED) {
595184610Salfred			break;
596184610Salfred		}
597184610Salfred		/* If the pipe is already stalled, don't do another stall */
598184610Salfred		if (!xfer->pipe->is_stalled) {
599184610Salfred			sc->sc_transfer.data_error = 1;
600184610Salfred		}
601184610Salfred		/* try again */
602184610Salfred		goto tr_setup;
603184610Salfred	}
604184610Salfred	if (error) {
605184610Salfred		if (sc->sc_csw.bCSWStatus == 0) {
606184610Salfred			/* set some default error code */
607184610Salfred			sc->sc_csw.bCSWStatus = CSWSTATUS_FAILED;
608184610Salfred		}
609184610Salfred		if (sc->sc_transfer.cbw_dir == DIR_READ) {
610184610Salfred			/* dump all data */
611184610Salfred			ustorage_fs_transfer_start(sc,
612184610Salfred			    USTORAGE_FS_T_BBB_DATA_DUMP);
613184610Salfred			return;
614184610Salfred		}
615184610Salfred		if (sc->sc_transfer.cbw_dir == DIR_WRITE) {
616184610Salfred			/* need to stall before status */
617184610Salfred			sc->sc_transfer.data_error = 1;
618184610Salfred		}
619184610Salfred		ustorage_fs_transfer_start(sc, USTORAGE_FS_T_BBB_STATUS);
620184610Salfred	}
621184610Salfred}
622184610Salfred
623184610Salfredstatic void
624192984Sthompsaustorage_fs_t_bbb_data_dump_callback(struct usb_xfer *xfer)
625184610Salfred{
626184610Salfred	struct ustorage_fs_softc *sc = xfer->priv_sc;
627184610Salfred	uint32_t max_bulk = xfer->max_data_length;
628184610Salfred
629184610Salfred	DPRINTF("\n");
630184610Salfred
631184610Salfred	switch (USB_GET_STATE(xfer)) {
632184610Salfred	case USB_ST_TRANSFERRED:
633184610Salfred		sc->sc_transfer.data_rem -= xfer->actlen;
634184610Salfred		sc->sc_transfer.offset += xfer->actlen;
635184610Salfred
636184610Salfred		if ((xfer->actlen != xfer->sumlen) ||
637184610Salfred		    (sc->sc_transfer.data_rem == 0)) {
638184610Salfred			/* short transfer or end of data */
639184610Salfred			ustorage_fs_transfer_start(sc,
640184610Salfred			    USTORAGE_FS_T_BBB_STATUS);
641184610Salfred			break;
642184610Salfred		}
643184610Salfred		/* Fallthrough */
644184610Salfred
645184610Salfred	case USB_ST_SETUP:
646184610Salfredtr_setup:
647184610Salfred		if (max_bulk > sc->sc_transfer.data_rem) {
648184610Salfred			max_bulk = sc->sc_transfer.data_rem;
649184610Salfred		}
650184610Salfred		if (sc->sc_transfer.data_error) {
651184610Salfred			sc->sc_transfer.data_error = 0;
652184610Salfred			xfer->flags.stall_pipe = 1;
653184610Salfred		} else {
654184610Salfred			xfer->flags.stall_pipe = 0;
655184610Salfred		}
656184610Salfred		xfer->frlengths[0] = max_bulk;
657184610Salfred		usb2_start_hardware(xfer);
658184610Salfred		break;
659184610Salfred
660184610Salfred	default:			/* Error */
661184610Salfred		if (xfer->error == USB_ERR_CANCELLED) {
662184610Salfred			break;
663184610Salfred		}
664184610Salfred		/*
665184610Salfred		 * If the pipe is already stalled, don't do another stall:
666184610Salfred		 */
667184610Salfred		if (!xfer->pipe->is_stalled) {
668184610Salfred			sc->sc_transfer.data_error = 1;
669184610Salfred		}
670184610Salfred		/* try again */
671184610Salfred		goto tr_setup;
672184610Salfred	}
673184610Salfred}
674184610Salfred
675184610Salfredstatic void
676192984Sthompsaustorage_fs_t_bbb_data_read_callback(struct usb_xfer *xfer)
677184610Salfred{
678184610Salfred	struct ustorage_fs_softc *sc = xfer->priv_sc;
679184610Salfred	uint32_t max_bulk = xfer->max_data_length;
680184610Salfred
681184610Salfred	DPRINTF("\n");
682184610Salfred
683184610Salfred	switch (USB_GET_STATE(xfer)) {
684184610Salfred	case USB_ST_TRANSFERRED:
685184610Salfred		sc->sc_transfer.data_rem -= xfer->actlen;
686184610Salfred		sc->sc_transfer.data_ptr += xfer->actlen;
687184610Salfred		sc->sc_transfer.offset += xfer->actlen;
688184610Salfred
689184610Salfred		if ((xfer->actlen != xfer->sumlen) ||
690184610Salfred		    (sc->sc_transfer.data_rem == 0)) {
691184610Salfred			/* short transfer or end of data */
692184610Salfred			ustorage_fs_transfer_start(sc,
693184610Salfred			    USTORAGE_FS_T_BBB_STATUS);
694184610Salfred			break;
695184610Salfred		}
696184610Salfred		/* Fallthrough */
697184610Salfred
698184610Salfred	case USB_ST_SETUP:
699184610Salfredtr_setup:
700184610Salfred		if (max_bulk > sc->sc_transfer.data_rem) {
701184610Salfred			max_bulk = sc->sc_transfer.data_rem;
702184610Salfred		}
703184610Salfred		if (sc->sc_transfer.data_error) {
704184610Salfred			sc->sc_transfer.data_error = 0;
705184610Salfred			xfer->flags.stall_pipe = 1;
706184610Salfred		} else {
707184610Salfred			xfer->flags.stall_pipe = 0;
708184610Salfred		}
709184610Salfred
710184610Salfred		xfer->frlengths[0] = max_bulk;
711184610Salfred		usb2_set_frame_data(xfer, sc->sc_transfer.data_ptr, 0);
712184610Salfred		usb2_start_hardware(xfer);
713184610Salfred		break;
714184610Salfred
715184610Salfred	default:			/* Error */
716184610Salfred		if (xfer->error == USB_ERR_CANCELLED) {
717184610Salfred			break;
718184610Salfred		}
719184610Salfred		/* If the pipe is already stalled, don't do another stall */
720184610Salfred		if (!xfer->pipe->is_stalled) {
721184610Salfred			sc->sc_transfer.data_error = 1;
722184610Salfred		}
723184610Salfred		/* try again */
724184610Salfred		goto tr_setup;
725184610Salfred	}
726184610Salfred}
727184610Salfred
728184610Salfredstatic void
729192984Sthompsaustorage_fs_t_bbb_data_write_callback(struct usb_xfer *xfer)
730184610Salfred{
731184610Salfred	struct ustorage_fs_softc *sc = xfer->priv_sc;
732184610Salfred	uint32_t max_bulk = xfer->max_data_length;
733184610Salfred
734184610Salfred	DPRINTF("\n");
735184610Salfred
736184610Salfred	switch (USB_GET_STATE(xfer)) {
737184610Salfred	case USB_ST_TRANSFERRED:
738184610Salfred		sc->sc_transfer.data_rem -= xfer->actlen;
739184610Salfred		sc->sc_transfer.data_ptr += xfer->actlen;
740184610Salfred		sc->sc_transfer.offset += xfer->actlen;
741184610Salfred
742184610Salfred		if ((xfer->actlen != xfer->sumlen) ||
743184610Salfred		    (sc->sc_transfer.data_rem == 0)) {
744184610Salfred			/* short transfer or end of data */
745184610Salfred			ustorage_fs_transfer_start(sc,
746184610Salfred			    USTORAGE_FS_T_BBB_STATUS);
747184610Salfred			break;
748184610Salfred		}
749184610Salfred	case USB_ST_SETUP:
750184610Salfredtr_setup:
751184610Salfred		if (max_bulk >= sc->sc_transfer.data_rem) {
752184610Salfred			max_bulk = sc->sc_transfer.data_rem;
753184610Salfred			if (sc->sc_transfer.data_short) {
754184610Salfred				xfer->flags.force_short_xfer = 1;
755184610Salfred			} else {
756184610Salfred				xfer->flags.force_short_xfer = 0;
757184610Salfred			}
758184610Salfred		} else {
759184610Salfred			xfer->flags.force_short_xfer = 0;
760184610Salfred		}
761184610Salfred
762184610Salfred		if (sc->sc_transfer.data_error) {
763184610Salfred			sc->sc_transfer.data_error = 0;
764184610Salfred			xfer->flags.stall_pipe = 1;
765184610Salfred		} else {
766184610Salfred			xfer->flags.stall_pipe = 0;
767184610Salfred		}
768184610Salfred
769184610Salfred		xfer->frlengths[0] = max_bulk;
770184610Salfred		usb2_set_frame_data(xfer, sc->sc_transfer.data_ptr, 0);
771184610Salfred		usb2_start_hardware(xfer);
772184610Salfred		break;
773184610Salfred
774184610Salfred	default:			/* Error */
775184610Salfred		if (xfer->error == USB_ERR_CANCELLED) {
776184610Salfred			break;
777184610Salfred		}
778184610Salfred		/*
779184610Salfred		 * If the pipe is already stalled, don't do another
780184610Salfred		 * stall
781184610Salfred		 */
782184610Salfred		if (!xfer->pipe->is_stalled) {
783184610Salfred			sc->sc_transfer.data_error = 1;
784184610Salfred		}
785184610Salfred		/* try again */
786184610Salfred		goto tr_setup;
787184610Salfred	}
788184610Salfred}
789184610Salfred
790184610Salfredstatic void
791192984Sthompsaustorage_fs_t_bbb_status_callback(struct usb_xfer *xfer)
792184610Salfred{
793184610Salfred	struct ustorage_fs_softc *sc = xfer->priv_sc;
794184610Salfred
795184610Salfred	DPRINTF("\n");
796184610Salfred
797184610Salfred	switch (USB_GET_STATE(xfer)) {
798184610Salfred	case USB_ST_TRANSFERRED:
799184610Salfred		ustorage_fs_transfer_start(sc, USTORAGE_FS_T_BBB_COMMAND);
800184610Salfred		break;
801184610Salfred
802184610Salfred	case USB_ST_SETUP:
803184610Salfredtr_setup:
804184610Salfred		USETDW(sc->sc_csw.dCSWSignature, CSWSIGNATURE);
805184610Salfred		USETDW(sc->sc_csw.dCSWDataResidue, sc->sc_transfer.data_rem);
806184610Salfred
807184610Salfred		if (sc->sc_transfer.data_error) {
808184610Salfred			sc->sc_transfer.data_error = 0;
809184610Salfred			xfer->flags.stall_pipe = 1;
810184610Salfred		} else {
811184610Salfred			xfer->flags.stall_pipe = 0;
812184610Salfred		}
813184610Salfred
814184610Salfred		xfer->frlengths[0] = sizeof(sc->sc_csw);
815184610Salfred		usb2_set_frame_data(xfer, &sc->sc_csw, 0);
816184610Salfred		usb2_start_hardware(xfer);
817184610Salfred		break;
818184610Salfred
819184610Salfred	default:
820184610Salfred		if (xfer->error == USB_ERR_CANCELLED) {
821184610Salfred			break;
822184610Salfred		}
823184610Salfred		/* If the pipe is already stalled, don't do another stall */
824184610Salfred		if (!xfer->pipe->is_stalled) {
825184610Salfred			sc->sc_transfer.data_error = 1;
826184610Salfred		}
827184610Salfred		/* try again */
828184610Salfred		goto tr_setup;
829184610Salfred	}
830184610Salfred}
831184610Salfred
832184610Salfred/* SCSI commands that we recognize */
833184610Salfred#define	SC_FORMAT_UNIT			0x04
834184610Salfred#define	SC_INQUIRY			0x12
835184610Salfred#define	SC_MODE_SELECT_6		0x15
836184610Salfred#define	SC_MODE_SELECT_10		0x55
837184610Salfred#define	SC_MODE_SENSE_6			0x1a
838184610Salfred#define	SC_MODE_SENSE_10		0x5a
839184610Salfred#define	SC_PREVENT_ALLOW_MEDIUM_REMOVAL	0x1e
840184610Salfred#define	SC_READ_6			0x08
841184610Salfred#define	SC_READ_10			0x28
842184610Salfred#define	SC_READ_12			0xa8
843184610Salfred#define	SC_READ_CAPACITY		0x25
844184610Salfred#define	SC_READ_FORMAT_CAPACITIES	0x23
845184610Salfred#define	SC_RELEASE			0x17
846184610Salfred#define	SC_REQUEST_SENSE		0x03
847184610Salfred#define	SC_RESERVE			0x16
848184610Salfred#define	SC_SEND_DIAGNOSTIC		0x1d
849184610Salfred#define	SC_START_STOP_UNIT		0x1b
850184610Salfred#define	SC_SYNCHRONIZE_CACHE		0x35
851184610Salfred#define	SC_TEST_UNIT_READY		0x00
852184610Salfred#define	SC_VERIFY			0x2f
853184610Salfred#define	SC_WRITE_6			0x0a
854184610Salfred#define	SC_WRITE_10			0x2a
855184610Salfred#define	SC_WRITE_12			0xaa
856184610Salfred
857184610Salfred/* SCSI Sense Key/Additional Sense Code/ASC Qualifier values */
858184610Salfred#define	SS_NO_SENSE				0
859184610Salfred#define	SS_COMMUNICATION_FAILURE		0x040800
860184610Salfred#define	SS_INVALID_COMMAND			0x052000
861184610Salfred#define	SS_INVALID_FIELD_IN_CDB			0x052400
862184610Salfred#define	SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE	0x052100
863184610Salfred#define	SS_LOGICAL_UNIT_NOT_SUPPORTED		0x052500
864184610Salfred#define	SS_MEDIUM_NOT_PRESENT			0x023a00
865184610Salfred#define	SS_MEDIUM_REMOVAL_PREVENTED		0x055302
866184610Salfred#define	SS_NOT_READY_TO_READY_TRANSITION	0x062800
867184610Salfred#define	SS_RESET_OCCURRED			0x062900
868184610Salfred#define	SS_SAVING_PARAMETERS_NOT_SUPPORTED	0x053900
869184610Salfred#define	SS_UNRECOVERED_READ_ERROR		0x031100
870184610Salfred#define	SS_WRITE_ERROR				0x030c02
871184610Salfred#define	SS_WRITE_PROTECTED			0x072700
872184610Salfred
873184610Salfred#define	SK(x)		((uint8_t) ((x) >> 16))	/* Sense Key byte, etc. */
874184610Salfred#define	ASC(x)		((uint8_t) ((x) >> 8))
875184610Salfred#define	ASCQ(x)		((uint8_t) (x))
876184610Salfred
877184610Salfred/* Routines for unaligned data access */
878184610Salfred
879184610Salfredstatic uint16_t
880184610Salfredget_be16(uint8_t *buf)
881184610Salfred{
882184610Salfred	return ((uint16_t)buf[0] << 8) | ((uint16_t)buf[1]);
883184610Salfred}
884184610Salfred
885184610Salfredstatic uint32_t
886184610Salfredget_be32(uint8_t *buf)
887184610Salfred{
888184610Salfred	return ((uint32_t)buf[0] << 24) | ((uint32_t)buf[1] << 16) |
889184610Salfred	((uint32_t)buf[2] << 8) | ((uint32_t)buf[3]);
890184610Salfred}
891184610Salfred
892184610Salfredstatic void
893184610Salfredput_be16(uint8_t *buf, uint16_t val)
894184610Salfred{
895184610Salfred	buf[0] = val >> 8;
896184610Salfred	buf[1] = val;
897184610Salfred}
898184610Salfred
899184610Salfredstatic void
900184610Salfredput_be32(uint8_t *buf, uint32_t val)
901184610Salfred{
902184610Salfred	buf[0] = val >> 24;
903184610Salfred	buf[1] = val >> 16;
904184610Salfred	buf[2] = val >> 8;
905184610Salfred	buf[3] = val & 0xff;
906184610Salfred}
907184610Salfred
908184610Salfred/*------------------------------------------------------------------------*
909184610Salfred *	ustorage_fs_verify
910184610Salfred *
911184610Salfred * Returns:
912184610Salfred *    0: Success
913184610Salfred * Else: Failure
914184610Salfred *------------------------------------------------------------------------*/
915184610Salfredstatic uint8_t
916184610Salfredustorage_fs_verify(struct ustorage_fs_softc *sc)
917184610Salfred{
918184610Salfred	struct ustorage_fs_lun *currlun = sc->sc_transfer.currlun;
919184610Salfred	uint32_t lba;
920184610Salfred	uint32_t vlen;
921184610Salfred	uint64_t file_offset;
922184610Salfred	uint64_t amount_left;
923184610Salfred
924184610Salfred	/*
925184610Salfred	 * Get the starting Logical Block Address
926184610Salfred	 */
927190733Sthompsa	lba = get_be32(&sc->sc_cmd_data[2]);
928184610Salfred
929184610Salfred	/*
930184610Salfred	 * We allow DPO (Disable Page Out = don't save data in the cache)
931184610Salfred	 * but we don't implement it.
932184610Salfred	 */
933190733Sthompsa	if ((sc->sc_cmd_data[1] & ~0x10) != 0) {
934184610Salfred		currlun->sense_data = SS_INVALID_FIELD_IN_CDB;
935184610Salfred		return (1);
936184610Salfred	}
937190733Sthompsa	vlen = get_be16(&sc->sc_cmd_data[7]);
938184610Salfred	if (vlen == 0) {
939184610Salfred		goto done;
940184610Salfred	}
941184610Salfred	/* No default reply */
942184610Salfred
943184610Salfred	/* Prepare to carry out the file verify */
944184610Salfred	amount_left = vlen;
945184610Salfred	amount_left <<= 9;
946184610Salfred	file_offset = lba;
947184610Salfred	file_offset <<= 9;
948184610Salfred
949184610Salfred	/* Range check */
950184610Salfred	vlen += lba;
951184610Salfred
952184610Salfred	if ((vlen < lba) ||
953184610Salfred	    (vlen > currlun->num_sectors) ||
954184610Salfred	    (lba >= currlun->num_sectors)) {
955184610Salfred		currlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
956184610Salfred		return (1);
957184610Salfred	}
958184610Salfred	/* XXX TODO: verify that data is readable */
959184610Salfreddone:
960184610Salfred	return (ustorage_fs_min_len(sc, 0, 0 - 1));
961184610Salfred}
962184610Salfred
963184610Salfred/*------------------------------------------------------------------------*
964184610Salfred *	ustorage_fs_inquiry
965184610Salfred *
966184610Salfred * Returns:
967184610Salfred *    0: Success
968184610Salfred * Else: Failure
969184610Salfred *------------------------------------------------------------------------*/
970184610Salfredstatic uint8_t
971184610Salfredustorage_fs_inquiry(struct ustorage_fs_softc *sc)
972184610Salfred{
973184610Salfred	uint8_t *buf = sc->sc_transfer.data_ptr;
974184610Salfred
975184610Salfred	struct ustorage_fs_lun *currlun = sc->sc_transfer.currlun;
976184610Salfred
977184610Salfred	if (!sc->sc_transfer.currlun) {
978184610Salfred		/* Unsupported LUNs are okay */
979184610Salfred		memset(buf, 0, 36);
980184610Salfred		buf[0] = 0x7f;
981184610Salfred		/* Unsupported, no device - type */
982184610Salfred		return (ustorage_fs_min_len(sc, 36, 0 - 1));
983184610Salfred	}
984184610Salfred	memset(buf, 0, 8);
985184610Salfred	/* Non - removable, direct - access device */
986184610Salfred	if (currlun->removable)
987184610Salfred		buf[1] = 0x80;
988184610Salfred	buf[2] = 2;
989184610Salfred	/* ANSI SCSI level 2 */
990184610Salfred	buf[3] = 2;
991184610Salfred	/* SCSI - 2 INQUIRY data format */
992184610Salfred	buf[4] = 31;
993184610Salfred	/* Additional length */
994184610Salfred	/* No special options */
995190719Sthompsa	/* Copy in ID string */
996190719Sthompsa	memcpy(buf + 8, USTORAGE_FS_ID_STRING, 28);
997190719Sthompsa
998190733Sthompsa#if (USTORAGE_QDATA_MAX < 36)
999190733Sthompsa#error "(USTORAGE_QDATA_MAX < 36)"
1000190733Sthompsa#endif
1001184610Salfred	return (ustorage_fs_min_len(sc, 36, 0 - 1));
1002184610Salfred}
1003184610Salfred
1004184610Salfred/*------------------------------------------------------------------------*
1005184610Salfred *	ustorage_fs_request_sense
1006184610Salfred *
1007184610Salfred * Returns:
1008184610Salfred *    0: Success
1009184610Salfred * Else: Failure
1010184610Salfred *------------------------------------------------------------------------*/
1011184610Salfredstatic uint8_t
1012184610Salfredustorage_fs_request_sense(struct ustorage_fs_softc *sc)
1013184610Salfred{
1014184610Salfred	uint8_t *buf = sc->sc_transfer.data_ptr;
1015184610Salfred	struct ustorage_fs_lun *currlun = sc->sc_transfer.currlun;
1016184610Salfred	uint32_t sd;
1017184610Salfred	uint32_t sdinfo;
1018184610Salfred	uint8_t valid;
1019184610Salfred
1020184610Salfred	/*
1021184610Salfred	 * From the SCSI-2 spec., section 7.9 (Unit attention condition):
1022184610Salfred	 *
1023184610Salfred	 * If a REQUEST SENSE command is received from an initiator
1024184610Salfred	 * with a pending unit attention condition (before the target
1025184610Salfred	 * generates the contingent allegiance condition), then the
1026184610Salfred	 * target shall either:
1027184610Salfred	 *   a) report any pending sense data and preserve the unit
1028184610Salfred	 *	attention condition on the logical unit, or,
1029184610Salfred	 *   b) report the unit attention condition, may discard any
1030184610Salfred	 *	pending sense data, and clear the unit attention
1031184610Salfred	 *	condition on the logical unit for that initiator.
1032184610Salfred	 *
1033184610Salfred	 * FSG normally uses option a); enable this code to use option b).
1034184610Salfred	 */
1035184610Salfred#if 0
1036184610Salfred	if (currlun && currlun->unit_attention_data != SS_NO_SENSE) {
1037184610Salfred		currlun->sense_data = currlun->unit_attention_data;
1038184610Salfred		currlun->unit_attention_data = SS_NO_SENSE;
1039184610Salfred	}
1040184610Salfred#endif
1041184610Salfred
1042184610Salfred	if (!currlun) {
1043184610Salfred		/* Unsupported LUNs are okay */
1044184610Salfred		sd = SS_LOGICAL_UNIT_NOT_SUPPORTED;
1045184610Salfred		sdinfo = 0;
1046184610Salfred		valid = 0;
1047184610Salfred	} else {
1048184610Salfred		sd = currlun->sense_data;
1049184610Salfred		sdinfo = currlun->sense_data_info;
1050184610Salfred		valid = currlun->info_valid << 7;
1051184610Salfred		currlun->sense_data = SS_NO_SENSE;
1052184610Salfred		currlun->sense_data_info = 0;
1053184610Salfred		currlun->info_valid = 0;
1054184610Salfred	}
1055184610Salfred
1056184610Salfred	memset(buf, 0, 18);
1057184610Salfred	buf[0] = valid | 0x70;
1058184610Salfred	/* Valid, current error */
1059184610Salfred	buf[2] = SK(sd);
1060184610Salfred	put_be32(&buf[3], sdinfo);
1061184610Salfred	/* Sense information */
1062184610Salfred	buf[7] = 18 - 8;
1063184610Salfred	/* Additional sense length */
1064184610Salfred	buf[12] = ASC(sd);
1065184610Salfred	buf[13] = ASCQ(sd);
1066190733Sthompsa
1067190733Sthompsa#if (USTORAGE_QDATA_MAX < 18)
1068190733Sthompsa#error "(USTORAGE_QDATA_MAX < 18)"
1069190733Sthompsa#endif
1070184610Salfred	return (ustorage_fs_min_len(sc, 18, 0 - 1));
1071184610Salfred}
1072184610Salfred
1073184610Salfred/*------------------------------------------------------------------------*
1074184610Salfred *	ustorage_fs_read_capacity
1075184610Salfred *
1076184610Salfred * Returns:
1077184610Salfred *    0: Success
1078184610Salfred * Else: Failure
1079184610Salfred *------------------------------------------------------------------------*/
1080184610Salfredstatic uint8_t
1081184610Salfredustorage_fs_read_capacity(struct ustorage_fs_softc *sc)
1082184610Salfred{
1083184610Salfred	uint8_t *buf = sc->sc_transfer.data_ptr;
1084184610Salfred	struct ustorage_fs_lun *currlun = sc->sc_transfer.currlun;
1085190733Sthompsa	uint32_t lba = get_be32(&sc->sc_cmd_data[2]);
1086190733Sthompsa	uint8_t pmi = sc->sc_cmd_data[8];
1087184610Salfred
1088184610Salfred	/* Check the PMI and LBA fields */
1089184610Salfred	if ((pmi > 1) || ((pmi == 0) && (lba != 0))) {
1090184610Salfred		currlun->sense_data = SS_INVALID_FIELD_IN_CDB;
1091184610Salfred		return (1);
1092184610Salfred	}
1093190733Sthompsa	/* Max logical block */
1094184610Salfred	put_be32(&buf[0], currlun->num_sectors - 1);
1095190733Sthompsa	/* Block length */
1096184610Salfred	put_be32(&buf[4], 512);
1097190733Sthompsa
1098190733Sthompsa#if (USTORAGE_QDATA_MAX < 8)
1099190733Sthompsa#error "(USTORAGE_QDATA_MAX < 8)"
1100190733Sthompsa#endif
1101184610Salfred	return (ustorage_fs_min_len(sc, 8, 0 - 1));
1102184610Salfred}
1103184610Salfred
1104184610Salfred/*------------------------------------------------------------------------*
1105184610Salfred *	ustorage_fs_mode_sense
1106184610Salfred *
1107184610Salfred * Returns:
1108184610Salfred *    0: Success
1109184610Salfred * Else: Failure
1110184610Salfred *------------------------------------------------------------------------*/
1111184610Salfredstatic uint8_t
1112184610Salfredustorage_fs_mode_sense(struct ustorage_fs_softc *sc)
1113184610Salfred{
1114184610Salfred	uint8_t *buf = sc->sc_transfer.data_ptr;
1115184610Salfred	struct ustorage_fs_lun *currlun = sc->sc_transfer.currlun;
1116184610Salfred	uint8_t *buf0;
1117184610Salfred	uint16_t len;
1118184610Salfred	uint16_t limit;
1119190733Sthompsa	uint8_t mscmnd = sc->sc_cmd_data[0];
1120184610Salfred	uint8_t pc;
1121184610Salfred	uint8_t page_code;
1122184610Salfred	uint8_t changeable_values;
1123184610Salfred	uint8_t all_pages;
1124184610Salfred
1125184610Salfred	buf0 = buf;
1126184610Salfred
1127190733Sthompsa	if ((sc->sc_cmd_data[1] & ~0x08) != 0) {
1128184610Salfred		/* Mask away DBD */
1129184610Salfred		currlun->sense_data = SS_INVALID_FIELD_IN_CDB;
1130184610Salfred		return (1);
1131184610Salfred	}
1132190733Sthompsa	pc = sc->sc_cmd_data[2] >> 6;
1133190733Sthompsa	page_code = sc->sc_cmd_data[2] & 0x3f;
1134184610Salfred	if (pc == 3) {
1135184610Salfred		currlun->sense_data = SS_SAVING_PARAMETERS_NOT_SUPPORTED;
1136184610Salfred		return (1);
1137184610Salfred	}
1138184610Salfred	changeable_values = (pc == 1);
1139184610Salfred	all_pages = (page_code == 0x3f);
1140184610Salfred
1141184610Salfred	/*
1142184610Salfred	 * Write the mode parameter header.  Fixed values are: default
1143184610Salfred	 * medium type, no cache control (DPOFUA), and no block descriptors.
1144184610Salfred	 * The only variable value is the WriteProtect bit.  We will fill in
1145184610Salfred	 * the mode data length later.
1146184610Salfred	 */
1147184610Salfred	memset(buf, 0, 8);
1148184610Salfred	if (mscmnd == SC_MODE_SENSE_6) {
1149184610Salfred		buf[2] = (currlun->read_only ? 0x80 : 0x00);
1150184610Salfred		/* WP, DPOFUA */
1151184610Salfred		buf += 4;
1152184610Salfred		limit = 255;
1153184610Salfred	} else {
1154184610Salfred		/* SC_MODE_SENSE_10 */
1155184610Salfred		buf[3] = (currlun->read_only ? 0x80 : 0x00);
1156184610Salfred		/* WP, DPOFUA */
1157184610Salfred		buf += 8;
1158184610Salfred		limit = 65535;
1159184610Salfred		/* Should really be mod_data.buflen */
1160184610Salfred	}
1161184610Salfred
1162184610Salfred	/* No block descriptors */
1163184610Salfred
1164184610Salfred	/*
1165184610Salfred	 * The mode pages, in numerical order.
1166184610Salfred	 */
1167184610Salfred	if ((page_code == 0x08) || all_pages) {
1168184610Salfred		buf[0] = 0x08;
1169184610Salfred		/* Page code */
1170184610Salfred		buf[1] = 10;
1171184610Salfred		/* Page length */
1172184610Salfred		memset(buf + 2, 0, 10);
1173184610Salfred		/* None of the fields are changeable */
1174184610Salfred
1175184610Salfred		if (!changeable_values) {
1176184610Salfred			buf[2] = 0x04;
1177184610Salfred			/* Write cache enable, */
1178184610Salfred			/* Read cache not disabled */
1179184610Salfred			/* No cache retention priorities */
1180184610Salfred			put_be16(&buf[4], 0xffff);
1181184610Salfred			/* Don 't disable prefetch */
1182184610Salfred			/* Minimum prefetch = 0 */
1183184610Salfred			put_be16(&buf[8], 0xffff);
1184184610Salfred			/* Maximum prefetch */
1185184610Salfred			put_be16(&buf[10], 0xffff);
1186184610Salfred			/* Maximum prefetch ceiling */
1187184610Salfred		}
1188184610Salfred		buf += 12;
1189184610Salfred	}
1190184610Salfred	/*
1191184610Salfred	 * Check that a valid page was requested and the mode data length
1192184610Salfred	 * isn't too long.
1193184610Salfred	 */
1194184610Salfred	len = buf - buf0;
1195184610Salfred	if (len > limit) {
1196184610Salfred		currlun->sense_data = SS_INVALID_FIELD_IN_CDB;
1197184610Salfred		return (1);
1198184610Salfred	}
1199184610Salfred	/* Store the mode data length */
1200184610Salfred	if (mscmnd == SC_MODE_SENSE_6)
1201184610Salfred		buf0[0] = len - 1;
1202184610Salfred	else
1203184610Salfred		put_be16(buf0, len - 2);
1204190733Sthompsa
1205190733Sthompsa#if (USTORAGE_QDATA_MAX < 24)
1206190733Sthompsa#error "(USTORAGE_QDATA_MAX < 24)"
1207190733Sthompsa#endif
1208184610Salfred	return (ustorage_fs_min_len(sc, len, 0 - 1));
1209184610Salfred}
1210184610Salfred
1211184610Salfred/*------------------------------------------------------------------------*
1212184610Salfred *	ustorage_fs_start_stop
1213184610Salfred *
1214184610Salfred * Returns:
1215184610Salfred *    0: Success
1216184610Salfred * Else: Failure
1217184610Salfred *------------------------------------------------------------------------*/
1218184610Salfredstatic uint8_t
1219184610Salfredustorage_fs_start_stop(struct ustorage_fs_softc *sc)
1220184610Salfred{
1221184610Salfred	struct ustorage_fs_lun *currlun = sc->sc_transfer.currlun;
1222184610Salfred	uint8_t loej;
1223184610Salfred	uint8_t start;
1224184610Salfred	uint8_t immed;
1225184610Salfred
1226184610Salfred	if (!currlun->removable) {
1227184610Salfred		currlun->sense_data = SS_INVALID_COMMAND;
1228184610Salfred		return (1);
1229184610Salfred	}
1230190733Sthompsa	immed = sc->sc_cmd_data[1] & 0x01;
1231190733Sthompsa	loej = sc->sc_cmd_data[4] & 0x02;
1232190733Sthompsa	start = sc->sc_cmd_data[4] & 0x01;
1233184610Salfred
1234184610Salfred	if (immed || loej || start) {
1235184610Salfred		/* compile fix */
1236184610Salfred	}
1237184610Salfred	return (0);
1238184610Salfred}
1239184610Salfred
1240184610Salfred/*------------------------------------------------------------------------*
1241184610Salfred *	ustorage_fs_prevent_allow
1242184610Salfred *
1243184610Salfred * Returns:
1244184610Salfred *    0: Success
1245184610Salfred * Else: Failure
1246184610Salfred *------------------------------------------------------------------------*/
1247184610Salfredstatic uint8_t
1248184610Salfredustorage_fs_prevent_allow(struct ustorage_fs_softc *sc)
1249184610Salfred{
1250184610Salfred	struct ustorage_fs_lun *currlun = sc->sc_transfer.currlun;
1251184610Salfred	uint8_t prevent;
1252184610Salfred
1253184610Salfred	if (!currlun->removable) {
1254184610Salfred		currlun->sense_data = SS_INVALID_COMMAND;
1255184610Salfred		return (1);
1256184610Salfred	}
1257190733Sthompsa	prevent = sc->sc_cmd_data[4] & 0x01;
1258190733Sthompsa	if ((sc->sc_cmd_data[4] & ~0x01) != 0) {
1259184610Salfred		/* Mask away Prevent */
1260184610Salfred		currlun->sense_data = SS_INVALID_FIELD_IN_CDB;
1261184610Salfred		return (1);
1262184610Salfred	}
1263184610Salfred	if (currlun->prevent_medium_removal && !prevent) {
1264184610Salfred		//fsync_sub(currlun);
1265184610Salfred	}
1266184610Salfred	currlun->prevent_medium_removal = prevent;
1267184610Salfred	return (0);
1268184610Salfred}
1269184610Salfred
1270184610Salfred/*------------------------------------------------------------------------*
1271184610Salfred *	ustorage_fs_read_format_capacities
1272184610Salfred *
1273184610Salfred * Returns:
1274184610Salfred *    0: Success
1275184610Salfred * Else: Failure
1276184610Salfred *------------------------------------------------------------------------*/
1277184610Salfredstatic uint8_t
1278184610Salfredustorage_fs_read_format_capacities(struct ustorage_fs_softc *sc)
1279184610Salfred{
1280184610Salfred	uint8_t *buf = sc->sc_transfer.data_ptr;
1281184610Salfred	struct ustorage_fs_lun *currlun = sc->sc_transfer.currlun;
1282184610Salfred
1283184610Salfred	buf[0] = buf[1] = buf[2] = 0;
1284184610Salfred	buf[3] = 8;
1285184610Salfred	/* Only the Current / Maximum Capacity Descriptor */
1286184610Salfred	buf += 4;
1287184610Salfred
1288190733Sthompsa	/* Number of blocks */
1289184610Salfred	put_be32(&buf[0], currlun->num_sectors);
1290190733Sthompsa	/* Block length */
1291184610Salfred	put_be32(&buf[4], 512);
1292190733Sthompsa	/* Current capacity */
1293184610Salfred	buf[4] = 0x02;
1294190733Sthompsa
1295190733Sthompsa#if (USTORAGE_QDATA_MAX < 12)
1296190733Sthompsa#error "(USTORAGE_QDATA_MAX < 12)"
1297190733Sthompsa#endif
1298184610Salfred	return (ustorage_fs_min_len(sc, 12, 0 - 1));
1299184610Salfred}
1300184610Salfred
1301184610Salfred/*------------------------------------------------------------------------*
1302184610Salfred *	ustorage_fs_mode_select
1303184610Salfred *
1304184610Salfred * Return values:
1305184610Salfred *    0: Success
1306184610Salfred * Else: Failure
1307184610Salfred *------------------------------------------------------------------------*/
1308184610Salfredstatic uint8_t
1309184610Salfredustorage_fs_mode_select(struct ustorage_fs_softc *sc)
1310184610Salfred{
1311184610Salfred	struct ustorage_fs_lun *currlun = sc->sc_transfer.currlun;
1312184610Salfred
1313184610Salfred	/* We don't support MODE SELECT */
1314184610Salfred	currlun->sense_data = SS_INVALID_COMMAND;
1315184610Salfred	return (1);
1316184610Salfred}
1317184610Salfred
1318184610Salfred/*------------------------------------------------------------------------*
1319184610Salfred *	ustorage_fs_synchronize_cache
1320184610Salfred *
1321184610Salfred * Return values:
1322184610Salfred *    0: Success
1323184610Salfred * Else: Failure
1324184610Salfred *------------------------------------------------------------------------*/
1325184610Salfredstatic uint8_t
1326184610Salfredustorage_fs_synchronize_cache(struct ustorage_fs_softc *sc)
1327184610Salfred{
1328186730Salfred#if 0
1329184610Salfred	struct ustorage_fs_lun *currlun = sc->sc_transfer.currlun;
1330184610Salfred	uint8_t rc;
1331184610Salfred
1332184610Salfred	/*
1333184610Salfred	 * We ignore the requested LBA and write out all dirty data buffers.
1334184610Salfred	 */
1335184610Salfred	rc = 0;
1336184610Salfred	if (rc) {
1337184610Salfred		currlun->sense_data = SS_WRITE_ERROR;
1338184610Salfred	}
1339186730Salfred#endif
1340184610Salfred	return (0);
1341184610Salfred}
1342184610Salfred
1343184610Salfred/*------------------------------------------------------------------------*
1344184610Salfred *	ustorage_fs_read - read data from disk
1345184610Salfred *
1346184610Salfred * Return values:
1347184610Salfred *    0: Success
1348184610Salfred * Else: Failure
1349184610Salfred *------------------------------------------------------------------------*/
1350184610Salfredstatic uint8_t
1351184610Salfredustorage_fs_read(struct ustorage_fs_softc *sc)
1352184610Salfred{
1353184610Salfred	struct ustorage_fs_lun *currlun = sc->sc_transfer.currlun;
1354184610Salfred	uint64_t file_offset;
1355184610Salfred	uint32_t lba;
1356184610Salfred	uint32_t len;
1357184610Salfred
1358184610Salfred	/*
1359184610Salfred	 * Get the starting Logical Block Address and check that it's not
1360184610Salfred	 * too big
1361184610Salfred	 */
1362190733Sthompsa	if (sc->sc_cmd_data[0] == SC_READ_6) {
1363190733Sthompsa		lba = (((uint32_t)sc->sc_cmd_data[1]) << 16) |
1364190733Sthompsa		    get_be16(&sc->sc_cmd_data[2]);
1365184610Salfred	} else {
1366190733Sthompsa		lba = get_be32(&sc->sc_cmd_data[2]);
1367184610Salfred
1368184610Salfred		/*
1369184610Salfred		 * We allow DPO (Disable Page Out = don't save data in the
1370184610Salfred		 * cache) and FUA (Force Unit Access = don't read from the
1371184610Salfred		 * cache), but we don't implement them.
1372184610Salfred		 */
1373190733Sthompsa		if ((sc->sc_cmd_data[1] & ~0x18) != 0) {
1374184610Salfred			currlun->sense_data = SS_INVALID_FIELD_IN_CDB;
1375184610Salfred			return (1);
1376184610Salfred		}
1377184610Salfred	}
1378184610Salfred	len = sc->sc_transfer.data_rem >> 9;
1379184610Salfred	len += lba;
1380184610Salfred
1381184610Salfred	if ((len < lba) ||
1382184610Salfred	    (len > currlun->num_sectors) ||
1383184610Salfred	    (lba >= currlun->num_sectors)) {
1384184610Salfred		currlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
1385184610Salfred		return (1);
1386184610Salfred	}
1387184610Salfred	file_offset = lba;
1388184610Salfred	file_offset <<= 9;
1389184610Salfred
1390190181Sthompsa	sc->sc_transfer.data_ptr = currlun->memory_image + file_offset;
1391184610Salfred
1392184610Salfred	return (0);
1393184610Salfred}
1394184610Salfred
1395184610Salfred/*------------------------------------------------------------------------*
1396184610Salfred *	ustorage_fs_write - write data to disk
1397184610Salfred *
1398184610Salfred * Return values:
1399184610Salfred *    0: Success
1400184610Salfred * Else: Failure
1401184610Salfred *------------------------------------------------------------------------*/
1402184610Salfredstatic uint8_t
1403184610Salfredustorage_fs_write(struct ustorage_fs_softc *sc)
1404184610Salfred{
1405184610Salfred	struct ustorage_fs_lun *currlun = sc->sc_transfer.currlun;
1406184610Salfred	uint64_t file_offset;
1407184610Salfred	uint32_t lba;
1408184610Salfred	uint32_t len;
1409184610Salfred
1410184610Salfred	if (currlun->read_only) {
1411184610Salfred		currlun->sense_data = SS_WRITE_PROTECTED;
1412184610Salfred		return (1);
1413184610Salfred	}
1414184610Salfred	/* XXX clear SYNC */
1415184610Salfred
1416184610Salfred	/*
1417184610Salfred	 * Get the starting Logical Block Address and check that it's not
1418184610Salfred	 * too big.
1419184610Salfred	 */
1420190733Sthompsa	if (sc->sc_cmd_data[0] == SC_WRITE_6)
1421190733Sthompsa		lba = (((uint32_t)sc->sc_cmd_data[1]) << 16) |
1422190733Sthompsa		    get_be16(&sc->sc_cmd_data[2]);
1423184610Salfred	else {
1424190733Sthompsa		lba = get_be32(&sc->sc_cmd_data[2]);
1425184610Salfred
1426184610Salfred		/*
1427184610Salfred		 * We allow DPO (Disable Page Out = don't save data in the
1428184610Salfred		 * cache) and FUA (Force Unit Access = write directly to the
1429184610Salfred		 * medium).  We don't implement DPO; we implement FUA by
1430184610Salfred		 * performing synchronous output.
1431184610Salfred		 */
1432190733Sthompsa		if ((sc->sc_cmd_data[1] & ~0x18) != 0) {
1433184610Salfred			currlun->sense_data = SS_INVALID_FIELD_IN_CDB;
1434184610Salfred			return (1);
1435184610Salfred		}
1436190733Sthompsa		if (sc->sc_cmd_data[1] & 0x08) {
1437184610Salfred			/* FUA */
1438184610Salfred			/* XXX set SYNC flag here */
1439184610Salfred		}
1440184610Salfred	}
1441184610Salfred
1442184610Salfred	len = sc->sc_transfer.data_rem >> 9;
1443184610Salfred	len += lba;
1444184610Salfred
1445184610Salfred	if ((len < lba) ||
1446184610Salfred	    (len > currlun->num_sectors) ||
1447184610Salfred	    (lba >= currlun->num_sectors)) {
1448184610Salfred		currlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
1449184610Salfred		return (1);
1450184610Salfred	}
1451184610Salfred	file_offset = lba;
1452184610Salfred	file_offset <<= 9;
1453184610Salfred
1454190181Sthompsa	sc->sc_transfer.data_ptr = currlun->memory_image + file_offset;
1455184610Salfred
1456184610Salfred	return (0);
1457184610Salfred}
1458184610Salfred
1459184610Salfred/*------------------------------------------------------------------------*
1460184610Salfred *	ustorage_fs_min_len
1461184610Salfred *
1462184610Salfred * Return values:
1463184610Salfred *    0: Success
1464184610Salfred * Else: Failure
1465184610Salfred *------------------------------------------------------------------------*/
1466184610Salfredstatic uint8_t
1467184610Salfredustorage_fs_min_len(struct ustorage_fs_softc *sc, uint32_t len, uint32_t mask)
1468184610Salfred{
1469184610Salfred	if (len != sc->sc_transfer.data_rem) {
1470184610Salfred
1471184610Salfred		if (sc->sc_transfer.cbw_dir == DIR_READ) {
1472184610Salfred			/*
1473184610Salfred			 * there must be something wrong about this SCSI
1474184610Salfred			 * command
1475184610Salfred			 */
1476184610Salfred			sc->sc_csw.bCSWStatus = CSWSTATUS_PHASE;
1477184610Salfred			return (1);
1478184610Salfred		}
1479184610Salfred		/* compute the minimum length */
1480184610Salfred
1481184610Salfred		if (sc->sc_transfer.data_rem > len) {
1482184610Salfred			/* data ends prematurely */
1483184610Salfred			sc->sc_transfer.data_rem = len;
1484184610Salfred			sc->sc_transfer.data_short = 1;
1485184610Salfred		}
1486184610Salfred		/* check length alignment */
1487184610Salfred
1488184610Salfred		if (sc->sc_transfer.data_rem & ~mask) {
1489184610Salfred			/* data ends prematurely */
1490184610Salfred			sc->sc_transfer.data_rem &= mask;
1491184610Salfred			sc->sc_transfer.data_short = 1;
1492184610Salfred		}
1493184610Salfred	}
1494184610Salfred	return (0);
1495184610Salfred}
1496184610Salfred
1497184610Salfred/*------------------------------------------------------------------------*
1498184610Salfred *	ustorage_fs_check_cmd - check command routine
1499184610Salfred *
1500184610Salfred * Check whether the command is properly formed and whether its data
1501184610Salfred * size and direction agree with the values we already have.
1502184610Salfred *
1503184610Salfred * Return values:
1504184610Salfred *    0: Success
1505184610Salfred * Else: Failure
1506184610Salfred *------------------------------------------------------------------------*/
1507184610Salfredstatic uint8_t
1508184610Salfredustorage_fs_check_cmd(struct ustorage_fs_softc *sc, uint8_t min_cmd_size,
1509184610Salfred    uint16_t mask, uint8_t needs_medium)
1510184610Salfred{
1511184610Salfred	struct ustorage_fs_lun *currlun;
1512190733Sthompsa	uint8_t lun = (sc->sc_cmd_data[1] >> 5);
1513184610Salfred	uint8_t i;
1514184610Salfred
1515184610Salfred	/* Verify the length of the command itself */
1516184610Salfred	if (min_cmd_size > sc->sc_transfer.cmd_len) {
1517184610Salfred		DPRINTF("%u > %u\n",
1518184610Salfred		    min_cmd_size, sc->sc_transfer.cmd_len);
1519184610Salfred		sc->sc_csw.bCSWStatus = CSWSTATUS_PHASE;
1520184610Salfred		return (1);
1521184610Salfred	}
1522184610Salfred	/* Mask away the LUN */
1523190733Sthompsa	sc->sc_cmd_data[1] &= 0x1f;
1524184610Salfred
1525184610Salfred	/* Check if LUN is correct */
1526184610Salfred	if (lun != sc->sc_transfer.lun) {
1527184610Salfred
1528184610Salfred	}
1529184610Salfred	/* Check the LUN */
1530184610Salfred	if (sc->sc_transfer.lun <= sc->sc_last_lun) {
1531184610Salfred		sc->sc_transfer.currlun = currlun =
1532184610Salfred		    sc->sc_lun + sc->sc_transfer.lun;
1533190733Sthompsa		if (sc->sc_cmd_data[0] != SC_REQUEST_SENSE) {
1534184610Salfred			currlun->sense_data = SS_NO_SENSE;
1535184610Salfred			currlun->sense_data_info = 0;
1536184610Salfred			currlun->info_valid = 0;
1537184610Salfred		}
1538184610Salfred		/*
1539184610Salfred		 * If a unit attention condition exists, only INQUIRY
1540184610Salfred		 * and REQUEST SENSE commands are allowed. Anything
1541184610Salfred		 * else must fail!
1542184610Salfred		 */
1543184610Salfred		if ((currlun->unit_attention_data != SS_NO_SENSE) &&
1544190733Sthompsa		    (sc->sc_cmd_data[0] != SC_INQUIRY) &&
1545190733Sthompsa		    (sc->sc_cmd_data[0] != SC_REQUEST_SENSE)) {
1546184610Salfred			currlun->sense_data = currlun->unit_attention_data;
1547184610Salfred			currlun->unit_attention_data = SS_NO_SENSE;
1548184610Salfred			return (1);
1549184610Salfred		}
1550184610Salfred	} else {
1551184610Salfred		sc->sc_transfer.currlun = currlun = NULL;
1552184610Salfred
1553184610Salfred		/*
1554184610Salfred		 * INQUIRY and REQUEST SENSE commands are explicitly allowed
1555184610Salfred		 * to use unsupported LUNs; all others may not.
1556184610Salfred		 */
1557190733Sthompsa		if ((sc->sc_cmd_data[0] != SC_INQUIRY) &&
1558190733Sthompsa		    (sc->sc_cmd_data[0] != SC_REQUEST_SENSE)) {
1559184610Salfred			return (1);
1560184610Salfred		}
1561184610Salfred	}
1562184610Salfred
1563184610Salfred	/*
1564184610Salfred	 * Check that only command bytes listed in the mask are
1565184610Salfred	 * non-zero.
1566184610Salfred	 */
1567184610Salfred	for (i = 0; i != min_cmd_size; i++) {
1568190733Sthompsa		if (sc->sc_cmd_data[i] && !(mask & (1UL << i))) {
1569184610Salfred			if (currlun) {
1570184610Salfred				currlun->sense_data = SS_INVALID_FIELD_IN_CDB;
1571184610Salfred			}
1572184610Salfred			return (1);
1573184610Salfred		}
1574184610Salfred	}
1575184610Salfred
1576184610Salfred	/*
1577184610Salfred	 * If the medium isn't mounted and the command needs to access
1578184610Salfred	 * it, return an error.
1579184610Salfred	 */
1580184610Salfred	if (currlun && (!currlun->memory_image) && needs_medium) {
1581184610Salfred		currlun->sense_data = SS_MEDIUM_NOT_PRESENT;
1582184610Salfred		return (1);
1583184610Salfred	}
1584184610Salfred	return (0);
1585184610Salfred}
1586184610Salfred
1587184610Salfred/*------------------------------------------------------------------------*
1588184610Salfred *	ustorage_fs_do_cmd - do command
1589184610Salfred *
1590184610Salfred * Return values:
1591184610Salfred *    0: Success
1592184610Salfred * Else: Failure
1593184610Salfred *------------------------------------------------------------------------*/
1594184610Salfredstatic uint8_t
1595184610Salfredustorage_fs_do_cmd(struct ustorage_fs_softc *sc)
1596184610Salfred{
1597184610Salfred	uint8_t error = 1;
1598184610Salfred	uint8_t i;
1599190719Sthompsa	uint32_t temp;
1600190719Sthompsa	const uint32_t mask9 = (0xFFFFFFFFUL >> 9) << 9;
1601184610Salfred
1602184610Salfred	/* set default data transfer pointer */
1603184610Salfred	sc->sc_transfer.data_ptr = sc->sc_qdata;
1604184610Salfred
1605184610Salfred	DPRINTF("cmd_data[0]=0x%02x, data_rem=0x%08x\n",
1606190733Sthompsa	    sc->sc_cmd_data[0], sc->sc_transfer.data_rem);
1607184610Salfred
1608190733Sthompsa	switch (sc->sc_cmd_data[0]) {
1609184610Salfred	case SC_INQUIRY:
1610184610Salfred		sc->sc_transfer.cmd_dir = DIR_WRITE;
1611190733Sthompsa		error = ustorage_fs_min_len(sc, sc->sc_cmd_data[4], 0 - 1);
1612184610Salfred		if (error) {
1613184610Salfred			break;
1614184610Salfred		}
1615184610Salfred		error = ustorage_fs_check_cmd(sc, 6,
1616190719Sthompsa		    (1UL << 4) | 1, 0);
1617184610Salfred		if (error) {
1618184610Salfred			break;
1619184610Salfred		}
1620184610Salfred		error = ustorage_fs_inquiry(sc);
1621184610Salfred
1622184610Salfred		break;
1623184610Salfred
1624184610Salfred	case SC_MODE_SELECT_6:
1625184610Salfred		sc->sc_transfer.cmd_dir = DIR_READ;
1626190733Sthompsa		error = ustorage_fs_min_len(sc, sc->sc_cmd_data[4], 0 - 1);
1627184610Salfred		if (error) {
1628184610Salfred			break;
1629184610Salfred		}
1630184610Salfred		error = ustorage_fs_check_cmd(sc, 6,
1631190719Sthompsa		    (1UL << 1) | (1UL << 4) | 1, 0);
1632184610Salfred		if (error) {
1633184610Salfred			break;
1634184610Salfred		}
1635184610Salfred		error = ustorage_fs_mode_select(sc);
1636184610Salfred
1637184610Salfred		break;
1638184610Salfred
1639184610Salfred	case SC_MODE_SELECT_10:
1640184610Salfred		sc->sc_transfer.cmd_dir = DIR_READ;
1641184610Salfred		error = ustorage_fs_min_len(sc,
1642190733Sthompsa		    get_be16(&sc->sc_cmd_data[7]), 0 - 1);
1643184610Salfred		if (error) {
1644184610Salfred			break;
1645184610Salfred		}
1646184610Salfred		error = ustorage_fs_check_cmd(sc, 10,
1647190719Sthompsa		    (1UL << 1) | (3UL << 7) | 1, 0);
1648184610Salfred		if (error) {
1649184610Salfred			break;
1650184610Salfred		}
1651184610Salfred		error = ustorage_fs_mode_select(sc);
1652184610Salfred
1653184610Salfred		break;
1654184610Salfred
1655184610Salfred	case SC_MODE_SENSE_6:
1656184610Salfred		sc->sc_transfer.cmd_dir = DIR_WRITE;
1657190733Sthompsa		error = ustorage_fs_min_len(sc, sc->sc_cmd_data[4], 0 - 1);
1658184610Salfred		if (error) {
1659184610Salfred			break;
1660184610Salfred		}
1661184610Salfred		error = ustorage_fs_check_cmd(sc, 6,
1662190719Sthompsa		    (1UL << 1) | (1UL << 2) | (1UL << 4) | 1, 0);
1663184610Salfred		if (error) {
1664184610Salfred			break;
1665184610Salfred		}
1666184610Salfred		error = ustorage_fs_mode_sense(sc);
1667184610Salfred
1668184610Salfred		break;
1669184610Salfred
1670184610Salfred	case SC_MODE_SENSE_10:
1671184610Salfred		sc->sc_transfer.cmd_dir = DIR_WRITE;
1672184610Salfred		error = ustorage_fs_min_len(sc,
1673190733Sthompsa		    get_be16(&sc->sc_cmd_data[7]), 0 - 1);
1674184610Salfred		if (error) {
1675184610Salfred			break;
1676184610Salfred		}
1677184610Salfred		error = ustorage_fs_check_cmd(sc, 10,
1678190719Sthompsa		    (1UL << 1) | (1UL << 2) | (3UL << 7) | 1, 0);
1679184610Salfred		if (error) {
1680184610Salfred			break;
1681184610Salfred		}
1682184610Salfred		error = ustorage_fs_mode_sense(sc);
1683184610Salfred
1684184610Salfred		break;
1685184610Salfred
1686184610Salfred	case SC_PREVENT_ALLOW_MEDIUM_REMOVAL:
1687184610Salfred		error = ustorage_fs_min_len(sc, 0, 0 - 1);
1688184610Salfred		if (error) {
1689184610Salfred			break;
1690184610Salfred		}
1691184610Salfred		error = ustorage_fs_check_cmd(sc, 6,
1692190719Sthompsa		    (1UL << 4) | 1, 0);
1693184610Salfred		if (error) {
1694184610Salfred			break;
1695184610Salfred		}
1696184610Salfred		error = ustorage_fs_prevent_allow(sc);
1697184610Salfred
1698184610Salfred		break;
1699184610Salfred
1700184610Salfred	case SC_READ_6:
1701190733Sthompsa		i = sc->sc_cmd_data[4];
1702184610Salfred		sc->sc_transfer.cmd_dir = DIR_WRITE;
1703190719Sthompsa		temp = ((i == 0) ? 256UL : i);
1704190719Sthompsa		error = ustorage_fs_min_len(sc, temp << 9, mask9);
1705184610Salfred		if (error) {
1706184610Salfred			break;
1707184610Salfred		}
1708184610Salfred		error = ustorage_fs_check_cmd(sc, 6,
1709190719Sthompsa		    (7UL << 1) | (1UL << 4) | 1, 1);
1710184610Salfred		if (error) {
1711184610Salfred			break;
1712184610Salfred		}
1713184610Salfred		error = ustorage_fs_read(sc);
1714184610Salfred
1715184610Salfred		break;
1716184610Salfred
1717184610Salfred	case SC_READ_10:
1718184610Salfred		sc->sc_transfer.cmd_dir = DIR_WRITE;
1719190733Sthompsa		temp = get_be16(&sc->sc_cmd_data[7]);
1720190719Sthompsa		error = ustorage_fs_min_len(sc, temp << 9, mask9);
1721184610Salfred		if (error) {
1722184610Salfred			break;
1723184610Salfred		}
1724184610Salfred		error = ustorage_fs_check_cmd(sc, 10,
1725190719Sthompsa		    (1UL << 1) | (0xfUL << 2) | (3UL << 7) | 1, 1);
1726184610Salfred		if (error) {
1727184610Salfred			break;
1728184610Salfred		}
1729184610Salfred		error = ustorage_fs_read(sc);
1730184610Salfred
1731184610Salfred		break;
1732184610Salfred
1733184610Salfred	case SC_READ_12:
1734184610Salfred		sc->sc_transfer.cmd_dir = DIR_WRITE;
1735190733Sthompsa		temp = get_be32(&sc->sc_cmd_data[6]);
1736190719Sthompsa		if (temp >= (1UL << (32 - 9))) {
1737190719Sthompsa			/* numerical overflow */
1738190719Sthompsa			sc->sc_csw.bCSWStatus = CSWSTATUS_FAILED;
1739190719Sthompsa			error = 1;
1740190719Sthompsa			break;
1741190719Sthompsa		}
1742190719Sthompsa		error = ustorage_fs_min_len(sc, temp << 9, mask9);
1743184610Salfred		if (error) {
1744184610Salfred			break;
1745184610Salfred		}
1746184610Salfred		error = ustorage_fs_check_cmd(sc, 12,
1747190719Sthompsa		    (1UL << 1) | (0xfUL << 2) | (0xfUL << 6) | 1, 1);
1748184610Salfred		if (error) {
1749184610Salfred			break;
1750184610Salfred		}
1751184610Salfred		error = ustorage_fs_read(sc);
1752184610Salfred
1753184610Salfred		break;
1754184610Salfred
1755184610Salfred	case SC_READ_CAPACITY:
1756184610Salfred		sc->sc_transfer.cmd_dir = DIR_WRITE;
1757184610Salfred		error = ustorage_fs_check_cmd(sc, 10,
1758190719Sthompsa		    (0xfUL << 2) | (1UL << 8) | 1, 1);
1759184610Salfred		if (error) {
1760184610Salfred			break;
1761184610Salfred		}
1762184610Salfred		error = ustorage_fs_read_capacity(sc);
1763184610Salfred
1764184610Salfred		break;
1765184610Salfred
1766184610Salfred	case SC_READ_FORMAT_CAPACITIES:
1767184610Salfred		sc->sc_transfer.cmd_dir = DIR_WRITE;
1768184610Salfred		error = ustorage_fs_min_len(sc,
1769190733Sthompsa		    get_be16(&sc->sc_cmd_data[7]), 0 - 1);
1770184610Salfred		if (error) {
1771184610Salfred			break;
1772184610Salfred		}
1773184610Salfred		error = ustorage_fs_check_cmd(sc, 10,
1774190719Sthompsa		    (3UL << 7) | 1, 1);
1775184610Salfred		if (error) {
1776184610Salfred			break;
1777184610Salfred		}
1778184610Salfred		error = ustorage_fs_read_format_capacities(sc);
1779184610Salfred
1780184610Salfred		break;
1781184610Salfred
1782184610Salfred	case SC_REQUEST_SENSE:
1783184610Salfred		sc->sc_transfer.cmd_dir = DIR_WRITE;
1784190733Sthompsa		error = ustorage_fs_min_len(sc, sc->sc_cmd_data[4], 0 - 1);
1785184610Salfred		if (error) {
1786184610Salfred			break;
1787184610Salfred		}
1788184610Salfred		error = ustorage_fs_check_cmd(sc, 6,
1789190719Sthompsa		    (1UL << 4) | 1, 0);
1790184610Salfred		if (error) {
1791184610Salfred			break;
1792184610Salfred		}
1793184610Salfred		error = ustorage_fs_request_sense(sc);
1794184610Salfred
1795184610Salfred		break;
1796184610Salfred
1797184610Salfred	case SC_START_STOP_UNIT:
1798184610Salfred		error = ustorage_fs_min_len(sc, 0, 0 - 1);
1799184610Salfred		if (error) {
1800184610Salfred			break;
1801184610Salfred		}
1802184610Salfred		error = ustorage_fs_check_cmd(sc, 6,
1803190719Sthompsa		    (1UL << 1) | (1UL << 4) | 1, 0);
1804184610Salfred		if (error) {
1805184610Salfred			break;
1806184610Salfred		}
1807184610Salfred		error = ustorage_fs_start_stop(sc);
1808184610Salfred
1809184610Salfred		break;
1810184610Salfred
1811184610Salfred	case SC_SYNCHRONIZE_CACHE:
1812184610Salfred		error = ustorage_fs_min_len(sc, 0, 0 - 1);
1813184610Salfred		if (error) {
1814184610Salfred			break;
1815184610Salfred		}
1816184610Salfred		error = ustorage_fs_check_cmd(sc, 10,
1817190719Sthompsa		    (0xfUL << 2) | (3UL << 7) | 1, 1);
1818184610Salfred		if (error) {
1819184610Salfred			break;
1820184610Salfred		}
1821184610Salfred		error = ustorage_fs_synchronize_cache(sc);
1822184610Salfred
1823184610Salfred		break;
1824184610Salfred
1825184610Salfred	case SC_TEST_UNIT_READY:
1826184610Salfred		error = ustorage_fs_min_len(sc, 0, 0 - 1);
1827184610Salfred		if (error) {
1828184610Salfred			break;
1829184610Salfred		}
1830184610Salfred		error = ustorage_fs_check_cmd(sc, 6,
1831184610Salfred		    0 | 1, 1);
1832184610Salfred		break;
1833184610Salfred
1834184610Salfred		/*
1835184610Salfred		 * Although optional, this command is used by MS-Windows.
1836184610Salfred		 * We support a minimal version: BytChk must be 0.
1837184610Salfred		 */
1838184610Salfred	case SC_VERIFY:
1839184610Salfred		error = ustorage_fs_min_len(sc, 0, 0 - 1);
1840184610Salfred		if (error) {
1841184610Salfred			break;
1842184610Salfred		}
1843184610Salfred		error = ustorage_fs_check_cmd(sc, 10,
1844190719Sthompsa		    (1UL << 1) | (0xfUL << 2) | (3UL << 7) | 1, 1);
1845184610Salfred		if (error) {
1846184610Salfred			break;
1847184610Salfred		}
1848184610Salfred		error = ustorage_fs_verify(sc);
1849184610Salfred
1850184610Salfred		break;
1851184610Salfred
1852184610Salfred	case SC_WRITE_6:
1853190733Sthompsa		i = sc->sc_cmd_data[4];
1854184610Salfred		sc->sc_transfer.cmd_dir = DIR_READ;
1855190719Sthompsa		temp = ((i == 0) ? 256UL : i);
1856190719Sthompsa		error = ustorage_fs_min_len(sc, temp << 9, mask9);
1857184610Salfred		if (error) {
1858184610Salfred			break;
1859184610Salfred		}
1860184610Salfred		error = ustorage_fs_check_cmd(sc, 6,
1861190719Sthompsa		    (7UL << 1) | (1UL << 4) | 1, 1);
1862184610Salfred		if (error) {
1863184610Salfred			break;
1864184610Salfred		}
1865184610Salfred		error = ustorage_fs_write(sc);
1866184610Salfred
1867184610Salfred		break;
1868184610Salfred
1869184610Salfred	case SC_WRITE_10:
1870184610Salfred		sc->sc_transfer.cmd_dir = DIR_READ;
1871190733Sthompsa		temp = get_be16(&sc->sc_cmd_data[7]);
1872190719Sthompsa		error = ustorage_fs_min_len(sc, temp << 9, mask9);
1873184610Salfred		if (error) {
1874184610Salfred			break;
1875184610Salfred		}
1876184610Salfred		error = ustorage_fs_check_cmd(sc, 10,
1877190719Sthompsa		    (1UL << 1) | (0xfUL << 2) | (3UL << 7) | 1, 1);
1878184610Salfred		if (error) {
1879184610Salfred			break;
1880184610Salfred		}
1881184610Salfred		error = ustorage_fs_write(sc);
1882184610Salfred
1883184610Salfred		break;
1884184610Salfred
1885184610Salfred	case SC_WRITE_12:
1886184610Salfred		sc->sc_transfer.cmd_dir = DIR_READ;
1887190733Sthompsa		temp = get_be32(&sc->sc_cmd_data[6]);
1888190719Sthompsa		if (temp > (mask9 >> 9)) {
1889190719Sthompsa			/* numerical overflow */
1890190719Sthompsa			sc->sc_csw.bCSWStatus = CSWSTATUS_FAILED;
1891190719Sthompsa			error = 1;
1892190719Sthompsa			break;
1893190719Sthompsa		}
1894190719Sthompsa		error = ustorage_fs_min_len(sc, temp << 9, mask9);
1895184610Salfred		if (error) {
1896184610Salfred			break;
1897184610Salfred		}
1898184610Salfred		error = ustorage_fs_check_cmd(sc, 12,
1899190719Sthompsa		    (1UL << 1) | (0xfUL << 2) | (0xfUL << 6) | 1, 1);
1900184610Salfred		if (error) {
1901184610Salfred			break;
1902184610Salfred		}
1903184610Salfred		error = ustorage_fs_write(sc);
1904184610Salfred
1905184610Salfred		break;
1906184610Salfred
1907184610Salfred		/*
1908184610Salfred		 * Some mandatory commands that we recognize but don't
1909184610Salfred		 * implement.  They don't mean much in this setting.
1910184610Salfred		 * It's left as an exercise for anyone interested to
1911184610Salfred		 * implement RESERVE and RELEASE in terms of Posix
1912184610Salfred		 * locks.
1913184610Salfred		 */
1914184610Salfred	case SC_FORMAT_UNIT:
1915184610Salfred	case SC_RELEASE:
1916184610Salfred	case SC_RESERVE:
1917184610Salfred	case SC_SEND_DIAGNOSTIC:
1918184610Salfred		/* Fallthrough */
1919184610Salfred
1920184610Salfred	default:
1921184610Salfred		error = ustorage_fs_min_len(sc, 0, 0 - 1);
1922184610Salfred		if (error) {
1923184610Salfred			break;
1924184610Salfred		}
1925184610Salfred		error = ustorage_fs_check_cmd(sc, sc->sc_transfer.cmd_len,
1926184610Salfred		    0xff, 0);
1927184610Salfred		if (error) {
1928184610Salfred			break;
1929184610Salfred		}
1930184610Salfred		sc->sc_transfer.currlun->sense_data =
1931184610Salfred		    SS_INVALID_COMMAND;
1932184610Salfred		error = 1;
1933184610Salfred
1934184610Salfred		break;
1935184610Salfred	}
1936184610Salfred	return (error);
1937184610Salfred}
1938