1/*  *********************************************************************
2    *  Broadcom Common Firmware Environment (CFE)
3    *
4    *  Generic IDE disk driver 			File: dev_ide_common.c
5    *
6    *  This is a simple driver for IDE hard disks.   The mechanics
7    *  of talking to the I/O ports are abstracted sufficiently to make
8    *  this driver usable for various bus interfaces.
9    *
10    *  Author:  Mitch Lichtenberg
11    *
12    *********************************************************************
13    *
14    *  Copyright 2000,2001,2002,2003
15    *  Broadcom Corporation. All rights reserved.
16    *
17    *  This software is furnished under license and may be used and
18    *  copied only in accordance with the following terms and
19    *  conditions.  Subject to these conditions, you may download,
20    *  copy, install, use, modify and distribute modified or unmodified
21    *  copies of this software in source and/or binary form.  No title
22    *  or ownership is transferred hereby.
23    *
24    *  1) Any source code used, modified or distributed must reproduce
25    *     and retain this copyright notice and list of conditions
26    *     as they appear in the source file.
27    *
28    *  2) No right is granted to use any trade name, trademark, or
29    *     logo of Broadcom Corporation.  The "Broadcom Corporation"
30    *     name may not be used to endorse or promote products derived
31    *     from this software without the prior written permission of
32    *     Broadcom Corporation.
33    *
34    *  3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
35    *     IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
36    *     WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
37    *     PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
38    *     SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
39    *     PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
40    *     INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
41    *     (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
42    *     GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
43    *     BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
44    *     OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
45    *     TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
46    *     THE POSSIBILITY OF SUCH DAMAGE.
47    ********************************************************************* */
48
49
50#include "cfe.h"
51
52#include "dev_ide_common.h"
53
54#include "dev_ide.h"
55
56/*  *********************************************************************
57    *  Macros
58    ********************************************************************* */
59
60#define DISK_MASTER	0
61#define DISK_SLAVE	1
62
63#define IDE_WRITEREG8(ide,reg,val)     IDEDISP_WRITEREG8(ide->idecommon_dispatch,reg,val)
64#define IDE_WRITEREG16(ide,reg,val)    IDEDISP_WRITEREG16(ide->idecommon_dispatch,reg,val)
65#define IDE_WRITEBUF(ide,reg,buf,len)  IDEDISP_WRITEBUF(ide->idecommon_dispatch,reg,buf,len)
66#define IDE_READREG8(ide,reg)          IDEDISP_READREG8(ide->idecommon_dispatch,reg)
67#define IDE_READREG16(ide,reg)         IDEDISP_READREG16(ide->idecommon_dispatch,reg)
68#define IDE_READBUF(ide,reg,buf,len)   IDEDISP_READBUF(ide->idecommon_dispatch,reg,buf,len)
69
70#define GETWORD_LE(buf,wordidx) (((unsigned int) (buf)[wordidx]) + \
71             (((unsigned int) (buf)[wordidx+1]) << 8))
72
73#define _IDE_DEBUG_
74
75
76static void idecommon_testdrq(idecommon_t *ide);
77static int idecommon_spinup(idecommon_t *ide );
78
79/*  *********************************************************************
80    *  idecommon_sectorshift(size)
81    *
82    *  Given a sector size, return log2(size).  We cheat; this is
83    *  only needed for 2048 and 512-byte sectors.
84    *  Explicitly using shifts and masks in sector number calculations
85    *  helps on 32-bit-only platforms, since we probably won't need
86    *  a helper library.
87    *
88    *  Input parameters:
89    *  	   size - sector size
90    *
91    *  Return value:
92    *  	   # of bits to shift
93    ********************************************************************* */
94
95#define idecommon_sectorshift(size) (((size)==2048)?11:9)
96
97/*  *********************************************************************
98    *  idecommon_waitnotbusy(ide)
99    *
100    *  Wait for an IDE device to report "not busy"
101    *
102    *  Input parameters:
103    *  	   ide - IDE interface
104    *
105    *  Return value:
106    *  	   0 if ok, else -1 if timeout
107    ********************************************************************* */
108
109static int idecommon_waitnotbusy(idecommon_t *ide)
110{
111    int32_t timer;
112    uint8_t status;
113
114    TIMER_SET(timer,10*CFE_HZ);
115
116    while (!TIMER_EXPIRED(timer)) {
117	status = IDE_READREG8(ide,IDE_REG_STATUS);
118	if (!(status & IDE_STS_BSY) && (status & IDE_STS_DRQ)) {
119	    idecommon_testdrq(ide);
120	    continue;
121	    }
122	if ((status & (IDE_STS_BSY | IDE_STS_DRQ )) == 0) return 0;
123	POLL();
124	}
125
126#ifdef _IDE_DEBUG_
127    xprintf("Device did not become unbusy\n");
128#endif
129    return -1;
130}
131
132#if 0
133/*  *********************************************************************
134    *  idecommon_waitready(ide)
135    *
136    *  Wait for the specified device to become ready.
137    *
138    *  Input parameters:
139    *  	   ide - IDE interface
140    *
141    *  Return value:
142    *  	   0 if device became ready
143    *  	   -1 if device did not become ready
144    ********************************************************************* */
145
146static int idecommon_waitready(idecommon_t *ide)
147{
148    int32_t timer;
149    uint8_t status;
150
151    TIMER_SET(timer,10*CFE_HZ);
152
153    while (!TIMER_EXPIRED(timer)) {
154	status = IDE_READREG8(ide,IDE_REG_STATUS);
155	if (status & IDE_STS_RDY) return 0;
156	POLL();
157	}
158
159#ifdef _IDE_DEBUG_
160    xprintf("Disk did not become ready\n");
161#endif
162
163    return -1;
164}
165#endif
166
167/*  *********************************************************************
168    *  idecommon_waitbusy(idx)
169    *
170    *  Wait for an IDE disk to start processing a command, or at
171    *  least long enough to indicate that it is doing so.
172    *  The code below looks suspiciously like a timing loop.
173    *  unfortunately, that's what it is, determined empirically
174    *  for certain ATA flash cards.  Without this many reads to the
175    *  ALTSTAT register, the PCMCIA controller deasserts the
176    *  card detect pins briefly.  Anyone have any clues?
177    *
178    *  Input parameters:
179    *  	   ide - IDE interface
180    *
181    *  Return value:
182    *  	   void
183    ********************************************************************* */
184
185static void idecommon_waitbusy(idecommon_t *ide)
186{
187    int idx;
188
189    for (idx = 0; idx < 10; idx++) {
190	IDE_READREG8(ide,IDE_REG_ALTSTAT);
191	IDE_READREG8(ide,IDE_REG_ALTSTAT);
192	IDE_READREG8(ide,IDE_REG_ALTSTAT);
193	IDE_READREG8(ide,IDE_REG_ALTSTAT);
194	}
195}
196
197
198/*  *********************************************************************
199    *  idecommon_wait_drq(ide)
200    *
201    *  Wait for the BUSY bit to be clear and the DRQ bit to be set.
202    *  This is usually the indication that it's time to transfer data.
203    *
204    *  Input parameters:
205    *  	   ide - IDE interface
206    *  	   0 if DRQ is set
207    *  	   -1 if timeout occured
208    ********************************************************************* */
209
210static int idecommon_wait_drq(idecommon_t *ide)
211{
212    int32_t timer;
213    uint8_t status;
214
215    TIMER_SET(timer,10*CFE_HZ);
216
217    while (!TIMER_EXPIRED(timer)) {
218	POLL();
219	status = IDE_READREG8(ide,IDE_REG_STATUS);
220	if (!(status & IDE_STS_BSY) && (status & IDE_STS_ERR)) {
221	    xprintf("Drive status: %02X error %02X\n",status,
222		    IDE_READREG8(ide,IDE_REG_ERROR));
223	    return -1;
224	    }
225	if (!(status & IDE_STS_BSY) && (status & IDE_STS_DRQ)) return 0;
226	}
227
228#ifdef _IDE_DEBUG_
229    xprintf("Timeout waiting for disk\n");
230#endif
231
232    return -1;
233}
234
235/*  *********************************************************************
236    *  idecommon_testdrq(ide)
237    *
238    *  Debug routine.  Check the DRQ bit.  If it's set, it is not
239    *  supposed to be, so transfer data until it clears and report
240    *  how much we had to transfer.
241    *
242    *  Input parameters:
243    *  	   ide - IDE interface
244    *
245    *  Return value:
246    *  	   nothing
247    ********************************************************************* */
248
249#ifdef _IDE_DEBUG_
250static void idecommon_testdrq(idecommon_t *ide)
251{
252    uint8_t status;
253    uint16_t data;
254    int idx;
255
256    status = IDE_READREG8(ide,IDE_REG_STATUS);
257    if (status & IDE_STS_DRQ) {
258	xprintf("Error: DRQ should be zero\n");
259	idx = 0;
260	while (status & IDE_STS_DRQ) {
261	    data = IDE_READREG16(ide,IDE_REG_DATA);
262	    idx++;
263	    status = IDE_READREG8(ide,IDE_REG_STATUS);
264	    }
265	xprintf("Had to read data %d times to clear DRQ\n",idx);
266	}
267}
268#else
269#define idecommon_testdrq(ide)
270#endif
271
272
273/*  *********************************************************************
274    *  idecommon_dumpregs(ide)
275    *
276    *  Dump out the IDE registers. (debug routine)
277    *
278    *  Input parameters:
279    *  	   ide - ide disk
280    *
281    *  Return value:
282    *  	   nothing
283    ********************************************************************* */
284
285static void idecommon_dumpregs(idecommon_t *ide)
286{
287#if 0
288    uint8_t reg = 0;
289
290    reg = IDE_READREG8(ide,IDE_REG_STATUS);
291    xprintf("Status:%02X ",reg);
292
293    reg = IDE_READREG8(ide,IDE_REG_DRVHD);
294    xprintf("DrvHd:%02X ",reg);
295
296    reg = IDE_READREG8(ide,IDE_REG_CYLLSB);
297    xprintf("CylLSB:%02X ",reg);
298
299    reg = IDE_READREG8(ide,IDE_REG_CYLMSB);
300    xprintf("CylMSB:%02X ",reg);
301
302    reg = IDE_READREG8(ide,IDE_REG_SECNUM);
303    xprintf("SecNum:%02X ",reg);
304
305    reg = IDE_READREG8(ide,IDE_REG_SECCNT);
306    xprintf("SecCnt:%02X ",reg);
307
308    xprintf("\n");
309#endif
310}
311
312
313/*  *********************************************************************
314    *  idecommon_reset(ide)
315    *
316    *  Reset the IDE interface.
317    *
318    *  Input parameters:
319    *  	   ide - IDE interface
320    *
321    *  Return value:
322    *  	   0 if ok, else -1 if a timeout occured
323    ********************************************************************* */
324
325static int idecommon_reset(idecommon_t *ide)
326{
327    return 0;
328}
329
330/*  *********************************************************************
331    *  idecommon_identify(ide,buffer)
332    *
333    *  Execute an IDENTIFY command to get information about the disk.
334    *
335    *  Input parameters:
336    *  	   ide - IDE interface
337    *  	   buffer - pointer to 512 byte buffer
338    *
339    *  Return value:
340    *  	   0 if ok
341    *  	   else error code
342    ********************************************************************* */
343
344int idecommon_identify(idecommon_t *ide,uint8_t *buffer)
345{
346
347    /* Device Select Protocol; see ATAPI-4 sect 9.6 */
348
349    if (idecommon_waitnotbusy(ide) < 0) return -1;
350    IDE_WRITEREG8(ide,IDE_REG_DRVHD,(ide->idecommon_unit<<4)|0);
351    if (idecommon_waitnotbusy(ide) < 0) return -1;
352
353    /* Set device registers */
354
355    IDE_WRITEREG8(ide,IDE_REG_CYLLSB,0);
356    IDE_WRITEREG8(ide,IDE_REG_CYLMSB,0);
357    IDE_WRITEREG8(ide,IDE_REG_SECNUM,1);
358    IDE_WRITEREG8(ide,IDE_REG_SECCNT,1);
359
360    idecommon_testdrq(ide);
361
362    /* Issue command, then read ALT STATUS (9.7) */
363
364    if (ide->idecommon_atapi) {
365	IDE_WRITEREG8(ide,IDE_REG_COMMAND,IDE_CMD_ATAPI_IDENTIFY);
366	}
367    else {
368	IDE_WRITEREG8(ide,IDE_REG_COMMAND,IDE_CMD_DRIVE_INFO);
369	}
370
371    IDE_READREG8(ide,IDE_REG_ALTSTAT);
372    idecommon_waitbusy(ide);		/* should not be necessary */
373
374    /* Wait BSY=0 && DRQ=1, then read buffer, see sect 9.7 */
375
376    if (idecommon_wait_drq(ide) < 0) return -1;
377    IDE_READBUF(ide,IDE_REG_DATA,PTR2HSADDR(buffer),DISK_SECTORSIZE);
378
379    idecommon_testdrq(ide);
380
381    xprintf("Identify Success\n ");
382
383    return 0;
384}
385
386
387/*  *********************************************************************
388    *  idecommon_spinup(ide,buffer)
389    *
390    *  Execute a spinup command to the disk.
391    *
392    *  Input parameters:
393    *  	   ide - IDE interface
394    *  	   buffer - pointer to 512 byte buffer
395    *
396    *  Return value:
397    *  	   0 if ok
398    *  	   else error code
399    ********************************************************************* */
400
401int idecommon_spinup(idecommon_t *ide )
402{
403
404    /* Device Select Protocol; see ATAPI-4 sect 9.6 */
405
406    if (idecommon_waitnotbusy(ide) < 0) return -1;
407    IDE_WRITEREG8(ide,IDE_REG_DRVHD,(ide->idecommon_unit<<4)|0);
408    if (idecommon_waitnotbusy(ide) < 0) return -1;
409
410    /* Set device registers */
411
412    IDE_WRITEREG8(ide,IDE_REG_CYLLSB,0);
413    IDE_WRITEREG8(ide,IDE_REG_CYLMSB,0);
414    IDE_WRITEREG8(ide,IDE_REG_SECNUM,1);
415    IDE_WRITEREG8(ide,IDE_REG_SECCNT,1);
416
417    idecommon_testdrq(ide);
418
419    /* Issue command, then read ALT STATUS (9.7) */
420	IDE_WRITEREG8(ide,IDE_REG_COMMAND,IDE_CMD_SET_FEATURE);
421    IDE_WRITEREG8(ide,IDE_REG_FEATURE,IDE_SUB_FEAT_DEV_SPINUP);
422
423    IDE_READREG8(ide,IDE_REG_ALTSTAT);
424    idecommon_waitbusy(ide);		/* should not be necessary */
425
426    /* Wait BSY=0 && DRQ=1 see sect 9.7 */
427    if (idecommon_wait_drq(ide) < 0) return -1;
428
429    idecommon_testdrq(ide);
430
431    return 0;
432}
433
434
435/*  *********************************************************************
436    *  idecommon_packet(ide,packet,pktlen,databuf,datalen)
437    *
438    *  Process an IDE "packet" command, for ATAPI devices
439    *
440    *  Input parameters:
441    *  	   ide - IDE interface
442    *  	   packet,pktlen - command packet
443    *  	   databuf,datalen - data buffer
444    *
445    *  Return value:
446    *  	   0 if ok
447    *  	   else error code
448    ********************************************************************* */
449
450static int idecommon_packet(idecommon_t *ide,
451			uint8_t *packet,int pktlen,
452			hsaddr_t databuf,int datalen)
453{
454    uint8_t status;
455
456    /*
457     * Not valid on non-ATAPI disks
458     */
459
460    if (!ide->idecommon_atapi) return -1;
461
462    /*
463     * Set up the standard IDE registers for an ATAPI PACKET command
464     */
465
466    /* Device Select Protocol */
467    if (idecommon_waitnotbusy(ide) < 0) return -1;
468    IDE_WRITEREG8(ide,IDE_REG_DRVHD,(ide->idecommon_unit<<4));
469    if (idecommon_waitnotbusy(ide) < 0) return -1;
470
471    /* Device Registers */
472    IDE_WRITEREG8(ide,IDE_REG_BCLSB,(datalen & 0xFF));
473    IDE_WRITEREG8(ide,IDE_REG_BCMSB,((datalen >> 8) & 0xFF));
474    IDE_WRITEREG8(ide,IDE_REG_SECNUM,0);
475    IDE_WRITEREG8(ide,IDE_REG_SECCNT,0);
476    IDE_WRITEREG8(ide,IDE_REG_COMMAND,IDE_CMD_ATAPI_PACKET);
477
478    /*
479     * Wait for the DRQ bit to indicate that we should send
480     * the packet.
481     */
482
483    if (idecommon_wait_drq(ide) < 0) return -1;
484
485    status = IDE_READREG8(ide,IDE_REG_IR);
486
487    /*
488     * Send the packet to the device
489     */
490
491    IDE_WRITEBUF(ide,IDE_REG_DATA,PTR2HSADDR(packet),pktlen);
492
493    /*
494     * Wait for BSY to be cleared and DRQ to be set.
495     */
496
497    if (idecommon_wait_drq(ide) < 0) return -1;
498    status = IDE_READREG8(ide,IDE_REG_ALTSTAT);
499    if (idecommon_wait_drq(ide) < 0) return -1;
500    status = IDE_READREG8(ide,IDE_REG_IR);
501
502
503    /*
504     * Transfer data, if necessary.  The direction will depend
505     * on what the drive says.  If this is a non-data command,
506     * passing databuf == NULL can avoid all this.
507     */
508
509    if (databuf) {
510	status = IDE_READREG8(ide,IDE_REG_IR);
511	if (status & IDE_IR_CD) {
512	    xprintf("Error: Command/data should be zero\n");
513	    }
514
515	if (status & IDE_IR_IO) {	/* from device (READ) */
516	    IDE_READBUF(ide,IDE_REG_DATA,databuf,datalen);
517	    }
518	else {				/* to device (WRITE) */
519	    IDE_WRITEBUF(ide,IDE_REG_DATA,databuf,datalen);
520	    }
521
522	}
523
524
525    idecommon_testdrq(ide);
526
527    return 0;
528
529}
530
531
532/*  *********************************************************************
533    *  idecommon_request_sense(ide)
534    *
535    *  Request sense data.  This also clears a UNIT_ATTENTION condition
536    *
537    *  Input parameters:
538    *  	   ide - IDE interface
539    *
540    *  Return value:
541    *  	   0 if ok
542    *  	   else error code
543    ********************************************************************* */
544static int idecommon_request_sense(idecommon_t *ide)
545{
546    uint8_t cdb[12];
547    uint8_t sensedata[32];
548    int res;
549    int numbytes;
550
551    numbytes = sizeof(sensedata);
552
553    cdb[0] = CDB_CMD_REQSENSE;
554    cdb[1] = 0;
555    cdb[2] = 0;
556    cdb[3] = 0;
557    cdb[4] = sizeof(sensedata);
558    cdb[5] = 0;
559    cdb[6] = 0;
560    cdb[7] = 0;
561    cdb[8] = 0;
562    cdb[9] = 0;
563    cdb[10] = 0;
564    cdb[11] = 0;
565
566    memset(sensedata,0,sizeof(sensedata));
567
568    res = idecommon_packet(ide,cdb,sizeof(cdb),PTR2HSADDR(sensedata),numbytes);
569
570#if 0
571    xprintf("Sense data: ");
572    xprintf("Err:%02X ",sensedata[0]);
573    xprintf("Key:%02X ",sensedata[1]);
574    xprintf("Information:%02X%02X ",sensedata[2],sensedata[3]);
575    xprintf("ASC:%02X ASCQ:%02X ",sensedata[12],sensedata[13]);
576    xprintf("\n");
577#endif
578
579    idecommon_testdrq(ide);
580
581    return res;
582}
583
584
585/*  *********************************************************************
586    *  idecommon_read_atapi(ide,lba,numsec,buffer)
587    *
588    *  Read sector(s) from the device.  This version is for ATAPI devs.
589    *
590    *  Input parameters:
591    *  	   ide - IDE interface
592    *  	   lba - logical block address
593    *  	   numsec - number of sectors
594    *  	   buffer - buffer address
595    *
596    *  Return value:
597    *  	   0 if ok
598    *  	   else error code
599    ********************************************************************* */
600
601static int idecommon_read_atapi(idecommon_t *ide,uint64_t lba,
602				int numsec,hsaddr_t buffer)
603{
604    uint8_t cdb[12];
605    int res = 0;
606    int numbytes;
607    int idx;
608
609    numbytes = numsec << idecommon_sectorshift(ide->idecommon_sectorsize);
610
611    cdb[0] = CDB_CMD_READ;
612    cdb[1] = 0;
613    cdb[2] = ((lba >> 24) & 0xFF);
614    cdb[3] = ((lba >> 16) & 0xFF);
615    cdb[4] = ((lba >> 8)  & 0xFF);
616    cdb[5] = ((lba >> 0)  & 0xFF);
617    cdb[6] = 0;
618    cdb[7] = ((numsec >> 8) & 0xFF);
619    cdb[8] = ((numsec >> 0) & 0xFF);
620    cdb[9] = 0;
621    cdb[10] = 0;
622    cdb[11] = 0;
623
624    for (idx = 0; idx < 4; idx++) {
625	res = idecommon_packet(ide,cdb,sizeof(cdb),buffer,numbytes);
626	if (res < 0) {
627	    idecommon_request_sense(ide);
628	    continue;
629	    }
630	break;
631	}
632
633    return res;
634}
635
636
637/*  *********************************************************************
638    *  idecommon_write_atapi(ide,lba,numsec,buffer)
639    *
640    *  Write sector(s) to the device.  This version is for ATAPI disks
641    *
642    *  Input parameters:
643    *  	   ide - IDE interface
644    *  	   lba - logical block address
645    *  	   numsec - number of sectors
646    *  	   buffer - buffer address
647    *
648    *  Return value:
649    *  	   0 if ok
650    *  	   else error code
651    ********************************************************************* */
652
653static int idecommon_write_atapi(idecommon_t *ide,uint64_t lba,
654				 int numsec,hsaddr_t buffer)
655{
656    uint8_t cdb[12];
657    int res;
658    int numbytes;
659
660    numbytes = numsec << idecommon_sectorshift(ide->idecommon_sectorsize);
661
662    cdb[0] = CDB_CMD_WRITE;
663    cdb[1] = 0;
664    cdb[2] = ((lba >> 24) & 0xFF);
665    cdb[3] = ((lba >> 16) & 0xFF);
666    cdb[4] = ((lba >> 8)  & 0xFF);
667    cdb[5] = ((lba >> 0)  & 0xFF);
668    cdb[6] = 0;
669    cdb[7] = ((numsec >> 8) & 0xFF);
670    cdb[8] = ((numsec >> 0) & 0xFF);
671    cdb[9] = 0;
672    cdb[10] = 0;
673    cdb[11] = 0;
674
675    res = idecommon_packet(ide,cdb,sizeof(cdb),buffer,numbytes);
676
677    return res;
678}
679
680
681/*  *********************************************************************
682    *  idecommon_read_lba(ide,lba,numsec,buffer)
683    *
684    *  Read sector(s) from the device.
685    *
686    *  Input parameters:
687    *  	   ide - IDE interface
688    *  	   lba - logical block address
689    *  	   numsec - number of sectors
690    *  	   buffer - buffer address
691    *
692    *  Return value:
693    *  	   0 if ok
694    *  	   else error code
695    ********************************************************************* */
696
697static int idecommon_read_lba(idecommon_t *ide,uint64_t lba,int numsec,hsaddr_t buffer)
698{
699    int secidx;
700    hsaddr_t ptr;
701
702    if (idecommon_waitnotbusy(ide) < 0) return -1;
703    IDE_WRITEREG8(ide,IDE_REG_DRVHD,(ide->idecommon_unit<<4) | ((lba >> 24) & 0x0F) | 0x40);
704    if (idecommon_waitnotbusy(ide) < 0) return -1;
705
706    IDE_WRITEREG8(ide,IDE_REG_CYLMSB,((lba >> 16) & 0xFF));
707    IDE_WRITEREG8(ide,IDE_REG_CYLLSB,((lba >> 8) & 0xFF));
708    IDE_WRITEREG8(ide,IDE_REG_SECNUM,(lba & 0xFF));
709    IDE_WRITEREG8(ide,IDE_REG_SECCNT,numsec);
710
711    idecommon_testdrq(ide);
712
713    IDE_WRITEREG8(ide,IDE_REG_COMMAND,IDE_CMD_READ);
714
715    idecommon_waitbusy(ide);
716    if (idecommon_wait_drq(ide) < 0) return -1;
717
718    ptr = buffer;
719
720    for (secidx = 0; secidx < numsec; secidx++) {
721	IDE_READBUF(ide,IDE_REG_DATA,ptr,ide->idecommon_sectorsize);
722	ptr += ide->idecommon_sectorsize;
723	}
724
725    idecommon_testdrq(ide);
726
727    return 0;
728}
729
730
731/*  *********************************************************************
732    *  idecommon_write_lba(ide,lba,numsec,buffer)
733    *
734    *  Write sector(s) from the device.
735    *
736    *  Input parameters:
737    *  	   ide - IDE interface
738    *  	   lba - logical block address
739    *  	   numsec - number of sectors
740    *  	   buffer - buffer address
741    *
742    *  Return value:
743    *  	   0 if ok
744    *  	   else error code
745    ********************************************************************* */
746
747static int idecommon_write_lba(idecommon_t *ide,uint64_t lba,int numsec,hsaddr_t buffer)
748{
749    int secidx;
750    hsaddr_t ptr;
751
752    if (idecommon_waitnotbusy(ide) < 0) return -1;
753    IDE_WRITEREG8(ide,IDE_REG_DRVHD,(ide->idecommon_unit<<4) | ((lba >> 24) & 0x0F) | 0x40);
754    if (idecommon_waitnotbusy(ide) < 0) return -1;
755
756    IDE_WRITEREG8(ide,IDE_REG_CYLMSB,((lba >> 16) & 0xFF));
757    IDE_WRITEREG8(ide,IDE_REG_CYLLSB,((lba >> 8) & 0xFF));
758    IDE_WRITEREG8(ide,IDE_REG_SECNUM,(lba & 0xFF));
759    IDE_WRITEREG8(ide,IDE_REG_SECCNT,numsec);
760
761    IDE_WRITEREG8(ide,IDE_REG_COMMAND,IDE_CMD_WRITE);
762
763    if (idecommon_wait_drq(ide) < 0) return -1;
764
765    ptr = buffer;
766
767    for (secidx = 0; secidx < numsec; secidx++) {
768	IDE_WRITEBUF(ide,IDE_REG_DATA,ptr,ide->idecommon_sectorsize);
769	ptr += ide->idecommon_sectorsize;
770	}
771
772    idecommon_testdrq(ide);
773
774    return 0;
775}
776
777
778/*  *********************************************************************
779    *  idecommon_diagnostic(ide)
780    *
781    *  run the device diagnostics on the IDE device.  This also
782    *  helps us determine if it's an IDE or ATAPI disk, since the
783    *  diagnostic will leave a signature in the registers.
784    *
785    *  Input parameters:
786    *  	   softc - IDE interface
787    *
788    *  Return value:
789    *  	   0 if ok
790    *  	   else error code
791    ********************************************************************* */
792
793static int idecommon_diagnostic(idecommon_t *softc)
794{
795    if (idecommon_waitnotbusy(softc) < 0) return -1;
796    IDE_WRITEREG8(softc,IDE_REG_DRVHD,(softc->idecommon_unit<<4));
797    if (idecommon_waitnotbusy(softc) < 0) return -1;
798
799    IDE_WRITEREG8(softc,IDE_REG_COMMAND,IDE_CMD_DIAGNOSTIC);
800    if (idecommon_waitnotbusy(softc) < 0) return -1;
801
802    cfe_sleep(CFE_HZ/2);
803    idecommon_dumpregs(softc);
804
805    return 0;
806}
807
808
809/*  *********************************************************************
810    *  idecommon_getmodel(buffer,model)
811    *
812    *  Get the ASCII model name out of an IDE identify buffer.  some
813    *  byte swapping is involved here.  The trailing blanks are trimmed.
814    *
815    *  Input parameters:
816    *  	   buffer - 512-byte buffer from IDENTIFY command
817    *  	   model - 41-byte string (max) for model name
818    *
819    *  Return value:
820    *  	   nothing
821    ********************************************************************* */
822
823static void idecommon_getmodel(uint8_t *buffer,char *model)
824{
825    uint16_t w;
826    int idx;
827
828    for (idx = 0; idx < 20; idx++) {
829	w = GETWORD_LE(buffer,27+idx);
830	model[idx*2] = w >> 8;
831	model[idx*2+1] = w & 0xFF;
832	}
833    for (idx = 39; idx > 0; idx--) {
834	if (model[idx] != ' ') {
835	    model[idx+1] = '\0';
836	    break;
837	    }
838	}
839
840}
841
842/*  *********************************************************************
843    *  idecommon_devprobe(softc)
844    *
845    *  Probe the IDE device, to determine if it's actually present
846    *  or not.  If present, determine if it's IDE or ATAPI and
847    *  get the device size.  Init our internal structures so we know
848    *  how to talk to the device.
849    *
850    *  Input parameters:
851    *  	   softc - IDE structure
852    *      noisy - display stuff as we probe
853    *
854    *  Return value:
855    *  	   0 if ok, else error code
856    ********************************************************************* */
857
858int idecommon_devprobe(idecommon_t *softc,int noisy)
859{
860    int res;
861    int atapi;
862    unsigned char buffer[DISK_SECTORSIZE];
863    unsigned char model[41];
864    uint64_t ttlsect;
865    int devtype;
866    uint16_t w;
867    char *typename;
868
869    /*
870     * Reset the drive
871     */
872
873    res = idecommon_reset(softc);
874    if (res < 0) return -1;
875
876
877    /*
878     * Attempt spinup( required for SATA )
879     */
880    res = idecommon_spinup(softc);
881
882
883    /*
884     * Run diagnostic to get the signature.
885     */
886
887    res = idecommon_diagnostic(softc);
888    if (res < 0) return res;
889
890    /*
891     * Test signature
892     */
893
894    atapi = 0;
895    if ((IDE_READREG8(softc,IDE_REG_CYLLSB) == ATAPI_SIG_LSB) &&
896	(IDE_READREG8(softc,IDE_REG_CYLMSB) == ATAPI_SIG_MSB)) {
897	atapi = 1;
898	}
899
900    if (noisy) {
901	if (atapi) xprintf("ATAPI: ");
902	else xprintf("IDE: ");
903	}
904
905    /*
906     * Do the appropriate IDENTIFY command to get device information
907     */
908    softc->idecommon_atapi = atapi;
909    res = idecommon_identify(softc,&buffer[0]);
910    if (res < 0) return -1;
911
912    /*
913     * Using that information, determine our device type
914     */
915
916    if (!atapi) {
917	devtype = IDE_DEVTYPE_DISK;
918	typename = "Disk";
919	}
920    else {
921	w = GETWORD_LE(&buffer[0],0);
922	switch ((w >> 8) & 31) {
923	    case 5:		/* CD-ROM */
924		devtype = IDE_DEVTYPE_CDROM;
925		typename = "CD-ROM";
926		break;
927	    default:
928		devtype = IDE_DEVTYPE_ATAPIDISK;
929		typename = "Disk";
930		break;
931	    }
932	}
933
934    /*
935     * Say nice things about the device.
936     */
937
938    noisy = 1;
939    idecommon_getmodel(&buffer[0], (char *)model);
940    if (noisy) xprintf("%s, \"%s\"",typename,model);
941
942#ifdef _IDE_DEBUG_
943    if (!softc->idecommon_atapi) {
944	ttlsect = (GETWORD_LE(buffer,57) + (GETWORD_LE(buffer,58) << 16));
945	if (noisy) xprintf(", Sectors: %llu (%lld MB)",ttlsect,
946			   (uint64_t) (ttlsect/2048));
947	}
948    else {
949	ttlsect = 0;
950	}
951
952#endif
953    if (noisy) xprintf("\n");
954
955    /*
956     * Initialize internal structure info, especially pointers to the
957     * read/write routines and the sector size.
958     */
959
960    softc->idecommon_ttlsect = ttlsect;
961    idecommon_init(softc,devtype);
962
963    return res;
964}
965
966/*  *********************************************************************
967    *  idecommon_open(ctx)
968    *
969    *  Process the CFE OPEN call for this device.  For IDE disks,
970    *  the device is reset and identified, and the geometry is
971    *  determined.
972    *
973    *  Input parameters:
974    *  	   ctx - device context
975    *
976    *  Return value:
977    *  	   0 if ok, else error code
978    ********************************************************************* */
979
980
981int idecommon_open(cfe_devctx_t *ctx)
982{
983    idecommon_t *softc = ctx->dev_softc;
984    int res;
985
986    if (softc->idecommon_deferprobe) {
987	res = idecommon_devprobe(softc,0);
988	if (res < 0) return res;
989	}
990
991    return 0;
992}
993
994/*  *********************************************************************
995    *  idecommon_read(ctx,buffer)
996    *
997    *  Process a CFE READ command for the IDE device.  This is
998    *  more complex than it looks, since CFE offsets are byte offsets
999    *  and we may need to read partial sectors.
1000    *
1001    *  Input parameters:
1002    *  	   ctx - device context
1003    *  	   buffer - buffer descriptor
1004    *
1005    *  Return value:
1006    *  	   number of bytes read, or <0 if an error occured
1007    ********************************************************************* */
1008
1009int idecommon_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer)
1010{
1011    idecommon_t *softc = ctx->dev_softc;
1012    hsaddr_t bptr;
1013    int blen;
1014    int numsec;
1015    int res = 0;
1016    int amtcopy;
1017    uint64_t lba;
1018    uint64_t offset;
1019    unsigned char sector[MAX_SECTORSIZE];
1020    int sectorshift;
1021
1022    sectorshift = idecommon_sectorshift(softc->idecommon_sectorsize);
1023
1024    bptr = buffer->buf_ptr;
1025    blen = buffer->buf_length;
1026    offset = buffer->buf_offset;
1027    numsec = (blen + softc->idecommon_sectorsize - 1) >> sectorshift;
1028
1029    if (offset & (softc->idecommon_sectorsize-1)) {
1030	lba = (offset >> sectorshift);
1031	res = (*softc->idecommon_readfunc)(softc,lba,1,PTR2HSADDR(sector));
1032	if (res < 0) goto out;
1033	amtcopy = softc->idecommon_sectorsize - (offset & (softc->idecommon_sectorsize-1));
1034	if (amtcopy > blen) amtcopy = blen;
1035	hs_memcpy_to_hs(bptr,&sector[offset & (softc->idecommon_sectorsize-1)],amtcopy);
1036	bptr += amtcopy;
1037	offset += amtcopy;
1038	blen -= amtcopy;
1039	}
1040
1041    while (blen >= softc->idecommon_sectorsize) {
1042	lba = (offset >> sectorshift);
1043	amtcopy = softc->idecommon_sectorsize;
1044	res = (*softc->idecommon_readfunc)(softc,lba,1,bptr);
1045	if (res < 0) goto out;
1046	bptr += amtcopy;
1047	offset += amtcopy;
1048	blen -= amtcopy;
1049	}
1050
1051    if (blen) {
1052	lba = (offset >> sectorshift);
1053	res = (*softc->idecommon_readfunc)(softc,lba,1,PTR2HSADDR(sector));
1054	if (res < 0) goto out;
1055	amtcopy = blen;
1056	hs_memcpy_to_hs(bptr,sector,amtcopy);
1057	bptr += amtcopy;
1058	offset += amtcopy;
1059	blen -= amtcopy;
1060	}
1061
1062out:
1063    buffer->buf_retlen = bptr - buffer->buf_ptr;
1064
1065    return res;
1066}
1067
1068/*  *********************************************************************
1069    *  idecommon_inpstat(ctx,inpstat)
1070    *
1071    *  Test input status for the IDE disk.  Disks are always ready
1072    *  to read.
1073    *
1074    *  Input parameters:
1075    *  	   ctx - device context
1076    *  	   inpstat - input status structure
1077    *
1078    *  Return value:
1079    *  	   0
1080    ********************************************************************* */
1081
1082int idecommon_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat)
1083{
1084    /* idecommon_t *softc = ctx->dev_softc; */
1085
1086    inpstat->inp_status = 1;
1087    return 0;
1088}
1089
1090/*  *********************************************************************
1091    *  idecommon_write(ctx,buffer)
1092    *
1093    *  Process a CFE WRITE command for the IDE device.  If the write
1094    *  involves partial sectors, the affected sectors are read first
1095    *  and the changes are merged in.
1096    *
1097    *  Input parameters:
1098    *  	   ctx - device context
1099    *  	   buffer - buffer descriptor
1100    *
1101    *  Return value:
1102    *  	   number of bytes write, or <0 if an error occured
1103    ********************************************************************* */
1104
1105int idecommon_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer)
1106{
1107    idecommon_t *softc = ctx->dev_softc;
1108    hsaddr_t bptr;
1109    int blen;
1110    int numsec;
1111    int res = 0;
1112    int amtcopy;
1113    uint64_t offset;
1114    uint64_t lba;
1115    unsigned char sector[MAX_SECTORSIZE];
1116    int sectorshift;
1117
1118    sectorshift = (softc->idecommon_sectorsize == 2048) ? 11 : 9;
1119
1120    bptr = buffer->buf_ptr;
1121    blen = buffer->buf_length;
1122    offset = buffer->buf_offset;
1123    numsec = (blen + softc->idecommon_sectorsize - 1) >> sectorshift;
1124
1125    if (offset & (softc->idecommon_sectorsize-1)) {
1126	lba = (offset >> sectorshift);
1127	res = (*softc->idecommon_readfunc)(softc,lba,1,PTR2HSADDR(sector));
1128	if (res < 0) goto out;
1129	amtcopy = softc->idecommon_sectorsize - (offset & (softc->idecommon_sectorsize-1));
1130	if (amtcopy > blen) amtcopy = blen;
1131	hs_memcpy_from_hs(&sector[offset & (softc->idecommon_sectorsize-1)],bptr,amtcopy);
1132	res = (*softc->idecommon_writefunc)(softc,lba,1,PTR2HSADDR(sector));
1133	if (res < 0) goto out;
1134	bptr += amtcopy;
1135	offset += amtcopy;
1136	blen -= amtcopy;
1137	}
1138
1139    while (blen >= softc->idecommon_sectorsize) {
1140	amtcopy = softc->idecommon_sectorsize;
1141	lba = (offset >> sectorshift);
1142	res = (*softc->idecommon_writefunc)(softc,lba,1,bptr);
1143	if (res < 0) goto out;
1144	bptr += amtcopy;
1145	offset += amtcopy;
1146	blen -= amtcopy;
1147	}
1148
1149    if (blen) {
1150	lba = (offset >> sectorshift);
1151	res = (*softc->idecommon_readfunc)(softc,lba,1,PTR2HSADDR(sector));
1152	if (res < 0) goto out;
1153	amtcopy = blen;
1154	hs_memcpy_from_hs(sector,bptr,amtcopy);
1155	res = (*softc->idecommon_writefunc)(softc,lba,1,PTR2HSADDR(sector));
1156	if (res < 0) goto out;
1157	bptr += amtcopy;
1158	offset += amtcopy;
1159	blen -= amtcopy;
1160	}
1161
1162out:
1163    buffer->buf_retlen = bptr - buffer->buf_ptr;
1164
1165    return res;
1166}
1167
1168
1169/*  *********************************************************************
1170    *  idecommon_ioctl(ctx,buffer)
1171    *
1172    *  Process device I/O control requests for the IDE device.
1173    *
1174    *  Input parameters:
1175    *  	   ctx - device context
1176    *  	   buffer - buffer descriptor
1177    *
1178    *  Return value:
1179    *  	   0 if ok
1180    *  	   else error code
1181    ********************************************************************* */
1182
1183int idecommon_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer)
1184{
1185    idecommon_t *softc = ctx->dev_softc;
1186    unsigned int info;
1187    unsigned long long linfo;
1188    blockdev_info_t devinfo;
1189
1190    switch ((int)buffer->buf_ioctlcmd) {
1191	case IOCTL_BLOCK_GETBLOCKSIZE:
1192	    info = softc->idecommon_sectorsize;
1193	    hs_memcpy_to_hs(buffer->buf_ptr,&info,sizeof(info));
1194	    break;
1195	case IOCTL_BLOCK_GETTOTALBLOCKS:
1196	    linfo = softc->idecommon_ttlsect;
1197	    hs_memcpy_to_hs(buffer->buf_ptr,&linfo,sizeof(linfo));
1198	    break;
1199	case IOCTL_BLOCK_GETDEVTYPE:
1200	    devinfo.blkdev_totalblocks = softc->idecommon_ttlsect;
1201	    devinfo.blkdev_blocksize = softc->idecommon_sectorsize;
1202	    devinfo.blkdev_devtype = (softc->idecommon_devtype == IDE_DEVTYPE_CDROM) ?
1203		BLOCK_DEVTYPE_CDROM : BLOCK_DEVTYPE_DISK;
1204	    hs_memcpy_to_hs(buffer->buf_ptr,&devinfo,sizeof(devinfo));
1205	    break;
1206	default:
1207	    return -1;
1208	}
1209
1210    return 0;
1211}
1212
1213/*  *********************************************************************
1214    *  idecommon_close(ctx)
1215    *
1216    *  Close the I/O device.
1217    *
1218    *  Input parameters:
1219    *  	   ctx - device context
1220    *
1221    *  Return value:
1222    *  	   0 if ok, else error code
1223    ********************************************************************* */
1224
1225int idecommon_close(cfe_devctx_t *ctx)
1226{
1227    /* idecommon_t *softc = ctx->dev_softc; */
1228
1229    return 0;
1230}
1231
1232
1233/*  *********************************************************************
1234    *  idecommon_init(ide,devtype)
1235    *
1236    *  Set up internal values based on the device type
1237    *
1238    *  Input parameters:
1239    *  	   ide - IDE interface
1240    *  	   devtype - device type
1241    *
1242    *  Return value:
1243    *  	   nothing
1244    ********************************************************************* */
1245
1246void idecommon_init(idecommon_t *ide,int devtype)
1247{
1248
1249    ide->idecommon_devtype = devtype;
1250
1251    switch (ide->idecommon_devtype) {
1252	case IDE_DEVTYPE_DISK:
1253	    ide->idecommon_atapi = FALSE;
1254	    ide->idecommon_sectorsize = DISK_SECTORSIZE;
1255	    break;
1256	case IDE_DEVTYPE_CDROM:
1257	    ide->idecommon_atapi = TRUE;
1258	    ide->idecommon_sectorsize = CDROM_SECTORSIZE;
1259	    break;
1260	case IDE_DEVTYPE_ATAPIDISK:
1261	    ide->idecommon_atapi = TRUE;
1262	    ide->idecommon_sectorsize = DISK_SECTORSIZE;
1263	    break;
1264	default:
1265	    ide->idecommon_atapi = FALSE;
1266	    ide->idecommon_sectorsize = DISK_SECTORSIZE;
1267	    break;
1268	}
1269
1270    if (ide->idecommon_atapi) {
1271	ide->idecommon_readfunc = idecommon_read_atapi;
1272	ide->idecommon_writefunc = idecommon_write_atapi;
1273	}
1274    else {
1275	ide->idecommon_readfunc = idecommon_read_lba;
1276	ide->idecommon_writefunc = idecommon_write_lba;
1277	}
1278}
1279
1280/*  *********************************************************************
1281    *  idecommon_attach(devdisp)
1282    *
1283    *  Set up a cfe_devdisp structure that points at the idecommon
1284    *  structures.
1285    *
1286    *  Input parameters:
1287    *  	   devdisp - cfe_devdisp_t structure
1288    *
1289    *  Return value:
1290    *  	   nothing
1291    ********************************************************************* */
1292void idecommon_attach(cfe_devdisp_t *disp)
1293{
1294    disp->dev_open = idecommon_open;
1295    disp->dev_read = idecommon_read;
1296    disp->dev_inpstat = idecommon_inpstat;
1297    disp->dev_write = idecommon_write;
1298    disp->dev_ioctl = idecommon_ioctl;
1299    disp->dev_close = idecommon_close;
1300    disp->dev_poll = NULL;
1301    disp->dev_reset = NULL;
1302}
1303