1/* ********************************************************************* 2 * Broadcom Common Firmware Environment (CFE) 3 * 4 * USB Mass-Storage driver File: usbmass.c 5 * 6 * This driver deals with mass-storage devices that support 7 * the SCSI Transparent command set and USB Bulk-Only protocol 8 * 9 * Author: Mitch Lichtenberg 10 * 11 ********************************************************************* 12 * 13 * Copyright 2000,2001,2002,2003 14 * Broadcom Corporation. All rights reserved. 15 * 16 * This software is furnished under license and may be used and 17 * copied only in accordance with the following terms and 18 * conditions. Subject to these conditions, you may download, 19 * copy, install, use, modify and distribute modified or unmodified 20 * copies of this software in source and/or binary form. No title 21 * or ownership is transferred hereby. 22 * 23 * 1) Any source code used, modified or distributed must reproduce 24 * and retain this copyright notice and list of conditions 25 * as they appear in the source file. 26 * 27 * 2) No right is granted to use any trade name, trademark, or 28 * logo of Broadcom Corporation. The "Broadcom Corporation" 29 * name may not be used to endorse or promote products derived 30 * from this software without the prior written permission of 31 * Broadcom Corporation. 32 * 33 * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR 34 * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED 35 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 36 * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT 37 * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN 38 * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, 39 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 40 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 41 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 42 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 43 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 44 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF 45 * THE POSSIBILITY OF SUCH DAMAGE. 46 ********************************************************************* */ 47 48 49#ifndef _CFE_ 50#include <stdio.h> 51#include <time.h> 52#include <memory.h> 53#include <stdint.h> 54#include "usbhack.h" 55#include "lib_malloc.h" 56#include "lib_queue.h" 57#else 58#include "cfe.h" 59#endif 60 61#include "usbchap9.h" 62#include "usbd.h" 63 64/* ********************************************************************* 65 * USB Mass-Storage class Constants 66 ********************************************************************* */ 67 68#define USBMASS_CBI_PROTOCOL 0 69#define USBMASS_CBI_NOCOMPLETE_PROTOCOL 1 70#define USBMASS_BULKONLY_PROTOCOL 0x50 71 72#define USBMASS_SUBCLASS_RBC 0x01 73#define USBMASS_SUBCLASS_SFF8020 0x02 74#define USBMASS_SUBCLASS_QIC157 0x03 75#define USBMASS_SUBCLASS_UFI 0x04 76#define USBMASS_SUBCLASS_SFF8070 0x05 77#define USBMASS_SUBCLASS_SCSI 0x06 78 79#define USBMASS_CSW_PASS 0x00 80#define USBMASS_CSW_FAILED 0x01 81#define USBMASS_CSW_PHASEERR 0x02 82 83#define USBMASS_CBW_SIGNATURE 0x43425355 84#define USBMASS_CSW_SIGNATURE 0x53425355 85 86/* ********************************************************************* 87 * USB Mass-Storage class Structures 88 ********************************************************************* */ 89 90typedef struct usbmass_cbw_s { 91 uint8_t dCBWSignature0,dCBWSignature1,dCBWSignature2,dCBWSignature3; 92 uint8_t dCBWTag0,dCBWTag1,dCBWTag2,dCBWTag3; 93 uint8_t dCBWDataTransferLength0,dCBWDataTransferLength1, 94 dCBWDataTransferLength2,dCBWDataTransferLength3; 95 uint8_t bmCBWFlags; 96 uint8_t bCBWLUN; 97 uint8_t bCBWCBLength; 98 uint8_t CBWCB[16]; 99} usbmass_cbw_t; 100 101typedef struct usbmass_csw_s { 102 uint8_t dCSWSignature0,dCSWSignature1,dCSWSignature2,dCSWSignature3; 103 uint8_t dCSWTag0,dCSWTag1,dCSWTag2,dCSWTag3; 104 uint8_t dCSWDataResidue0,dCSWDataResidue1,dCSWDataResidue2,dCSWDataResidue3; 105 uint8_t bCSWStatus; 106} usbmass_csw_t; 107 108#define GETCBWFIELD(s,f) ((uint32_t)((s)->f##0) | ((uint32_t)((s)->f##1) << 8) | \ 109 ((uint32_t)((s)->f##2) << 16) | ((uint32_t)((s)->f##3) << 24)) 110#define PUTCBWFIELD(s,f,v) (s)->f##0 = (v & 0xFF); \ 111 (s)->f##1 = ((v)>>8 & 0xFF); \ 112 (s)->f##2 = ((v)>>16 & 0xFF); \ 113 (s)->f##3 = ((v)>>24 & 0xFF); 114 115 116int usbmass_request_sense(usbdev_t *dev); 117 118/* ********************************************************************* 119 * Linkage to CFE 120 ********************************************************************* */ 121 122#ifdef _CFE_ 123 124/* 125 * Softc for the CFE side of the disk driver. 126 */ 127#define MAX_SECTORSIZE 2048 128typedef struct usbdisk_s { 129 uint32_t usbdisk_sectorsize; 130 uint32_t usbdisk_ttlsect; 131 uint32_t usbdisk_devtype; 132 int usbdisk_unit; 133} usbdisk_t; 134 135/* 136 * This table points at the currently configured USB disk 137 * devices. This lets us leave the CFE half of the driver lying 138 * around while the USB devices come and go. We use the unit number 139 * from the original CFE attach to index this table, and devices 140 * that are not present are "not ready." 141 */ 142 143#define USBDISK_MAXUNITS 4 144static usbdev_t *usbdisk_units[USBDISK_MAXUNITS]; 145 146/* 147 * CFE device driver routine forwards 148 */ 149 150static void usbdisk_probe(cfe_driver_t *drv, 151 unsigned long probe_a, unsigned long probe_b, 152 void *probe_ptr); 153 154static int usbdisk_open(cfe_devctx_t *ctx); 155static int usbdisk_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer); 156static int usbdisk_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat); 157static int usbdisk_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer); 158static int usbdisk_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer); 159static int usbdisk_close(cfe_devctx_t *ctx); 160 161/* 162 * CFE device driver descriptor 163 */ 164 165const static cfe_devdisp_t usbdisk_dispatch = { 166 usbdisk_open, 167 usbdisk_read, 168 usbdisk_inpstat, 169 usbdisk_write, 170 usbdisk_ioctl, 171 usbdisk_close, 172 NULL, 173 NULL 174}; 175 176const cfe_driver_t usb_disk = { 177 "USB Disk", 178 "usbdisk", 179 CFE_DEV_DISK, 180 &usbdisk_dispatch, 181 usbdisk_probe 182}; 183 184 185#endif 186 187 188 189/* ********************************************************************* 190 * Forward Definitions 191 ********************************************************************* */ 192 193static int usbmass_attach(usbdev_t *dev,usb_driver_t *drv); 194static int usbmass_detach(usbdev_t *dev); 195 196/* ********************************************************************* 197 * Structures 198 ********************************************************************* */ 199 200typedef struct usbmass_softc_s { 201 int umass_inpipe; 202 int umass_outpipe; 203 int umass_devtype; 204 uint32_t umass_curtag; 205 int umass_unit; 206} usbmass_softc_t; 207 208usb_driver_t usbmass_driver = { 209 "Mass-Storage Device", 210 usbmass_attach, 211 usbmass_detach 212}; 213 214usbdev_t *usbmass_dev = NULL; /* XX hack for testing only */ 215 216/* ********************************************************************* 217 * usbmass_mass_storage_reset(dev,ifc) 218 * 219 * Do a bulk-only mass-storage reset. 220 * 221 * Input parameters: 222 * dev - device to reset 223 * ifc - interface number to reset (bInterfaceNum) 224 * 225 * Return value: 226 * status 227 ********************************************************************* */ 228 229#define usbmass_mass_storage_reset(dev,ifc) \ 230 usb_simple_request(dev,0x21,0xFF,ifc,0) 231 232#if 0 233/* ********************************************************************* 234 * usbmass_get_max_lun(dev,lunp) 235 * 236 * Get maximum LUN from device 237 * 238 * Input parameters: 239 * dev - device to reset 240 * lunp - pointer to int to receive max lun 241 * 242 * Return value: 243 * status 244 ********************************************************************* */ 245 246static int usbmass_get_max_lun(usbdev_t *dev,int *lunp) 247{ 248 uint8_t buf = 0; 249 int res; 250 251 res = usb_std_request(dev,0xA1,0xFE,0,0,&buf,1); 252 253 if (res < 0) return res; 254 255 if (lunp) *lunp = (int) buf; 256 return 0; 257} 258 259#endif 260 261 262/* ********************************************************************* 263 * usbmass_stall_recovery(dev) 264 * 265 * Do whatever it takes to unstick a stalled mass-storage device. 266 * 267 * Input parameters: 268 * dev - usb device 269 * 270 * Return value: 271 * nothing 272 ********************************************************************* */ 273 274static void usbmass_stall_recovery(usbdev_t *dev) 275{ 276 usbmass_softc_t *softc; 277 278 softc = (usbmass_softc_t *) dev->ud_private; 279 280 usb_clear_stall(dev,softc->umass_inpipe); 281 282 usbmass_request_sense(dev); 283} 284 285 286/* ********************************************************************* 287 * usbmass_read_capacity(dev,sectornum,buffer) 288 * 289 * Reads a sector from the device. 290 * 291 * Input parameters: 292 * dev - usb device 293 * sectornum - sector number to read 294 * buffer - place to put sector we read 295 * 296 * Return value: 297 * status 298 ********************************************************************* */ 299 300int usbmass_request_sense(usbdev_t *dev) 301{ 302 uint8_t *cbwcsw; 303 uint8_t *sector; 304 usbmass_cbw_t *cbw; 305 usbmass_csw_t *csw; 306 usbmass_softc_t *softc; 307 int res; 308 309 softc = (usbmass_softc_t *) dev->ud_private; 310 311 cbwcsw = KMALLOC(64,32); 312 sector = KMALLOC(64,32); 313 314 memset(sector,0,64); 315 316 cbw = (usbmass_cbw_t *) cbwcsw; 317 csw = (usbmass_csw_t *) cbwcsw; 318 319 /* 320 * Fill in the fields of the CBW 321 */ 322 323 PUTCBWFIELD(cbw,dCBWSignature,USBMASS_CBW_SIGNATURE); 324 PUTCBWFIELD(cbw,dCBWTag,softc->umass_curtag); 325 PUTCBWFIELD(cbw,dCBWDataTransferLength,18); 326 cbw->bmCBWFlags = 0x80; /* IN */ 327 cbw->bCBWLUN = 0; 328 cbw->bCBWCBLength = 12; 329 cbw->CBWCB[0] = 0x3; /* REQUEST SENSE */ 330 cbw->CBWCB[1] = 0; 331 cbw->CBWCB[2] = 0; 332 cbw->CBWCB[3] = 0; 333 cbw->CBWCB[4] = 18; /* allocation length */ 334 cbw->CBWCB[5] = 0; 335 cbw->CBWCB[6] = 0; 336 cbw->CBWCB[7] = 0; 337 cbw->CBWCB[8] = 0; 338 cbw->CBWCB[9] = 0; 339 340 softc->umass_curtag++; 341 342 /* 343 * Send the CBW 344 */ 345 346 res = usb_make_sync_request(dev,softc->umass_outpipe,(uint8_t *) cbw, 347 sizeof(usbmass_cbw_t),UR_FLAG_OUT); 348 349 /* 350 * Get the data 351 */ 352 353 memset(sector,0,18); 354 res = usb_make_sync_request(dev,softc->umass_inpipe,sector, 355 18,UR_FLAG_IN | UR_FLAG_SHORTOK); 356 357 /* 358 * Get the Status 359 */ 360 361 memset(csw,0,sizeof(usbmass_csw_t)); 362 res = usb_make_sync_request(dev,softc->umass_inpipe,(uint8_t *) csw, 363 sizeof(usbmass_csw_t),UR_FLAG_IN); 364 365 KFREE(cbwcsw); 366 367 KFREE(sector); 368 369 return 0; 370 371} 372 373/* ********************************************************************* 374 * usbmass_read_sector(dev,sectornum,seccnt,buffer) 375 * 376 * Reads a sector from the device. 377 * 378 * Input parameters: 379 * dev - usb device 380 * sectornum - sector number to read 381 * seccnt - count of sectors to read 382 * buffer - place to put sector we read 383 * 384 * Return value: 385 * status 386 ********************************************************************* */ 387 388int usbmass_read_sector(usbdev_t *dev,uint32_t sectornum,uint32_t seccnt, 389 hsaddr_t buffer); 390int usbmass_read_sector(usbdev_t *dev,uint32_t sectornum,uint32_t seccnt, 391 hsaddr_t buffer) 392{ 393 uint8_t *cbwcsw; 394 uint8_t *sector; 395 usbmass_cbw_t *cbw; 396 usbmass_csw_t *csw; 397 usbmass_softc_t *softc; 398 int res; 399 400 softc = (usbmass_softc_t *) dev->ud_private; 401 402 cbwcsw = KMALLOC(64,32); 403 sector = (uint8_t *) HSADDR2PTR(buffer); /* XXX not 64-bit compatible */ 404 405 cbw = (usbmass_cbw_t *) cbwcsw; 406 csw = (usbmass_csw_t *) cbwcsw; 407 408 /* 409 * Fill in the fields of the CBW 410 */ 411 412 PUTCBWFIELD(cbw,dCBWSignature,USBMASS_CBW_SIGNATURE); 413 PUTCBWFIELD(cbw,dCBWTag,softc->umass_curtag); 414 PUTCBWFIELD(cbw,dCBWDataTransferLength,(512*seccnt)); 415 cbw->bmCBWFlags = 0x80; /* IN */ 416 cbw->bCBWLUN = 0; 417 cbw->bCBWCBLength = 10; 418 cbw->CBWCB[0] = 0x28; /* READ */ 419 cbw->CBWCB[1] = 0; 420 cbw->CBWCB[2] = (sectornum >> 24) & 0xFF; /* LUN 0 & MSB's of sector */ 421 cbw->CBWCB[3] = (sectornum >> 16) & 0xFF; 422 cbw->CBWCB[4] = (sectornum >> 8) & 0xFF; 423 cbw->CBWCB[5] = (sectornum >> 0) & 0xFF; 424 cbw->CBWCB[6] = 0; 425 cbw->CBWCB[7] = 0; 426 cbw->CBWCB[8] = seccnt; 427 cbw->CBWCB[9] = 0; 428 429 softc->umass_curtag++; 430 431 /* 432 * Send the CBW 433 */ 434 435 res = usb_make_sync_request(dev,softc->umass_outpipe,(uint8_t *) cbw, 436 sizeof(usbmass_cbw_t),UR_FLAG_OUT); 437 if (res == 4) { 438 usbmass_stall_recovery(dev); 439 KFREE(cbwcsw); 440 return -1; 441 } 442 443 444 /* 445 * Get the data 446 */ 447 448 res = usb_make_sync_request(dev,softc->umass_inpipe,sector, 449 512*seccnt,UR_FLAG_IN | UR_FLAG_SHORTOK); 450 if (res == 4) { 451 usbmass_stall_recovery(dev); 452 KFREE(cbwcsw); 453 return -1; 454 } 455 456 457 /* 458 * Get the Status 459 */ 460 461 memset(csw,0,sizeof(usbmass_csw_t)); 462 res = usb_make_sync_request(dev,softc->umass_inpipe,(uint8_t *) csw, 463 sizeof(usbmass_csw_t),UR_FLAG_IN); 464 if (res == 4) { 465 usbmass_stall_recovery(dev); 466 KFREE(cbwcsw); 467 return -1; 468 } 469 470 471#if 0 472 printf("CSW: Signature=%08X Tag=%08X Residue=%08X Status=%02X\n", 473 GETCBWFIELD(csw,dCSWSignature), 474 GETCBWFIELD(csw,dCSWTag), 475 GETCBWFIELD(csw,dCSWDataResidue), 476 csw->bCSWStatus); 477#endif 478 479 res = (csw->bCSWStatus == USBMASS_CSW_PASS) ? 0 : -1; 480 481 KFREE(cbwcsw); 482 483 return res; 484 485} 486 487/* ********************************************************************* 488 * usbmass_write_sector(dev,sectornum,seccnt,buffer) 489 * 490 * Writes a sector to the device 491 * 492 * Input parameters: 493 * dev - usb device 494 * sectornum - sector number to write 495 * seccnt - count of sectors to write 496 * buffer - place to get sector to write 497 * 498 * Return value: 499 * status 500 ********************************************************************* */ 501 502static int usbmass_write_sector(usbdev_t *dev,uint32_t sectornum,uint32_t seccnt, 503 hsaddr_t buffer) 504{ 505 uint8_t *cbwcsw; 506 uint8_t *sector; 507 usbmass_cbw_t *cbw; 508 usbmass_csw_t *csw; 509 usbmass_softc_t *softc; 510 int res; 511 512 softc = (usbmass_softc_t *) dev->ud_private; 513 514 cbwcsw = KMALLOC(64,32); 515 sector = (uint8_t *) HSADDR2PTR(buffer); /* XXX not 64-bit compatible */ 516 517 cbw = (usbmass_cbw_t *) cbwcsw; 518 csw = (usbmass_csw_t *) cbwcsw; 519 520 /* 521 * Fill in the fields of the CBW 522 */ 523 524 PUTCBWFIELD(cbw,dCBWSignature,USBMASS_CBW_SIGNATURE); 525 PUTCBWFIELD(cbw,dCBWTag,softc->umass_curtag); 526 PUTCBWFIELD(cbw,dCBWDataTransferLength,(512*seccnt)); 527 cbw->bmCBWFlags = 0x00; /* OUT */ 528 cbw->bCBWLUN = 0; 529 cbw->bCBWCBLength = 10; 530 cbw->CBWCB[0] = 0x2A; /* WRITE */ 531 cbw->CBWCB[1] = 0; 532 cbw->CBWCB[2] = (sectornum >> 24) & 0xFF; /* LUN 0 & MSB's of sector */ 533 cbw->CBWCB[3] = (sectornum >> 16) & 0xFF; 534 cbw->CBWCB[4] = (sectornum >> 8) & 0xFF; 535 cbw->CBWCB[5] = (sectornum >> 0) & 0xFF; 536 cbw->CBWCB[6] = 0; 537 cbw->CBWCB[7] = 0; 538 cbw->CBWCB[8] = seccnt; 539 cbw->CBWCB[9] = 0; 540 541 softc->umass_curtag++; 542 543 /* 544 * Send the CBW 545 */ 546 547 res = usb_make_sync_request(dev,softc->umass_outpipe,(uint8_t *) cbw, 548 sizeof(usbmass_cbw_t),UR_FLAG_OUT); 549 550 /* 551 * Send the data 552 */ 553 554 res = usb_make_sync_request(dev,softc->umass_outpipe,sector, 555 512*seccnt,UR_FLAG_OUT); 556 557 /* 558 * Get the Status 559 */ 560 561 memset(csw,0,sizeof(usbmass_csw_t)); 562 res = usb_make_sync_request(dev,softc->umass_inpipe,(uint8_t *) csw, 563 sizeof(usbmass_csw_t),UR_FLAG_IN); 564 565#if 0 566 printf("CSW: Signature=%08X Tag=%08X Residue=%08X Status=%02X\n", 567 GETCBWFIELD(csw,dCSWSignature), 568 GETCBWFIELD(csw,dCSWTag), 569 GETCBWFIELD(csw,dCSWDataResidue), 570 csw->bCSWStatus); 571#endif 572 573 res = (csw->bCSWStatus == USBMASS_CSW_PASS) ? 0 : -1; 574 575 KFREE(cbwcsw); 576 577 return res; 578} 579 580/* ********************************************************************* 581 * usbmass_read_capacity(dev,sectornum,buffer) 582 * 583 * Reads a sector from the device. 584 * 585 * Input parameters: 586 * dev - usb device 587 * sectornum - sector number to read 588 * buffer - place to put sector we read 589 * 590 * Return value: 591 * status 592 ********************************************************************* */ 593 594int usbmass_read_capacity(usbdev_t *dev,uint32_t *size); 595int usbmass_read_capacity(usbdev_t *dev,uint32_t *size) 596{ 597 uint8_t *cbwcsw; 598 uint8_t *sector; 599 usbmass_cbw_t *cbw; 600 usbmass_csw_t *csw; 601 usbmass_softc_t *softc; 602 int res; 603 604 softc = (usbmass_softc_t *) dev->ud_private; 605 606 cbwcsw = KMALLOC(64,32); 607 sector = KMALLOC(64,32); 608 609 memset(sector,0,64); 610 611 cbw = (usbmass_cbw_t *) cbwcsw; 612 csw = (usbmass_csw_t *) cbwcsw; 613 614 *size = 0; 615 616 /* 617 * Fill in the fields of the CBW 618 */ 619 620 PUTCBWFIELD(cbw,dCBWSignature,USBMASS_CBW_SIGNATURE); 621 PUTCBWFIELD(cbw,dCBWTag,softc->umass_curtag); 622 PUTCBWFIELD(cbw,dCBWDataTransferLength,8); 623 cbw->bmCBWFlags = 0x80; /* IN */ 624 cbw->bCBWLUN = 0; 625 cbw->bCBWCBLength = 10; 626 cbw->CBWCB[0] = 0x25; /* READ CAPACITY */ 627 cbw->CBWCB[1] = 0; 628 cbw->CBWCB[2] = 0; 629 cbw->CBWCB[3] = 0; 630 cbw->CBWCB[4] = 0; 631 cbw->CBWCB[5] = 0; 632 cbw->CBWCB[6] = 0; 633 cbw->CBWCB[7] = 0; 634 cbw->CBWCB[8] = 0; 635 cbw->CBWCB[9] = 0; 636 637 softc->umass_curtag++; 638 639 /* 640 * Send the CBW 641 */ 642 643 res = usb_make_sync_request(dev,softc->umass_outpipe,(uint8_t *) cbw, 644 sizeof(usbmass_cbw_t),UR_FLAG_OUT); 645 if (res == 4) { 646 usbmass_stall_recovery(dev); 647 KFREE(cbwcsw); 648 KFREE(sector); 649 return -1; 650 } 651 652 /* 653 * Get the data 654 */ 655 656 res = usb_make_sync_request(dev,softc->umass_inpipe,sector, 657 8,UR_FLAG_IN | UR_FLAG_SHORTOK); 658 if (res == 4) { 659 usbmass_stall_recovery(dev); 660 KFREE(cbwcsw); 661 KFREE(sector); 662 return -1; 663 } 664 665 /* 666 * Get the Status 667 */ 668 669 memset(csw,0,sizeof(usbmass_csw_t)); 670 res = usb_make_sync_request(dev,softc->umass_inpipe,(uint8_t *) csw, 671 sizeof(usbmass_csw_t),UR_FLAG_IN); 672 673 KFREE(cbwcsw); 674 675 *size = (((uint32_t) sector[0]) << 24) | 676 (((uint32_t) sector[1]) << 16) | 677 (((uint32_t) sector[2]) << 8) | 678 (((uint32_t) sector[3]) << 0); 679 680 KFREE(sector); 681 682 return 0; 683 684} 685 686 687 688/* ********************************************************************* 689 * usbmass_attach(dev,drv) 690 * 691 * This routine is called when the bus scan stuff finds a mass-storage 692 * device. We finish up the initialization by configuring the 693 * device and allocating our softc here. 694 * 695 * Input parameters: 696 * dev - usb device, in the "addressed" state. 697 * drv - the driver table entry that matched 698 * 699 * Return value: 700 * 0 701 ********************************************************************* */ 702 703static int usbmass_attach(usbdev_t *dev,usb_driver_t *drv) 704{ 705 usb_config_descr_t *cfgdscr = dev->ud_cfgdescr; 706 usb_endpoint_descr_t *epdscr; 707 usb_endpoint_descr_t *indscr = NULL; 708 usb_endpoint_descr_t *outdscr = NULL; 709 usb_interface_descr_t *ifdscr; 710 usbmass_softc_t *softc; 711 int idx; 712 713 dev->ud_drv = drv; 714 715 softc = KMALLOC(sizeof(usbmass_softc_t),0); 716 memset(softc,0,sizeof(usbmass_softc_t)); 717 dev->ud_private = softc; 718 719 ifdscr = usb_find_cfg_descr(dev,USB_INTERFACE_DESCRIPTOR_TYPE,0); 720 if (ifdscr == NULL) { 721 return -1; 722 } 723 724 if ((ifdscr->bInterfaceSubClass != USBMASS_SUBCLASS_SCSI) || 725 (ifdscr->bInterfaceProtocol != USBMASS_BULKONLY_PROTOCOL)) { 726 console_log("USBMASS: Do not understand devices with SubClass 0x%02X, Protocol 0x%02X", 727 ifdscr->bInterfaceSubClass, 728 ifdscr->bInterfaceProtocol); 729 return -1; 730 } 731 732 for (idx = 0; idx < 2; idx++) { 733 epdscr = usb_find_cfg_descr(dev,USB_ENDPOINT_DESCRIPTOR_TYPE,idx); 734 735 if (USB_ENDPOINT_DIR_OUT(epdscr->bEndpointAddress)) { 736 outdscr = epdscr; 737 } 738 else { 739 indscr = epdscr; 740 } 741 } 742 743 744 if (!indscr || !outdscr) { 745 /* 746 * Could not get descriptors, something is very wrong. 747 * Leave device addressed but not configured. 748 */ 749 return -1; 750 } 751 752 /* 753 * Choose the standard configuration. 754 */ 755 756 usb_set_configuration(dev,cfgdscr->bConfigurationValue); 757 758 /* 759 * Open the pipes. 760 */ 761 762 softc->umass_inpipe = usb_open_pipe(dev,indscr); 763 softc->umass_outpipe = usb_open_pipe(dev,outdscr); 764 softc->umass_curtag = 0x12345678; 765 766 /* 767 * Save pointer in global unit table so we can 768 * match CFE devices up with USB ones 769 */ 770 771 772#ifdef _CFE_ 773 softc->umass_unit = -1; 774 for (idx = 0; idx < USBDISK_MAXUNITS; idx++) { 775 if (usbdisk_units[idx] == NULL) { 776 softc->umass_unit = idx; 777 usbdisk_units[idx] = dev; 778 break; 779 } 780 } 781 782 console_log("USBMASS: Unit %d connected",softc->umass_unit); 783#endif 784 785 usbmass_dev = dev; 786 787 return 0; 788} 789 790/* ********************************************************************* 791 * usbmass_detach(dev) 792 * 793 * This routine is called when the bus scanner notices that 794 * this device has been removed from the system. We should 795 * do any cleanup that is required. The pending requests 796 * will be cancelled automagically. 797 * 798 * Input parameters: 799 * dev - usb device 800 * 801 * Return value: 802 * 0 803 ********************************************************************* */ 804 805static int usbmass_detach(usbdev_t *dev) 806{ 807 usbmass_softc_t *softc; 808 softc = (usbmass_softc_t *) dev->ud_private; 809 810#ifdef _CFE_ 811 console_log("USBMASS: USB unit %d disconnected",softc->umass_unit); 812 if (softc->umass_unit >= 0) usbdisk_units[softc->umass_unit] = NULL; 813#endif 814 815 KFREE(softc); 816 return 0; 817} 818 819 820 821#ifdef _CFE_ 822 823 824/* ********************************************************************* 825 * usbdisk_sectorshift(size) 826 * 827 * Given a sector size, return log2(size). We cheat; this is 828 * only needed for 2048 and 512-byte sectors. 829 * Explicitly using shifts and masks in sector number calculations 830 * helps on 32-bit-only platforms, since we probably won't need 831 * a helper library. 832 * 833 * Input parameters: 834 * size - sector size 835 * 836 * Return value: 837 * # of bits to shift 838 ********************************************************************* */ 839 840#define usbdisk_sectorshift(size) (((size)==2048)?11:9) 841 842 843/* ********************************************************************* 844 * usbdisk_probe(drv,probe_a,probe_b,probe_ptr) 845 * 846 * Our probe routine. Attach an empty USB disk device to the firmware. 847 * 848 * Input parameters: 849 * drv - driver structure 850 * probe_a - not used 851 * probe_b - not used 852 * probe_ptr - not used 853 * 854 * Return value: 855 * nothing 856 ********************************************************************* */ 857 858static void usbdisk_probe(cfe_driver_t *drv, 859 unsigned long probe_a, unsigned long probe_b, 860 void *probe_ptr) 861{ 862 usbdisk_t *softc; 863 char descr[128]; 864 865 softc = (usbdisk_t *) KMALLOC(sizeof(usbdisk_t),0); 866 867 memset(softc,0,sizeof(usbdisk_t)); 868 869 softc->usbdisk_sectorsize = 512; 870 softc->usbdisk_devtype = BLOCK_DEVTYPE_DISK; 871 softc->usbdisk_ttlsect = 0; /* not calculated yet */ 872 softc->usbdisk_unit = (int)probe_a; 873 874 xsprintf(descr,"USB Disk unit %d",(int)probe_a); 875 876 cfe_attach(drv,softc,NULL,descr); 877} 878 879 880/* ********************************************************************* 881 * usbdisk_open(ctx) 882 * 883 * Process the CFE OPEN call for this device. For IDE disks, 884 * the device is reset and identified, and the geometry is 885 * determined. 886 * 887 * Input parameters: 888 * ctx - device context 889 * 890 * Return value: 891 * 0 if ok, else error code 892 ********************************************************************* */ 893 894 895static int usbdisk_open(cfe_devctx_t *ctx) 896{ 897 usbdisk_t *softc = ctx->dev_softc; 898 usbdev_t *dev = usbdisk_units[softc->usbdisk_unit]; 899 uint32_t size; 900 int res; 901 902 if (!dev) return CFE_ERR_NOTREADY; 903 904 usbmass_request_sense(dev); 905 906 res = usbmass_read_capacity(dev,&size); 907 if (res < 0) return res; 908 909 softc->usbdisk_ttlsect = size; 910 911 return 0; 912} 913 914/* ********************************************************************* 915 * usbdisk_read(ctx,buffer) 916 * 917 * Process a CFE READ command for the IDE device. This is 918 * more complex than it looks, since CFE offsets are byte offsets 919 * and we may need to read partial sectors. 920 * 921 * Input parameters: 922 * ctx - device context 923 * buffer - buffer descriptor 924 * 925 * Return value: 926 * number of bytes read, or <0 if an error occured 927 ********************************************************************* */ 928 929static int usbdisk_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer) 930{ 931 usbdisk_t *softc = ctx->dev_softc; 932 usbdev_t *dev = usbdisk_units[softc->usbdisk_unit]; 933 hsaddr_t bptr; 934 int blen; 935 int numsec; 936 int res = 0; 937 int amtcopy; 938 uint64_t lba; 939 uint64_t offset; 940 unsigned char sector[MAX_SECTORSIZE]; 941 int sectorshift; 942 943 if (!dev) return CFE_ERR_NOTREADY; 944 945 sectorshift = usbdisk_sectorshift(softc->usbdisk_sectorsize); 946 947 bptr = buffer->buf_ptr; 948 blen = buffer->buf_length; 949 offset = buffer->buf_offset; 950 numsec = (blen + softc->usbdisk_sectorsize - 1) >> sectorshift; 951 952 if (offset & (softc->usbdisk_sectorsize-1)) { 953 lba = (offset >> sectorshift); 954 res = usbmass_read_sector(dev,lba,1,PTR2HSADDR(sector)); 955 if (res < 0) goto out; 956 amtcopy = softc->usbdisk_sectorsize - (offset & (softc->usbdisk_sectorsize-1)); 957 if (amtcopy > blen) amtcopy = blen; 958 hs_memcpy_to_hs(bptr,§or[offset & (softc->usbdisk_sectorsize-1)],amtcopy); 959 bptr += amtcopy; 960 offset += amtcopy; 961 blen -= amtcopy; 962 } 963 964 if (blen >= softc->usbdisk_sectorsize) { 965 int seccnt; 966 967 lba = (offset >> sectorshift); 968 seccnt = (blen >> sectorshift); 969 970 res = usbmass_read_sector(dev,lba,seccnt,bptr); 971 if (res < 0) goto out; 972 973 amtcopy = seccnt << sectorshift; 974 bptr += amtcopy; 975 offset += amtcopy; 976 blen -= amtcopy; 977 } 978 979 if (blen) { 980 lba = (offset >> sectorshift); 981 res = usbmass_read_sector(dev,lba,1,PTR2HSADDR(sector)); 982 if (res < 0) goto out; 983 amtcopy = blen; 984 hs_memcpy_to_hs(bptr,sector,amtcopy); 985 bptr += amtcopy; 986 offset += amtcopy; 987 blen -= amtcopy; 988 } 989 990out: 991 buffer->buf_retlen = bptr - buffer->buf_ptr; 992 993 return res; 994} 995 996/* ********************************************************************* 997 * usbdisk_inpstat(ctx,inpstat) 998 * 999 * Test input status for the IDE disk. Disks are always ready 1000 * to read. 1001 * 1002 * Input parameters: 1003 * ctx - device context 1004 * inpstat - input status structure 1005 * 1006 * Return value: 1007 * 0 1008 ********************************************************************* */ 1009 1010static int usbdisk_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat) 1011{ 1012 /* usbdisk_t *softc = ctx->dev_softc; */ 1013 1014 inpstat->inp_status = 1; 1015 return 0; 1016} 1017 1018/* ********************************************************************* 1019 * usbdisk_write(ctx,buffer) 1020 * 1021 * Process a CFE WRITE command for the IDE device. If the write 1022 * involves partial sectors, the affected sectors are read first 1023 * and the changes are merged in. 1024 * 1025 * Input parameters: 1026 * ctx - device context 1027 * buffer - buffer descriptor 1028 * 1029 * Return value: 1030 * number of bytes write, or <0 if an error occured 1031 ********************************************************************* */ 1032 1033static int usbdisk_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer) 1034{ 1035 usbdisk_t *softc = ctx->dev_softc; 1036 usbdev_t *dev = usbdisk_units[softc->usbdisk_unit]; 1037 hsaddr_t bptr; 1038 int blen; 1039 int numsec; 1040 int res = 0; 1041 int amtcopy; 1042 uint64_t offset; 1043 uint64_t lba; 1044 unsigned char sector[MAX_SECTORSIZE]; 1045 int sectorshift; 1046 1047 if (!dev) return CFE_ERR_NOTREADY; 1048 1049 sectorshift = usbdisk_sectorshift(softc->usbdisk_sectorsize); 1050 1051 bptr = buffer->buf_ptr; 1052 blen = buffer->buf_length; 1053 offset = buffer->buf_offset; 1054 numsec = (blen + softc->usbdisk_sectorsize - 1) >> sectorshift; 1055 1056 if (offset & (softc->usbdisk_sectorsize-1)) { 1057 lba = (offset >> sectorshift); 1058 res = usbmass_read_sector(dev,lba,1,PTR2HSADDR(sector)); 1059 if (res < 0) goto out; 1060 amtcopy = softc->usbdisk_sectorsize - (offset & (softc->usbdisk_sectorsize-1)); 1061 if (amtcopy > blen) amtcopy = blen; 1062 hs_memcpy_from_hs(§or[offset & (softc->usbdisk_sectorsize-1)],bptr,amtcopy); 1063 res = usbmass_write_sector(dev,lba,1,PTR2HSADDR(sector)); 1064 if (res < 0) goto out; 1065 bptr += amtcopy; 1066 offset += amtcopy; 1067 blen -= amtcopy; 1068 } 1069 1070 while (blen >= softc->usbdisk_sectorsize) { 1071 amtcopy = softc->usbdisk_sectorsize; 1072 lba = (offset >> sectorshift); 1073 res = usbmass_write_sector(dev,lba,1,bptr); 1074 if (res < 0) goto out; 1075 bptr += amtcopy; 1076 offset += amtcopy; 1077 blen -= amtcopy; 1078 } 1079 1080 if (blen) { 1081 lba = (offset >> sectorshift); 1082 res = usbmass_read_sector(dev,lba,1,PTR2HSADDR(sector)); 1083 if (res < 0) goto out; 1084 amtcopy = blen; 1085 hs_memcpy_from_hs(sector,bptr,amtcopy); 1086 res = usbmass_write_sector(dev,lba,1,PTR2HSADDR(sector)); 1087 if (res < 0) goto out; 1088 bptr += amtcopy; 1089 offset += amtcopy; 1090 blen -= amtcopy; 1091 } 1092 1093out: 1094 buffer->buf_retlen = bptr - buffer->buf_ptr; 1095 1096 return res; 1097} 1098 1099 1100/* ********************************************************************* 1101 * usbdisk_ioctl(ctx,buffer) 1102 * 1103 * Process device I/O control requests for the IDE device. 1104 * 1105 * Input parameters: 1106 * ctx - device context 1107 * buffer - buffer descriptor 1108 * 1109 * Return value: 1110 * 0 if ok 1111 * else error code 1112 ********************************************************************* */ 1113 1114static int usbdisk_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer) 1115{ 1116 usbdisk_t *softc = ctx->dev_softc; 1117 unsigned int info; 1118 unsigned long long linfo; 1119 blockdev_info_t devinfo; 1120 1121 switch ((int)buffer->buf_ioctlcmd) { 1122 case IOCTL_BLOCK_GETBLOCKSIZE: 1123 info = softc->usbdisk_sectorsize; 1124 hs_memcpy_to_hs(buffer->buf_ptr,&info,sizeof(info)); 1125 break; 1126 case IOCTL_BLOCK_GETTOTALBLOCKS: 1127 linfo = softc->usbdisk_ttlsect; 1128 hs_memcpy_to_hs(buffer->buf_ptr,&linfo,sizeof(linfo)); 1129 break; 1130 case IOCTL_BLOCK_GETDEVTYPE: 1131 devinfo.blkdev_totalblocks = softc->usbdisk_ttlsect; 1132 devinfo.blkdev_blocksize = softc->usbdisk_sectorsize; 1133 devinfo.blkdev_devtype = softc->usbdisk_devtype; 1134 hs_memcpy_to_hs(buffer->buf_ptr,&devinfo,sizeof(devinfo)); 1135 break; 1136 default: 1137 return -1; 1138 } 1139 1140 return 0; 1141} 1142 1143/* ********************************************************************* 1144 * usbdisk_close(ctx) 1145 * 1146 * Close the I/O device. 1147 * 1148 * Input parameters: 1149 * ctx - device context 1150 * 1151 * Return value: 1152 * 0 if ok, else error code 1153 ********************************************************************* */ 1154 1155static int usbdisk_close(cfe_devctx_t *ctx) 1156{ 1157 /* usbdisk_t *softc = ctx->dev_softc; */ 1158 1159 return 0; 1160} 1161 1162 1163#endif 1164