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