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