From owner-p4-projects@FreeBSD.ORG Mon Jul 17 11:01:59 2006 Return-Path: X-Original-To: p4-projects@freebsd.org Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id 0D39216A4F2; Mon, 17 Jul 2006 11:01:59 +0000 (UTC) X-Original-To: perforce@FreeBSD.org Delivered-To: perforce@FreeBSD.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id C13E316A4E5 for ; Mon, 17 Jul 2006 11:01:58 +0000 (UTC) (envelope-from hselasky@FreeBSD.org) Received: from repoman.freebsd.org (repoman.freebsd.org [216.136.204.115]) by mx1.FreeBSD.org (Postfix) with ESMTP id 8B5BA43D7C for ; Mon, 17 Jul 2006 11:01:46 +0000 (GMT) (envelope-from hselasky@FreeBSD.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.13.6/8.13.6) with ESMTP id k6HB1kf4074129 for ; Mon, 17 Jul 2006 11:01:46 GMT (envelope-from hselasky@FreeBSD.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.13.6/8.13.4/Submit) id k6HB1jVN074126 for perforce@freebsd.org; Mon, 17 Jul 2006 11:01:45 GMT (envelope-from hselasky@FreeBSD.org) Date: Mon, 17 Jul 2006 11:01:45 GMT Message-Id: <200607171101.k6HB1jVN074126@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to hselasky@FreeBSD.org using -f From: Hans Petter Selasky To: Perforce Change Reviews Cc: Subject: PERFORCE change 101747 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 17 Jul 2006 11:01:59 -0000 http://perforce.freebsd.org/chv.cgi?CH=101747 Change 101747 by hselasky@hselasky_mini_itx on 2006/07/17 11:00:53 Finished converting "ata-usb.c". Please test. Affected files ... .. //depot/projects/usb/src/sys/dev/ata/ata-usb.c#2 edit Differences ... ==== //depot/projects/usb/src/sys/dev/ata/ata-usb.c#2 (text) ==== @@ -24,34 +24,30 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include "opt_ata.h" + #include -__FBSDID("$FreeBSD: src/sys/dev/ata/ata-usb.c,v 1.4 2006/03/31 08:09:05 sos Exp $"); - -#include "opt_ata.h" #include -#include #include #include -#include +#include #include -#include -#include -#include -#include -#include +#include #include -#include #include -#include -#include -#include + +#include #include -#include -#include -#include +#include +#include + #include #include +__FBSDID("$FreeBSD: src/sys/dev/ata/ata-usb.c,v 1.4 2006/03/31 08:09:05 sos Exp $"); + +#define ATAUSB_BULK_SIZE (1<<17) /* don't set this lower than (1 << 16) */ + /* Command Block Wrapper */ struct bbb_cbw { u_int8_t signature[4]; @@ -68,7 +64,7 @@ #define CBWCDBLENGTH 16 u_int8_t cdb[CBWCDBLENGTH]; -}; +} UPACKED; /* Command Status Wrapper */ struct bbb_csw { @@ -81,89 +77,238 @@ #define CSWSTATUS_GOOD 0x0 #define CSWSTATUS_FAILED 0x1 #define CSWSTATUS_PHASE 0x2 -}; +} UPACKED; /* USB-ATA 'controller' softc */ struct atausb_softc { - USBBASEDEVICE dev; /* base device */ - usbd_interface_handle iface; /* interface */ - int ifaceno; /* interface number */ - u_int8_t bulkin; /* endpoint address's */ - u_int8_t bulkout; - u_int8_t bulkirq; - usbd_pipe_handle bulkin_pipe; /* pipe handle's */ - usbd_pipe_handle bulkout_pipe; - usbd_pipe_handle bulkirq_pipe; - int maxlun; - int timeout; - struct ata_request *ata_request; - usb_device_request_t usb_request; struct bbb_cbw cbw; struct bbb_csw csw; + struct mtx locked_mtx; + struct usbd_memory_wait mem_wait; + struct __callout watchdog; + + struct ata_channel *locked_ch; + struct ata_channel *restart_ch; + struct ata_request *ata_request; + +#define ATAUSB_T_BBB_RESET1 0 +#define ATAUSB_T_BBB_RESET2 1 +#define ATAUSB_T_BBB_RESET3 2 +#define ATAUSB_T_BBB_COMMAND 3 +#define ATAUSB_T_BBB_DATA_READ 4 +#define ATAUSB_T_BBB_DATA_WRITE 5 +#define ATAUSB_T_BBB_STATUS 6 +#define ATAUSB_T_BBB_INTERRUPT 7 +#define ATAUSB_T_BBB_I_CLEAR_STALL 8 +#define ATAUSB_T_MAX 9 + struct usbd_xfer * xfer[ATAUSB_T_MAX]; + caddr_t ata_data; + device_t dev; -#define ATAUSB_T_BBB_CBW 0 -#define ATAUSB_T_BBB_DATA 1 -#define ATAUSB_T_BBB_DCLEAR 2 -#define ATAUSB_T_BBB_CSW1 3 -#define ATAUSB_T_BBB_CSW2 4 -#define ATAUSB_T_BBB_SCLEAR 5 -#define ATAUSB_T_BBB_RESET1 6 -#define ATAUSB_T_BBB_RESET2 7 -#define ATAUSB_T_BBB_RESET3 8 -#define ATAUSB_T_MAX 9 - usbd_xfer_handle transfer[ATAUSB_T_MAX]; + u_int32_t timeout; + u_int32_t ata_donecount; + u_int32_t ata_bytecount; - int state; -#define ATAUSB_S_ATTACH 0 -#define ATAUSB_S_IDLE 1 -#define ATAUSB_S_BBB_COMMAND 2 -#define ATAUSB_S_BBB_DATA 3 -#define ATAUSB_S_BBB_DCLEAR 4 -#define ATAUSB_S_BBB_STATUS1 5 -#define ATAUSB_S_BBB_SCLEAR 6 -#define ATAUSB_S_BBB_STATUS2 7 -#define ATAUSB_S_BBB_RESET1 8 -#define ATAUSB_S_BBB_RESET2 9 -#define ATAUSB_S_BBB_RESET3 10 -#define ATAUSB_S_DETACH 11 + u_int8_t last_xfer_no; + u_int8_t reset_count; + u_int8_t usb_speed; + u_int8_t intr_stall_cleared; + u_int8_t maxlun; + u_int8_t iface_no; - struct mtx locked_mtx; - struct ata_channel *locked_ch; - struct ata_channel *restart_ch; }; -static int atausbdebug = 0; +static const int atausbdebug = 0; + +/* prototypes */ + +static device_probe_t atausb_probe; +static device_attach_t atausb_attach; +static device_detach_t atausb_detach; + +static void +atausb_watchdog(void *arg); + +static void +atausb_transfer_start(struct atausb_softc *sc, u_int8_t xfer_no); + +static void +atausb_t_bbb_reset1_callback(struct usbd_xfer *xfer); + +static void +atausb_t_bbb_reset2_callback(struct usbd_xfer *xfer); + +static void +atausb_t_bbb_reset3_callback(struct usbd_xfer *xfer); + +static void +atausb_t_bbb_command_callback(struct usbd_xfer *xfer); + +static void +atausb_t_bbb_data_read_callback(struct usbd_xfer *xfer); + +static void +atausb_t_bbb_data_write_callback(struct usbd_xfer *xfer); + +static void +atausb_t_bbb_status_callback(struct usbd_xfer *xfer); + +static void +atausb_t_bbb_interrupt_callback(struct usbd_xfer *xfer); + +static void +atausb_t_bbb_i_clear_stall_callback(struct usbd_xfer *xfer); + +static void +atausb_tr_error(struct usbd_xfer *xfer); + +static int +ata_usbchannel_begin_transaction(struct ata_request *request); + +static int +ata_usbchannel_end_transaction(struct ata_request *request); -/* prototypes*/ -static usbd_status atausb_start(struct atausb_softc *sc, usbd_pipe_handle pipe, void *buffer, int buflen, int flags, usbd_xfer_handle xfer); -static usbd_status atausb_ctl_start(struct atausb_softc *sc, usbd_device_handle udev, usb_device_request_t *req, void *buffer, int buflen, int flags, usbd_xfer_handle xfer); -static void atausb_clear_stall(struct atausb_softc *sc, u_int8_t endpt, usbd_pipe_handle pipe, int state, usbd_xfer_handle xfer); -static void atausb_bbb_reset(struct atausb_softc *sc); -static int atausb_bbb_start(struct ata_request *request); -static void atausb_bbb_finish(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status err); -int ata_usbchannel_begin_transaction(struct ata_request *request); -int ata_usbchannel_end_transaction(struct ata_request *request); +static device_probe_t ata_usbchannel_probe; +static device_attach_t ata_usbchannel_attach; +static device_detach_t ata_usbchannel_detach; +static ata_setmode_t ata_usbchannel_setmode; +static ata_locking_t ata_usbchannel_locking; /* * USB frontend part */ -USB_DECLARE_DRIVER(atausb); + +struct usbd_config atausb_config[ATAUSB_T_MAX] = { + + [ATAUSB_T_BBB_RESET1] = { + .type = UE_CONTROL, + .endpoint = 0x00, /* Control pipe */ + .direction = -1, + .bufsize = sizeof(usb_device_request_t), + .flags = USBD_USE_DMA, + .callback = &atausb_t_bbb_reset1_callback, + .timeout = 5000, /* 5 seconds */ + }, + + [ATAUSB_T_BBB_RESET2] = { + .type = UE_CONTROL, + .endpoint = 0x00, /* Control pipe */ + .direction = -1, + .bufsize = sizeof(usb_device_request_t), + .flags = USBD_USE_DMA, + .callback = &atausb_t_bbb_reset2_callback, + .timeout = 5000, /* 5 seconds */ + }, + + [ATAUSB_T_BBB_RESET3] = { + .type = UE_CONTROL, + .endpoint = 0x00, /* Control pipe */ + .direction = -1, + .bufsize = sizeof(usb_device_request_t), + .flags = USBD_USE_DMA, + .callback = &atausb_t_bbb_reset3_callback, + .timeout = 5000, /* 5 seconds */ + }, + + [ATAUSB_T_BBB_COMMAND] = { + .type = UE_BULK, + .endpoint = -1, /* any */ + .direction = UE_DIR_OUT, + .bufsize = sizeof(struct bbb_cbw), + .flags = USBD_USE_DMA, + .callback = &atausb_t_bbb_command_callback, + .timeout = 5000, /* 5 seconds */ + }, + + [ATAUSB_T_BBB_DATA_READ] = { + .type = UE_BULK, + .endpoint = -1, /* any */ + .direction = UE_DIR_IN, + .bufsize = ATAUSB_BULK_SIZE, + .flags = (USBD_USE_DMA|USBD_SHORT_XFER_OK), + .callback = &atausb_t_bbb_data_read_callback, + .timeout = 0, /* overwritten later */ + }, + + [ATAUSB_T_BBB_DATA_WRITE] = { + .type = UE_BULK, + .endpoint = -1, /* any */ + .direction = UE_DIR_OUT, + .bufsize = ATAUSB_BULK_SIZE, + .flags = USBD_USE_DMA, + .callback = &atausb_t_bbb_data_write_callback, + .timeout = 0, /* overwritten later */ + }, + + [ATAUSB_T_BBB_STATUS] = { + .type = UE_BULK, + .endpoint = -1, /* any */ + .direction = UE_DIR_IN, + .bufsize = sizeof(struct bbb_csw), + .flags = (USBD_USE_DMA|USBD_SHORT_XFER_OK), + .callback = &atausb_t_bbb_status_callback, + .timeout = 5000, /* ms */ + }, + + /* + * the following endpoints are only + * present on CBI devices: + */ + + [ATAUSB_T_BBB_INTERRUPT] = { + .type = UE_INTERRUPT, + .endpoint = -1, /* any */ + .direction = UE_DIR_IN, + .flags = (USBD_USE_DMA|USBD_SHORT_XFER_OK), + .bufsize = 0, /* use wMaxPacketSize */ + .callback = &atausb_t_bbb_interrupt_callback, + }, + + [ATAUSB_T_BBB_I_CLEAR_STALL] = { + .type = UE_CONTROL, + .endpoint = 0x00, /* Control pipe */ + .direction = -1, + .flags = USBD_USE_DMA, + .bufsize = sizeof(usb_device_request_t), + .callback = &atausb_t_bbb_i_clear_stall_callback, + .timeout = 5000, /* ms */ + }, +}; + +static devclass_t atausb_devclass; + +static device_method_t atausb_methods[] = { + DEVMETHOD(device_probe, atausb_probe), + DEVMETHOD(device_attach, atausb_attach), + DEVMETHOD(device_detach, atausb_detach), + { 0, 0 } +}; + +static driver_t atausb_driver = { + .name = "atausb", + .methods = atausb_methods, + .size = sizeof(struct atausb_softc), +}; + DRIVER_MODULE(atausb, uhub, atausb_driver, atausb_devclass, 0, 0); +MODULE_DEPEND(atausb, usb, 1, 1, 1); MODULE_VERSION(atausb, 1); static int -atausb_match(device_t dev) +atausb_probe(device_t dev) { struct usb_attach_arg *uaa = device_get_ivars(dev); usb_interface_descriptor_t *id; - if (uaa->iface == NULL) + if (uaa->iface == NULL) { return UMATCH_NONE; + } id = usbd_get_interface_descriptor(uaa->iface); - if (!id || id->bInterfaceClass != UICLASS_MASS) + if ((!id) || (id->bInterfaceClass != UICLASS_MASS)) { return UMATCH_NONE; + } switch (id->bInterfaceSubClass) { case UISUBCLASS_QIC157: @@ -193,27 +338,26 @@ struct atausb_softc *sc = device_get_softc(dev); struct usb_attach_arg *uaa = device_get_ivars(dev); usb_interface_descriptor_t *id; - usb_endpoint_descriptor_t *ed; - usbd_device_handle udev; + const char *proto, *subclass; usb_device_request_t request; - char devinfo[1024], *proto, *subclass; + u_int16_t i; u_int8_t maxlun; - int err, i; + u_int8_t has_intr; + int err; + + usbd_set_desc(dev, uaa->device); sc->dev = dev; - usbd_devinfo(uaa->device, 0, devinfo); - device_set_desc_copy(dev, devinfo); - sc->bulkin = sc->bulkout = sc->bulkirq = -1; - sc->bulkin_pipe = sc->bulkout_pipe= sc->bulkirq_pipe = NULL; - sc->iface = uaa->iface; - sc->ifaceno = uaa->ifaceno; sc->maxlun = 0; - sc->timeout = 5000; sc->locked_ch = NULL; sc->restart_ch = NULL; - mtx_init(&sc->locked_mtx, "ATAUSB lock", NULL, MTX_DEF); + sc->usb_speed = usbd_get_speed(uaa->device); + mtx_init(&(sc->locked_mtx), "ATAUSB lock", NULL, MTX_DEF); + + __callout_init_mtx(&(sc->watchdog), + &(sc->locked_mtx), CALLOUT_RETURNUNLOCKED); - id = usbd_get_interface_descriptor(sc->iface); + id = usbd_get_interface_descriptor(uaa->iface); switch (id->bInterfaceProtocol) { case UIPROTO_MASS_BBB: case UIPROTO_MASS_BBB_OLD: @@ -228,6 +372,7 @@ default: proto = "Unknown"; } + switch (id->bInterfaceSubClass) { case UISUBCLASS_RBC: subclass = "RBC"; @@ -246,93 +391,44 @@ default: subclass = "Unknown"; } + + has_intr = (id->bInterfaceProtocol == UIPROTO_MASS_CBI_I); + sc->iface_no = id->bInterfaceNumber; + device_printf(dev, "using %s over %s\n", subclass, proto); if (strcmp(proto, "Bulk-Only") || - (strcmp(subclass, "ATAPI") && strcmp(subclass, "SCSI"))) - return ENXIO; - - for (i = 0 ; i < id->bNumEndpoints ; i++) { - if (!(ed = usbd_interface2endpoint_descriptor(sc->iface, i))) { - device_printf(sc->dev, "could not read endpoint descriptor\n"); - return ENXIO; - } - if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && - (ed->bmAttributes & UE_XFERTYPE) == UE_BULK) { - sc->bulkin = ed->bEndpointAddress; - } - if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && - (ed->bmAttributes & UE_XFERTYPE) == UE_BULK) { - sc->bulkout = ed->bEndpointAddress; - } - if (id->bInterfaceProtocol == UIPROTO_MASS_CBI_I && - UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && - (ed->bmAttributes & UE_XFERTYPE) == UE_INTERRUPT) { - sc->bulkirq = ed->bEndpointAddress; - } - } - - /* check whether we found at least the endpoints we need */ - if (!sc->bulkin || !sc->bulkout) { - device_printf(sc->dev, "needed endpoints not found (%d,%d)\n", - sc->bulkin, sc->bulkout); - atausb_detach(dev); + (strcmp(subclass, "ATAPI") && strcmp(subclass, "SCSI"))) { return ENXIO; } - /* open the pipes */ - if (usbd_open_pipe(sc->iface, sc->bulkout, - USBD_EXCLUSIVE_USE, &sc->bulkout_pipe)) { - device_printf(sc->dev, "cannot open bulkout pipe (%d)\n", sc->bulkout); - atausb_detach(dev); - return ENXIO; - } - if (usbd_open_pipe(sc->iface, sc->bulkin, - USBD_EXCLUSIVE_USE, &sc->bulkin_pipe)) { - device_printf(sc->dev, "cannot open bulkin pipe (%d)\n", sc->bulkin); - atausb_detach(dev); - return ENXIO; - } - if (id->bInterfaceProtocol == UIPROTO_MASS_CBI_I) { - if (usbd_open_pipe(sc->iface, sc->bulkirq, - USBD_EXCLUSIVE_USE, &sc->bulkirq_pipe)) { - device_printf(sc->dev, "cannot open bulkirq pipe (%d)\n", - sc->bulkirq); - atausb_detach(dev); - return ENXIO; - } + err = usbd_transfer_setup(uaa->device, uaa->iface_index, sc->xfer, + atausb_config, + has_intr ? ATAUSB_T_MAX : (ATAUSB_T_MAX-2), sc, + &(sc->locked_mtx), &(sc->mem_wait)); + if (err) { + device_printf(sc->dev, "could not setup required " + "transfers, %s\n", usbd_errstr(err)); + goto detach; } - sc->state = ATAUSB_S_ATTACH; - /* alloc needed number of transfer handles */ - for (i = 0; i < ATAUSB_T_MAX; i++) { - sc->transfer[i] = usbd_alloc_xfer(uaa->device); - if (!sc->transfer[i]) { - device_printf(sc->dev, "out of memory\n"); - atausb_detach(dev); - return ENXIO; - } - } - - /* driver is ready to process requests here */ - sc->state = ATAUSB_S_IDLE; - /* get number of devices so we can add matching channels */ - usbd_interface2device_handle(sc->iface, &udev); request.bmRequestType = UT_READ_CLASS_INTERFACE; - request.bRequest = 0xfe; //GET_MAX_LUN; + request.bRequest = 0xfe; /* GET_MAX_LUN; */ USETW(request.wValue, 0); - USETW(request.wIndex, sc->ifaceno); + USETW(request.wIndex, sc->iface_no); USETW(request.wLength, sizeof(maxlun)); - switch ((err = usbd_do_request(udev, &request, &maxlun))) { - case USBD_NORMAL_COMPLETION: - if (bootverbose) - device_printf(sc->dev, "maxlun=%d\n", maxlun); + err = usbd_do_request(uaa->device, &request, &maxlun); + + if (err) { + if (bootverbose) { + device_printf(sc->dev, "get maxlun not supported %s\n", + usbd_errstr(err)); + } + } else { sc->maxlun = maxlun; - break; - default: - if (bootverbose) - device_printf(sc->dev, "get maxlun not supported %s\n", - usbd_errstr(err)); + if (bootverbose) { + device_printf(sc->dev, "maxlun=%d\n", sc->maxlun); + } } /* ata channels are children to this USB control device */ @@ -340,403 +436,469 @@ if (!device_add_child(sc->dev, "ata", devclass_find_free_unit(ata_devclass, 2))) { device_printf(sc->dev, "failed to attach ata child device\n"); - atausb_detach(dev); - return ENXIO; + goto detach; } } bus_generic_attach(sc->dev); + + /* start the watchdog */ + + mtx_lock(&(sc->locked_mtx)); + + atausb_watchdog(sc); + return 0; + + detach: + atausb_detach(dev); + return ENXIO; } static int -atausb_detach(device_ptr_t dev) +atausb_detach(device_t dev) { struct atausb_softc *sc = device_get_softc(dev); - usbd_device_handle udev; device_t *children; int nchildren, i; + mtx_lock(&(sc->locked_mtx)); + + /* stop watchdog */ + __callout_stop(&(sc->watchdog)); + /* signal that device is going away */ - sc->state = ATAUSB_S_DETACH; + sc->last_xfer_no = ATAUSB_T_MAX; + + /* stop all transfers, if any */ + for (i = 0; i < ATAUSB_T_MAX; i++) { + if (sc->xfer[i]) { + usbd_transfer_stop(sc->xfer[i]); + } + } + + mtx_unlock(&(sc->locked_mtx)); - /* abort all the pipes in case there are active transfers */ - usbd_interface2device_handle(sc->iface, &udev); - usbd_abort_default_pipe(udev); - if (sc->bulkout_pipe) - usbd_abort_pipe(sc->bulkout_pipe); - if (sc->bulkin_pipe) - usbd_abort_pipe(sc->bulkin_pipe); - if (sc->bulkirq_pipe) - usbd_abort_pipe(sc->bulkirq_pipe); + /* detach & delete all children, if any */ - /* detach & delete all children */ if (!device_get_children(dev, &children, &nchildren)) { - for (i = 0; i < nchildren; i++) + for (i = 0; i < nchildren; i++) { device_delete_child(dev, children[i]); + } free(children, M_TEMP); } - /* free the transfers */ - for (i = 0; i < ATAUSB_T_MAX; i++) - if (sc->transfer[i]) - usbd_free_xfer(sc->transfer[i]); + usbd_transfer_unsetup(sc->xfer, ATAUSB_T_MAX); - /* remove all the pipes */ - if (sc->bulkout_pipe) - usbd_close_pipe(sc->bulkout_pipe); - if (sc->bulkin_pipe) - usbd_close_pipe(sc->bulkin_pipe); - if (sc->bulkirq_pipe) - usbd_close_pipe(sc->bulkirq_pipe); + usbd_transfer_drain(&(sc->mem_wait), &(sc->locked_mtx)); mtx_destroy(&sc->locked_mtx); return 0; } - -/* - * Generic USB transfer routines - */ -static usbd_status -atausb_start(struct atausb_softc *sc, usbd_pipe_handle pipe, - void *buffer, int buflen, int flags, usbd_xfer_handle xfer) +static void +atausb_watchdog(void *arg) { - usbd_status err; + struct atausb_softc *sc = arg; - if (sc->state == ATAUSB_S_DETACH) - return USBD_NOT_STARTED; + mtx_assert(&(sc->locked_mtx), MA_OWNED); - usbd_setup_xfer(xfer, pipe, (void *)sc, buffer, buflen, flags, - sc->timeout, atausb_bbb_finish); - err = usbd_transfer(xfer); - if (err && (err != USBD_IN_PROGRESS)) { - if (atausbdebug) - device_printf(sc->dev, "failed to setup transfer, %s\n", - usbd_errstr(err)); - return err; + if (sc->xfer[ATAUSB_T_BBB_INTERRUPT]) { + /* start the interrupt pipe, in case it stopped */ + usbd_transfer_start(sc->xfer[ATAUSB_T_BBB_INTERRUPT]); } - return USBD_NORMAL_COMPLETION; + + __callout_reset(&(sc->watchdog), + hz, &atausb_watchdog, sc); + + mtx_unlock(&(sc->locked_mtx)); + return; +} + +static void +atausb_transfer_start(struct atausb_softc *sc, u_int8_t xfer_no) +{ +#if 0 + device_printf(sc->dev, "BBB transfer %d\n", xfer_no); +#endif + sc->last_xfer_no = xfer_no; + usbd_transfer_start(sc->xfer[xfer_no]); + return; } -static usbd_status -atausb_ctl_start(struct atausb_softc *sc, usbd_device_handle udev, - usb_device_request_t *req, void *buffer, int buflen, int flags, - usbd_xfer_handle xfer) +static void +atausb_t_bbb_reset1_callback(struct usbd_xfer *xfer) { - usbd_status err; + struct atausb_softc *sc = xfer->priv_sc; + usb_device_request_t req; + + USBD_CHECK_STATUS(xfer); + + tr_error: + atausb_tr_error(xfer); + return; - if (sc->state == ATAUSB_S_DETACH) - return USBD_NOT_STARTED; + tr_transferred: + atausb_transfer_start(sc, ATAUSB_T_BBB_RESET2); + return; - usbd_setup_default_xfer(xfer, udev, (void *)sc, sc->timeout, req, - buffer, buflen, flags, atausb_bbb_finish); - err = usbd_transfer(xfer); - if (err && (err != USBD_IN_PROGRESS)) { - if (atausbdebug) - device_printf(sc->dev, "failed to setup ctl transfer, %s\n", - usbd_errstr(err)); - return err; + tr_setup: + if (sc->reset_count >= 16) { + device_printf(sc->dev, "timeout: giving up reset!\n"); + return; } - return USBD_NORMAL_COMPLETION; + + sc->reset_count ++; + + req.bmRequestType = UT_WRITE_CLASS_INTERFACE; + req.bRequest = 0xff; /* bulk-only reset */ + USETW(req.wValue, 0); + USETW(req.wIndex, sc->iface_no); + USETW(req.wLength, 0); + + usbd_copy_in(&(xfer->buf_data), 0, &req, sizeof(req)); + + usbd_start_hardware(xfer); + return; } static void -atausb_clear_stall(struct atausb_softc *sc, u_int8_t endpt, - usbd_pipe_handle pipe, int state, usbd_xfer_handle xfer) +atausb_t_bbb_reset2_callback(struct usbd_xfer *xfer) { - usbd_device_handle udev; + struct atausb_softc *sc = xfer->priv_sc; + + USBD_CHECK_STATUS(xfer); + + tr_error: + atausb_tr_error(xfer); + return; + + tr_transferred: + atausb_transfer_start(sc, ATAUSB_T_BBB_RESET3); + return; - if (atausbdebug) - device_printf(sc->dev, "clear endpoint 0x%02x stall\n", endpt); - usbd_interface2device_handle(sc->iface, &udev); - sc->state = state; - usbd_clear_endpoint_toggle(pipe); - sc->usb_request.bmRequestType = UT_WRITE_ENDPOINT; - sc->usb_request.bRequest = UR_CLEAR_FEATURE; - USETW(sc->usb_request.wValue, UF_ENDPOINT_HALT); - USETW(sc->usb_request.wIndex, endpt); - USETW(sc->usb_request.wLength, 0); - atausb_ctl_start(sc, udev, &sc->usb_request, NULL, 0, 0, xfer); + tr_setup: + usbd_clear_stall_tr_setup(xfer, sc->xfer[ATAUSB_T_BBB_DATA_READ]); + usbd_clear_stall_tr_transferred(xfer, sc->xfer[ATAUSB_T_BBB_DATA_READ]); + return; } +static void +atausb_t_bbb_reset3_callback(struct usbd_xfer *xfer) +{ + struct atausb_softc *sc = xfer->priv_sc; + + USBD_CHECK_STATUS(xfer); + + tr_error: + atausb_tr_error(xfer); + return; + + tr_transferred: + atausb_transfer_start(sc, ATAUSB_T_BBB_COMMAND); + return; -/* - * Bulk-Only transport part - */ + tr_setup: + usbd_clear_stall_tr_setup(xfer, sc->xfer[ATAUSB_T_BBB_DATA_WRITE]); + usbd_clear_stall_tr_transferred(xfer, sc->xfer[ATAUSB_T_BBB_DATA_WRITE]); + return; +} + static void -atausb_bbb_reset(struct atausb_softc *sc) +atausb_t_bbb_command_callback(struct usbd_xfer *xfer) { - usbd_device_handle udev; + struct atausb_softc *sc = xfer->priv_sc; + struct ata_request *request = sc->ata_request; + struct ata_channel *ch; + + USBD_CHECK_STATUS(xfer); + + tr_error: + atausb_tr_error(xfer); + return; + + tr_transferred: + atausb_transfer_start + (sc, ((request->flags & ATA_R_READ) ? ATAUSB_T_BBB_DATA_READ : + (request->flags & ATA_R_WRITE) ? ATAUSB_T_BBB_DATA_WRITE : + ATAUSB_T_BBB_STATUS)); + return; + + tr_setup: + + sc->reset_count = 0; + + if (request) { + ch = device_get_softc(request->parent); + + sc->timeout = (request->timeout * 1000) + 5000; + + USETDW(sc->cbw.signature, CBWSIGNATURE); + USETDW(sc->cbw.tag, UGETDW(sc->cbw.tag) + 1); + USETDW(sc->cbw.transfer_length, request->bytecount); + sc->cbw.flags = (request->flags & ATA_R_READ) ? CBWFLAGS_IN : CBWFLAGS_OUT; + sc->cbw.lun = ch->unit; + sc->cbw.length = 16; + bzero(sc->cbw.cdb, 16); + bcopy(request->u.atapi.ccb, sc->cbw.cdb, 12); /* XXX SOS */ + + usbd_copy_in(&(xfer->buf_data), 0, &(sc->cbw), sizeof(sc->cbw)); - if (atausbdebug) - device_printf(sc->dev, "Bulk Reset\n"); - sc->timeout = 5000; - sc->state = ATAUSB_S_BBB_RESET1; - usbd_interface2device_handle(sc->iface, &udev); - sc->usb_request.bmRequestType = UT_WRITE_CLASS_INTERFACE; - sc->usb_request.bRequest = 0xff; /* bulk-only reset */ - USETW(sc->usb_request.wValue, 0); - USETW(sc->usb_request.wIndex, sc->ifaceno); - USETW(sc->usb_request.wLength, 0); - atausb_ctl_start(sc, udev, &sc->usb_request, NULL, - 0, 0, sc->transfer[ATAUSB_T_BBB_RESET1]); + usbd_start_hardware(xfer); + } + return; } -static int -atausb_bbb_start(struct ata_request *request) +static void +atausb_t_bbb_data_read_callback(struct usbd_xfer *xfer) { - struct atausb_softc *sc = - device_get_softc(device_get_parent(request->parent)); - struct ata_channel *ch = device_get_softc(request->parent); + struct atausb_softc *sc = xfer->priv_sc; + u_int32_t max_bulk = (ATAUSB_BULK_SIZE - + (ATAUSB_BULK_SIZE % xfer->max_packet_size)); + USBD_CHECK_STATUS(xfer); + + tr_error: + atausb_tr_error(xfer); + return; + + tr_transferred: + + usbd_copy_out(&(xfer->buf_data), 0, + sc->ata_data, xfer->actlen); + + sc->ata_bytecount -= xfer->actlen; + sc->ata_data += xfer->actlen; + sc->ata_donecount += xfer->actlen; + + if (xfer->actlen < xfer->length) { + /* short transfer */ + sc->ata_bytecount = 0; + } + + tr_setup: + if (sc->ata_bytecount == 0) { + atausb_transfer_start(sc, ATAUSB_T_BBB_STATUS); + return; + } - sc->timeout = (request->timeout * 1000) + 5000; - USETDW(sc->cbw.signature, CBWSIGNATURE); - USETDW(sc->cbw.tag, UGETDW(sc->cbw.tag) + 1); - USETDW(sc->cbw.transfer_length, request->bytecount); - sc->cbw.flags = (request->flags & ATA_R_READ) ? CBWFLAGS_IN : CBWFLAGS_OUT; - sc->cbw.lun = ch->unit; - sc->cbw.length = 16; - bzero(sc->cbw.cdb, 16); - bcopy(request->u.atapi.ccb, sc->cbw.cdb, 12); /* XXX SOS */ - sc->state = ATAUSB_S_BBB_COMMAND; - if (atausb_start(sc, sc->bulkout_pipe, &sc->cbw, sizeof(struct bbb_cbw), - 0, sc->transfer[ATAUSB_T_BBB_CBW])) { - request->result = EIO; - if (atausbdebug) - device_printf(request->dev, "cannot setup USB transfer\n"); - atausb_bbb_reset(sc); - return ATA_OP_FINISHED; + if (max_bulk > sc->ata_bytecount) { + max_bulk = sc->ata_bytecount; } - return ATA_OP_CONTINUES; + + xfer->timeout = sc->timeout; + xfer->length = max_bulk; + + usbd_start_hardware(xfer); + return; } static void -atausb_bbb_finish(usbd_xfer_handle xfer, usbd_private_handle priv, - usbd_status err) +atausb_t_bbb_data_write_callback(struct usbd_xfer *xfer) { - struct atausb_softc *sc = (struct atausb_softc *)priv; - struct ata_request *request = sc->ata_request; - usbd_xfer_handle next_xfer; + struct atausb_softc *sc = xfer->priv_sc; + u_int32_t max_bulk = (ATAUSB_BULK_SIZE - + (ATAUSB_BULK_SIZE % xfer->max_packet_size)); + USBD_CHECK_STATUS(xfer); + + tr_error: + atausb_tr_error(xfer); + return; + + tr_transferred: + + sc->ata_bytecount -= xfer->actlen; + sc->ata_data += xfer->actlen; + sc->ata_donecount += xfer->actlen; - //device_printf(sc->dev, "BBB state %d: %s\n", sc->state, usbd_errstr(err)); + tr_setup: - if (sc->state == ATAUSB_S_DETACH) { - device_printf(sc->dev, "WARNING - device has been removed\n"); + if (sc->ata_bytecount == 0) { + atausb_transfer_start(sc, ATAUSB_T_BBB_STATUS); return; } - switch (sc->state) { - case ATAUSB_S_BBB_COMMAND: /* command transport phase */ - if (err) { - if (atausbdebug) - device_printf(sc->dev, "failed to send CBW\n"); - request->result = EIO; - atausb_bbb_reset(sc); - return; - } + if (max_bulk > sc->ata_bytecount) { + max_bulk = sc->ata_bytecount; + } + + xfer->timeout = sc->timeout; + xfer->length = max_bulk; + + usbd_copy_in(&(xfer->buf_data), 0, + sc->ata_data, max_bulk); + + usbd_start_hardware(xfer); + return; +} + +static void +atausb_t_bbb_status_callback(struct usbd_xfer *xfer) +{ + struct atausb_softc *sc = xfer->priv_sc; + struct ata_request *request = sc->ata_request; + u_int32_t residue; + + USBD_CHECK_STATUS(xfer); - /* next is data transport phase, setup transfer */ - sc->state = ATAUSB_S_BBB_DATA; - if (request->flags & ATA_R_READ) { - if (atausb_start(sc, sc->bulkin_pipe, - request->data, request->bytecount, - USBD_SHORT_XFER_OK, - sc->transfer[ATAUSB_T_BBB_DATA])) { - request->result = EIO; - atausb_bbb_reset(sc); - } - return; - } - if (request->flags & ATA_R_WRITE) { - if (atausb_start(sc, sc->bulkout_pipe, - request->data, request->bytecount, - 0, sc->transfer[ATAUSB_T_BBB_DATA])) { - request->result = EIO; - atausb_bbb_reset(sc); - } - return; - } - /* FALLTHROUGH */ + tr_error: + atausb_tr_error(xfer); + return; - case ATAUSB_S_BBB_DATA: /* data transport phase */ - if (request->flags & (ATA_R_READ | ATA_R_WRITE)) { - usbd_get_xfer_status(xfer, NULL, NULL, &request->donecount, NULL); >>> TRUNCATED FOR MAIL (1000 lines) <<<