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,&sector[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(&sector[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