1/* $FreeBSD: head/sys/dev/usb/usb_msctest.c 244503 2012-12-20 18:38:02Z hselasky $ */ |
2/*- 3 * Copyright (c) 2008,2011 Hans Petter Selasky. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. --- 124 unchanged lines hidden (view full) --- 134#define CSWSTATUS_GOOD 0x0 135#define CSWSTATUS_FAILED 0x1 136#define CSWSTATUS_PHASE 0x2 137} __packed; 138 139struct bbb_transfer { 140 struct mtx mtx; 141 struct cv cv; |
142 struct bbb_cbw *cbw; 143 struct bbb_csw *csw; |
144 145 struct usb_xfer *xfer[ST_MAX]; 146 147 uint8_t *data_ptr; 148 149 usb_size_t data_len; /* bytes */ 150 usb_size_t data_rem; /* bytes */ 151 usb_timeout_t data_timeout; /* ms */ 152 usb_frlength_t actlen; /* bytes */ 153 154 uint8_t cmd_len; /* bytes */ 155 uint8_t dir; 156 uint8_t lun; 157 uint8_t state; 158 uint8_t status_try; 159 int error; 160 |
161 uint8_t *buffer; |
162}; 163 164static usb_callback_t bbb_command_callback; 165static usb_callback_t bbb_data_read_callback; 166static usb_callback_t bbb_data_rd_cs_callback; 167static usb_callback_t bbb_data_write_callback; 168static usb_callback_t bbb_data_wr_cs_callback; 169static usb_callback_t bbb_status_callback; --- 9 unchanged lines hidden (view full) --- 179 180static const struct usb_config bbb_config[ST_MAX] = { 181 182 [ST_COMMAND] = { 183 .type = UE_BULK, 184 .endpoint = UE_ADDR_ANY, 185 .direction = UE_DIR_OUT, 186 .bufsize = sizeof(struct bbb_cbw), |
187 .callback = &bbb_command_callback, 188 .timeout = 4 * USB_MS_HZ, /* 4 seconds */ 189 }, 190 191 [ST_DATA_RD] = { 192 .type = UE_BULK, 193 .endpoint = UE_ADDR_ANY, 194 .direction = UE_DIR_IN, |
195 .bufsize = MAX(SCSI_MAX_LEN, BULK_SIZE), 196 .flags = {.proxy_buffer = 1,.short_xfer_ok = 1,}, |
197 .callback = &bbb_data_read_callback, 198 .timeout = 4 * USB_MS_HZ, /* 4 seconds */ 199 }, 200 201 [ST_DATA_RD_CS] = { 202 .type = UE_CONTROL, 203 .endpoint = 0x00, /* Control pipe */ 204 .direction = UE_DIR_ANY, --- 21 unchanged lines hidden (view full) --- 226 .timeout = 1 * USB_MS_HZ, /* 1 second */ 227 }, 228 229 [ST_STATUS] = { 230 .type = UE_BULK, 231 .endpoint = UE_ADDR_ANY, 232 .direction = UE_DIR_IN, 233 .bufsize = sizeof(struct bbb_csw), |
234 .flags = {.short_xfer_ok = 1,}, |
235 .callback = &bbb_status_callback, 236 .timeout = 1 * USB_MS_HZ, /* 1 second */ 237 }, 238}; 239 240static void 241bbb_done(struct bbb_transfer *sc, int error) 242{ |
243 sc->error = error; 244 sc->state = ST_COMMAND; 245 sc->status_try = 1; 246 cv_signal(&sc->cv); 247} 248 249static void 250bbb_transfer_start(struct bbb_transfer *sc, uint8_t xfer_index) --- 32 unchanged lines hidden (view full) --- 283 bbb_transfer_start 284 (sc, ((sc->dir == DIR_IN) ? ST_DATA_RD : 285 (sc->dir == DIR_OUT) ? ST_DATA_WR : 286 ST_STATUS)); 287 break; 288 289 case USB_ST_SETUP: 290 sc->status_try = 0; |
291 tag = UGETDW(sc->cbw->dCBWTag) + 1; 292 USETDW(sc->cbw->dCBWSignature, CBWSIGNATURE); 293 USETDW(sc->cbw->dCBWTag, tag); 294 USETDW(sc->cbw->dCBWDataTransferLength, (uint32_t)sc->data_len); 295 sc->cbw->bCBWFlags = ((sc->dir == DIR_IN) ? CBWFLAGS_IN : CBWFLAGS_OUT); 296 sc->cbw->bCBWLUN = sc->lun; 297 sc->cbw->bCDBLength = sc->cmd_len; 298 if (sc->cbw->bCDBLength > sizeof(sc->cbw->CBWCDB)) { 299 sc->cbw->bCDBLength = sizeof(sc->cbw->CBWCDB); |
300 DPRINTFN(0, "Truncating long command\n"); 301 } |
302 usbd_transfer_submit(xfer); 303 break; 304 305 default: /* Error */ 306 bbb_done(sc, error); 307 break; 308 } 309} --- 112 unchanged lines hidden (view full) --- 422 423 usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL); 424 425 switch (USB_GET_STATE(xfer)) { 426 case USB_ST_TRANSFERRED: 427 428 /* very simple status check */ 429 |
430 if (actlen < (int)sizeof(struct bbb_csw)) { |
431 bbb_done(sc, USB_ERR_SHORT_XFER); |
432 } else if (sc->csw->bCSWStatus == CSWSTATUS_GOOD) { |
433 bbb_done(sc, 0); /* success */ 434 } else { 435 bbb_done(sc, ERR_CSW_FAILED); /* error */ 436 } 437 break; 438 439 case USB_ST_SETUP: |
440 usbd_transfer_submit(xfer); 441 break; 442 443 default: 444 DPRINTF("Failed to read CSW: %s, try %d\n", 445 usbd_errstr(error), sc->status_try); 446 447 if (error == USB_ERR_CANCELLED || sc->status_try) { --- 21 unchanged lines hidden (view full) --- 469 sc->lun = lun; 470 sc->dir = data_len ? dir : DIR_NONE; 471 sc->data_ptr = data_ptr; 472 sc->data_len = data_len; 473 sc->data_rem = data_len; 474 sc->data_timeout = (data_timeout + USB_MS_HZ); 475 sc->actlen = 0; 476 sc->cmd_len = cmd_len; |
477 memset(&sc->cbw->CBWCDB, 0, sizeof(sc->cbw->CBWCDB)); 478 memcpy(&sc->cbw->CBWCDB, cmd_ptr, cmd_len); 479 DPRINTFN(1, "SCSI cmd = %*D\n", (int)cmd_len, (char *)sc->cbw->CBWCDB, ":"); |
480 481 mtx_lock(&sc->mtx); 482 usbd_transfer_start(sc->xfer[sc->state]); 483 484 while (usbd_transfer_pending(sc->xfer[sc->state])) { 485 cv_wait(&sc->cv, &sc->mtx); 486 } 487 mtx_unlock(&sc->mtx); --- 57 unchanged lines hidden (view full) --- 545 cv_init(&sc->cv, "WBBB"); 546 547 err = usbd_transfer_setup(udev, &iface_index, sc->xfer, bbb_config, 548 ST_MAX, sc, &sc->mtx); 549 if (err) { 550 bbb_detach(sc); 551 return (NULL); 552 } |
553 /* store pointer to DMA buffers */ 554 sc->buffer = usbd_xfer_get_frame_buffer( 555 sc->xfer[ST_DATA_RD], 0); 556 sc->cbw = usbd_xfer_get_frame_buffer( 557 sc->xfer[ST_COMMAND], 0); 558 sc->csw = usbd_xfer_get_frame_buffer( 559 sc->xfer[ST_STATUS], 0); 560 |
561 return (sc); 562} 563 564static void 565bbb_detach(struct bbb_transfer *sc) 566{ 567 usbd_transfer_unsetup(sc->xfer, ST_MAX); 568 mtx_destroy(&sc->mtx); --- 280 unchanged lines hidden --- |