1 /* MFM & IDE Hard Disk Device Driver for MMURTL.
\r
2 This driver does not depend on the data stored in CMOS RAM for
\r
3 drive geometry. Three routines determine number of sectors per track,
\r
4 number of cylinders, and number of heads by actually trying to seek
\r
5 and/or read them. This eliminates dependence on some system's proprietary
\r
9 #define U32 unsigned long
\r
11 #define U16 unsigned int
\r
13 #define U8 unsigned char
\r
16 /* MMURTL OS PROTOTYPES */
\r
18 extern far AllocExch(U32 *pExchRet);
\r
19 extern far U32 InitDevDr(U32 dDevNum,
\r
24 extern far U32 UnMaskIRQ(U32 IRQNum);
\r
25 extern far U32 MaskIRQ(U32 IRQNum);
\r
26 extern far U32 SetIRQVector(U32 IRQNum, S8 *pIRQ);
\r
27 extern far U32 EndOfIRQ(U32 IRQNum);
\r
28 extern far U32 SendMsg(U32 Exch, U32 msg1, U32 msg2);
\r
29 extern far U32 ISendMsg(U32 Exch, U32 msg1, U32 msg2);
\r
30 extern far U32 WaitMsg(U32 Exch, U32 *pMsgRet);
\r
31 extern far U32 CheckMsg(U32 Exch, U32 *pMsgRet);
\r
32 extern far U32 Alarm(U32 Exch, U32 count);
\r
33 extern far U32 KillAlarm(U32 Exch);
\r
34 extern far U32 Sleep(U32 count);
\r
35 extern far void MicroDelay(U32 us15count);
\r
36 extern far void OutByte(U8 Byte, U16 wPort);
\r
37 extern far void OutWord(U16 Word, U16 wPort);
\r
38 extern far U8 InByte(U16 wPort);
\r
39 extern far U16 InWord(U16 wPort);
\r
40 extern far U8 ReadCMOS(U16 Address);
\r
41 extern far void CopyData(U8 *pSource, U8 *pDestination, U32 dBytes);
\r
42 extern far InWords(U32 dPort, U8 *pDataIn, U32 dBytes);
\r
43 extern far OutWords(U32 dPort, U8 *pDataOut, U32 dBytes);
\r
45 /* Near External for troubleshooting */
\r
47 extern long xprintf(char *fmt, ...);
\r
50 /* LOCAL PROTOTYPES */
\r
52 U32 hdisk_setup(void);
\r
53 static void interrupt hdisk_isr(void); /* The HD interrupt function */
\r
54 static U32 hd_format_track(U32 dLBA, U32 dnBlocks);
\r
55 static void hd_reset(void);
\r
56 static U32 send_command(U8 parm);
\r
57 static U32 hd_wait (void);
\r
58 static U32 check_busy(void);
\r
59 static U32 hd_seek(U32 dLBA);
\r
60 static U32 hd_recal(U8 drive);
\r
61 static U32 hd_write(U32 dLBA, U32 dnBlocks, U8 *pDataOut);
\r
62 static U32 hd_read(U32 dLBA, U32 dnBlocks, U8 *pDataIn);
\r
63 static U32 hd_status(U8 LastCmd);
\r
64 static U32 setupseek(U32 dLBA, U32 nBlks);
\r
65 static U32 hd_init(U8 drive);
\r
66 static U32 ReadSector(U32 Cylinder, U32 HdSect, U8 *pDataRet);
\r
68 /* The following 3 calls are required in every MMURTL device driver */
\r
70 static U32 hddev_op(U32 dDevice,
\r
76 static U32 hddev_stat(U32 dDevice,
\r
81 static U32 hddev_init(U32 dDevNum,
\r
85 /* LOCAL DEFINITIONS */
\r
89 /* Error Codes to return */
\r
92 #define ErcNotInstalled 504
\r
94 #define ErcBadBlock 651
\r
95 #define ErcAddrMark 652
\r
96 #define ErcBadECC 653
\r
97 #define ErcSectNotFound 654
\r
98 #define ErcNoDrive0 655
\r
99 #define ErcNotSupported 656
\r
100 #define ErcBadHDC 658
\r
101 #define ErcBadSeek 659
\r
102 #define ErcHDCTimeOut 660
\r
103 #define ErcOverRun 661
\r
104 #define ErcBadLBA 662
\r
105 #define ErcInvalidDrive 663
\r
106 #define ErcBadOp 664
\r
107 #define ErcBadRecal 665
\r
108 #define ErcSendHDC 666
\r
109 #define ErcNotReady 667
\r
110 #define ErcBadCmd 668
\r
111 #define ErcNeedsInit 669
\r
112 #define ErcTooManyBlks 670 /* The controller can only do 128 max */
\r
113 #define ErcZeroBlks 671 /* 0 Blocks not allowed for this cmd */
\r
114 #define ErcWriteFault 672 /* WriteFault bit set... bummer */
\r
116 #define ErcMissHDDInt 675
\r
118 #define ErcHDDMsgBogus 676
\r
119 #define ErcHDDIntMsg 677
\r
120 #define ErcHDDAlarmMsg 678
\r
122 /* Commands accepted by this HD driver */
\r
127 #define CmdVerify 3
\r
128 #define CmdFmtBlk 4
\r
129 #define CmdFmtTrk 5
\r
130 #define CmdSeekTrk 6
\r
131 #define CmdSetMedia 7 /* Not used unless mountable */
\r
132 #define CmdResetHdw 8 /* Used to reset controller hardware */
\r
134 /* CmdReadSect is the only device specific call in the IDE/MFM hard
\r
135 disk device driver. This allows you to read ONE sector
\r
136 specified by Cylinder, head and Sector number.
\r
137 Cylinder is HiWord of dLBA in DeviceOp call,
\r
138 Head is LoWord of dLBA in DeviceOp call, and
\r
139 Sector number is LowWord in dnBlocks.
\r
142 #define CmdReadSect 256 /* only device specific call in HDD */
\r
144 /* HDC port definitions */
\r
146 #define HD_PORT 0x1f0
\r
148 /* When writing to the port+X (where X =):
\r
149 0 - write data (1F0h - 16 bit)
\r
150 1 - pre-comp (1F1h)
\r
151 2 - sector count (1F2h)
\r
152 3 - sector number (1F3h)
\r
154 5 - high cyl (1F5h)
\r
155 6 - size/drive/head (1F6h)
\r
156 7 - command register (1F7h)
\r
158 When reading from the port+X (where X =):
\r
159 0 - read data (1F0h - 16 bit)
\r
160 1 - error register (1F1h)
\r
161 2 - sector count (1F2h)
\r
162 3 - sector number (1F3h)
\r
164 5 - high cyl (1F5h)
\r
165 6 - size/drive/head (1F6h)
\r
166 7 - status register (1F7h)
\r
169 #define HD_REG_PORT 0x3f6
\r
171 /* This is a byte wide write only control port
\r
172 that allows reset and defines some special
\r
173 characteristics of the hard drives.
\r
177 2 Reset Bit - Set, wait 50us, then Reset
\r
178 3 Mucho Heads Flag. Set = More than 8 heads
\r
182 7 Disable retries (same as six, either one set)
\r
185 /* HDC Status Register Bit Masks (1F7h) */
\r
187 #define BUSY 0x80 /* busy.. can't talk now! */
\r
188 #define READY 0x40 /* Drive Ready */
\r
189 #define WRITE_FAULT 0x20 /* Bad news */
\r
190 #define SEEKOK 0x10 /* Seek Complete */
\r
191 #define DATA_REQ 0x08 /* Sector buffer needs servicing */
\r
192 #define CORRECTED 0x04 /* ECC corrected data was read */
\r
193 #define REV_INDEX 0x02 /* Set once each disk revolution */
\r
194 #define ERROR 0x01 /* data address mark not found */
\r
196 /* HDC Error Register Bit Masks (1F1h) */
\r
198 #define BAD_SECTOR 0x80 /* bad block */
\r
199 #define BAD_ECC 0x40 /* bad data ecc */
\r
200 #define BAD_IDMARK 0x10 /* id not found */
\r
201 #define BAD_CMD 0x04 /* aborted command */
\r
202 #define BAD_SEEK 0x02 /* trk 0 not found on recalibrate, or bad seek */
\r
203 #define BAD_ADDRESS 0x01 /* data address mark not found */
\r
206 /* HDC internal command bytes (HDC_Cmd[7]) */
\r
208 #define HDC_RECAL 0x10 /* 0001 0000 */
\r
209 #define HDC_READ 0x20 /* 0010 0000 */
\r
210 #define HDC_READ_LONG 0x22 /* 0010 0010 */
\r
211 #define HDC_WRITE 0x30 /* 0011 0000 */
\r
212 #define HDC_WRITE_LONG 0x32 /* 0011 0010 */
\r
213 #define HDC_VERIFY 0x40 /* 0100 0000 */
\r
214 #define HDC_FORMAT 0x50 /* 0101 0000 */
\r
215 #define HDC_SEEK 0x70 /* 0111 0000 */
\r
216 #define HDC_DIAG 0x90 /* 1001 0000 */
\r
217 #define HDC_SET_PARAMS 0x91 /* 1001 0001 */
\r
219 /* L O C A L D A T A */
\r
221 static U8 hd_Cmd[8]; /* For all 8 command bytes */
\r
223 static U8 fDataReq; /* Flag to indicate is fDataRequest is active */
\r
224 static U8 statbyte; /* From HDC status register last time it was read */
\r
226 static U8 hd_control; /* Current control byte value */
\r
227 static U8 hd_command; /* Current Command */
\r
228 static U8 hd_drive; /* Current Physical Drive, 0 or 1 */
\r
229 static U8 hd_head; /* Calculated from LBA - which head */
\r
230 static U8 hd_nsectors; /* Calculated from LBA - n sectors to read/write */
\r
231 static U8 hd_sector; /* Calculated from LBA - Starting sector */
\r
233 /* Current type drive 0 & 1 found in CMOS or Set by caller. */
\r
234 /* Current number of heads, cylinders, and sectors set by caller */
\r
236 static U8 hd0_type;
\r
237 static U8 hd0_heads;
\r
238 static U8 hd0_secpertrk;
\r
239 static U16 hd0_cyls;
\r
241 static U8 hd1_type;
\r
242 static U8 hd1_heads;
\r
243 static U8 hd1_secpertrk;
\r
244 static U16 hd1_cyls;
\r
248 static struct statstruct
\r
254 U8 type_now; /* current fdisk_table for drive selected */
\r
255 U8 resvd0[2]; /* padding for DWord align */
\r
256 U32 nCyl; /* total physical cylinders */
\r
257 U32 nHead; /* total heads on device */
\r
258 U32 nSectors; /* Sectors per track */
\r
259 U32 nBPS; /* Number of bytes per sect. 32 bytes out to here.*/
\r
265 U8 fIntOnReset; /* Interrupt was received on HDC_RESET */
\r
272 U8 ResetStatByte; /* Status Byte immediately after RESET */
\r
275 U32 resvd1[2]; /* out to 64 bytes */
\r
278 static struct statstruct hdstatus;
\r
279 static struct statstruct HDStatTmp;
\r
281 static struct dcbtype
\r
303 static struct dcbtype hdcb[2]; /* two HD device control blocks */
\r
305 /* Exch and msgs space for HD ISR */
\r
307 static U32 hd_exch;
\r
310 static U32 hd_msg2;
\r
312 static long HDDInt;
\r
314 /*======================================================*/
\r
315 /*=================== START OF CODE ====================*/
\r
316 /*======================================================*/
\r
318 /*********************************************************
\r
319 This is called ONCE to initialize the HD Driver.
\r
320 *********************************************************/
\r
322 U32 hdisk_setup(void)
\r
326 /* first we set up the 2 DCBs in anticipation of calling InitDevDr */
\r
328 hdcb[0].Name[0] = 'H';
\r
329 hdcb[0].Name[1] = 'D';
\r
330 hdcb[0].Name[2] = '0';
\r
331 hdcb[0].sbName = 3;
\r
332 hdcb[0].type = 1; /* Random */
\r
333 hdcb[0].nBPB = 512;
\r
334 hdcb[0].nBlocks = 524288; /* largest disk handled - 2Gb disks*/
\r
335 hdcb[0].pDevOp = &hddev_op;
\r
336 hdcb[0].pDevInit = &hddev_init;
\r
337 hdcb[0].pDevSt = &hddev_stat;
\r
339 hdcb[1].Name[0] = 'H';
\r
340 hdcb[1].Name[1] = 'D';
\r
341 hdcb[1].Name[2] = '1';
\r
342 hdcb[1].sbName = 3;
\r
343 hdcb[1].type = 1; /* Random */
\r
344 hdcb[1].nBPB = 512;
\r
345 hdcb[1].nBlocks = 524288; /* largest device handled - 2Gb disks*/
\r
346 hdcb[1].pDevOp = &hddev_op;
\r
347 hdcb[1].pDevInit = &hddev_init;
\r
348 hdcb[1].pDevSt = &hddev_stat;
\r
350 /* These are defaulted to non zero values to
\r
351 ensure we don't get a divide by zero during initial calculations
\r
355 hd0_type = ReadCMOS(0x19); /* read this but don't use it */
\r
356 hd0_heads = 16; /* Max */
\r
357 hd0_secpertrk = 17; /* most common */
\r
358 hd0_cyls = 1024; /* Max */
\r
360 hd1_type = ReadCMOS(0x1A);
\r
362 hd1_secpertrk = 17;
\r
365 erc = AllocExch(&hd_exch); /* Exhange for HD Task to use */
\r
367 SetIRQVector(14, &hdisk_isr);
\r
370 /* Documentation lists the fixed disk types at CMOS 11h and 12h,
\r
371 and also shows them at 19h and 1Ah. We don't actually read them
\r
372 because they are not dependable. They vary from BIOS to BIOS.
\r
373 We have to make this sucker work the hard way.
\r
376 /* Reset the HDC - hd_reset resets the controller (which controlls
\r
377 both drives). We have to do it once, then try both physical drives.
\r
378 If the second drive is not there, some controllers will lock-up
\r
379 (the el-cheapos). In this case we have to reset it again so it
\r
380 will work. It seems like a lot of work, but to make it function
\r
381 with the widest range of IDE and MFM controllers this is the
\r
382 only way I have found that works.
\r
385 hd_reset(); /* no error is returned */
\r
387 /* Now we attempt to select and recal both drives.
\r
388 The driver MUST be able to recal the first physical drive
\r
389 or the Driver won't install.
\r
392 erc = hd_recal(0); /* try to recal */
\r
394 { /* try one more time! */
\r
396 erc = hd_recal(0); /* try to recal */
\r
399 hdcb[0].last_erc = erc;
\r
400 hd0_type = 0; /* Must not be a valid drive */
\r
401 return(ErcNoDrive0);
\r
405 /* if we got here, drive 0 looks OK and the controller is
\r
406 functioning. Now we try drive 1 if type > 0.
\r
411 erc = hd_recal(1); /* try to recal if CMOS says it's there */
\r
414 hdcb[1].last_erc = erc;
\r
415 hd1_type = 0; /* Guess it's not a valid drive */
\r
419 /* We must redo drive 0 cause some cheap controllers lockup
\r
420 on us if drive 1 is not there. They SHOULD simply return
\r
421 a Bad Command bit set in the Error register, but they don't. */
\r
424 erc = hd_recal(0); /* recal drive 0 */
\r
425 hdcb[0].last_erc = erc;
\r
429 return(erc = InitDevDr(12, &hdcb, 2, 1));
\r
433 /************************************************************
\r
434 Reset the HD controller. This should only be called by
\r
435 DeviceInit or hdisk_setup. This resets the controller
\r
436 and reloads parameters for both drives (if present) and
\r
437 attempts to recal them.
\r
438 *************************************************************/
\r
440 static void hd_reset(void)
\r
443 UnMaskIRQ(14); /* enable the IRQ */
\r
444 OutByte(4, HD_REG_PORT); /* reset the controller */
\r
445 MicroDelay(4); /* Delay 60us */
\r
447 /* bit 3 of HD_REG must be 1 for access to heads 8-15 */
\r
448 /* Clear "MUCHO" heads bit, and clear the reset bit */
\r
450 OutByte(hd_control & 0x0f, HD_REG_PORT);
\r
452 Sleep(20); /* 200ms - seems some controllers are SLOW!! */
\r
453 i = CheckMsg(hd_exch, &hd_msg); /* Eat Int if one came back */
\r
455 hdstatus.ResetStatByte = statbyte; /* The ISR gets statbyte */
\r
457 if (i) hdstatus.fIntOnReset = 1;
\r
458 else hdstatus.fIntOnReset = 0;
\r
462 /*************************************************************
\r
463 The ISR is VERY simple. It just waits for an interrupt, gets
\r
464 the single status byte from the controller (which clears the
\r
465 interrupt condition) then sends an empty message to the
\r
466 exchange where the HD Driver task will be waiting.
\r
467 This tells the HD task currently running that it's got
\r
468 some status to act on!
\r
469 ****************************************************************/
\r
470 static void interrupt hdisk_isr(void)
\r
472 statbyte = InByte(HD_PORT+7);
\r
474 ISendMsg(hd_exch, 0xfffffff0, 0xfffffff0);
\r
478 /*************************************************************
\r
479 This checks the HDC controller to see if it's busy so we can
\r
480 send it commands or read the rest of the registers.
\r
481 We will wait up to 3 seconds then error out.
\r
482 The caller should call check_busy and check the error.
\r
483 If it's 0 then the controller became ready in less than
\r
484 3 seconds. ErcNotReady will be returned otherwise.
\r
485 It leaves the status byte in the global statbyte.
\r
486 ****************************************************************/
\r
488 static U32 check_busy(void)
\r
493 while (count++ < 60)
\r
495 statbyte = InByte(HD_PORT+7);
\r
496 if ((statbyte & BUSY) == 0) return(ok);
\r
497 Sleep(5); /* 50ms shots */
\r
499 return(ErcNotReady); /* controller out to lunch! */
\r
502 /*************************************************************
\r
503 This sends the SetParams command to the controller to set
\r
504 up the drive geometry (nHeads, nSectors, etc.).
\r
505 ****************************************************************/
\r
507 static U32 hd_init(U8 drive)
\r
510 /* set max heads, sectors and cylinders */
\r
513 hd_Cmd[2] = hd0_secpertrk; /* sector count */
\r
514 hd_Cmd[6] = (drive << 4) | ((hd0_heads-1) & 0x0f) | 0xa0; /* hds & drv */
\r
518 hd_Cmd[2] = hd1_secpertrk; /* sector count */
\r
519 hd_Cmd[6] = (drive << 4) | ((hd1_heads-1) & 0x0f) | 0xa0; /* hds & drv */
\r
523 hd_Cmd[4] = 0; /* cyl = 0 for init */
\r
524 hd_Cmd[5] = 0; /* cyl = 0 for init */
\r
526 erc = send_command(HDC_SET_PARAMS); /* Send the command */
\r
527 erc = hd_wait(); /* wait for interrupt */
\r
529 erc = hd_status(HDC_SET_PARAMS);
\r
533 /******************************************
\r
534 Wait for the hardware interrupt to occur.
\r
535 Time-out and return if no interrupt.
\r
536 ********************************************/
\r
538 static U32 hd_wait(void)
\r
542 /* Set alarm for 3 seconds */
\r
545 KillAlarm(hd_exch); /* kill any pending alarm */
\r
547 erc = Alarm(hd_exch, 300); /* Set it up again */
\r
549 return(erc); /* bad problem */
\r
551 erc = WaitMsg(hd_exch, &hd_msg);
\r
553 KillAlarm(hd_exch);
\r
555 if (hd_msg != 0xfffffff0)
\r
556 { /* HD interrupt sends fffffff0 */
\r
558 return(ErcMissHDDInt);
\r
560 return(ErcHDCTimeOut); /* Alarm sends 0xffffffff */
\r
564 KillAlarm(hd_exch);
\r
569 /********************************************
\r
570 Recalibrate the drive.
\r
571 *********************************************/
\r
573 static U32 hd_recal(U8 drive)
\r
577 hd_Cmd[6] = (drive << 4) | (hd_head & 0x0f) | 0xa0;
\r
578 erc = send_command(HDC_RECAL);
\r
580 erc = hd_wait(); /* wait for interrupt */
\r
582 erc = hd_status(HDC_RECAL);
\r
584 hdstatus.LastRecalErc1 = erc;
\r
586 hdstatus.LastRecalErc0 = erc;
\r
591 /********************************************
\r
592 Send the command to the controller.
\r
593 Clear the Echange of any left over
\r
594 alarm or int messages before we
\r
596 *********************************************/
\r
598 static U32 send_command(U8 Cmd)
\r
602 while (CheckMsg(hd_exch, &msg) == 0); /* Empty it */
\r
604 /* bit 3 of HD_REG must be 1 for access to heads 8-15 */
\r
607 hd_control |= 0x08;
\r
608 OutByte(hd_control, HD_REG_PORT); /* set bit for head > 7 */
\r
609 hd_control &= 0xf7;
\r
611 erc = check_busy();
\r
612 if (!erc) OutByte(hd_Cmd[1], HD_PORT+1);
\r
613 if (!erc) erc = check_busy();
\r
614 if (!erc) OutByte(hd_Cmd[2], HD_PORT+2);
\r
615 if (!erc) erc = check_busy();
\r
616 if (!erc) OutByte(hd_Cmd[3], HD_PORT+3);
\r
617 if (!erc) erc = check_busy();
\r
618 if (!erc) OutByte(hd_Cmd[4], HD_PORT+4);
\r
619 if (!erc) erc = check_busy();
\r
620 if (!erc) OutByte(hd_Cmd[5], HD_PORT+5);
\r
621 if (!erc) erc = check_busy();
\r
622 if (!erc) OutByte(hd_Cmd[6], HD_PORT+6);
\r
623 if (!erc) erc = check_busy();
\r
624 if (!erc) OutByte(Cmd, HD_PORT+7);
\r
628 /*************************************************************
\r
629 This sets up the cylinder, head and sector variables for all
\r
630 commands that require them (read, write, verify, format, seek).
\r
631 nBlks ca NOT be greater than the hardware can handle. For
\r
632 IDE/MFM controllers this is 128 sectors.
\r
633 The caculated values are placed in the proper command byte
\r
634 in anticipation of the command being sent.
\r
635 *************************************************************/
\r
637 static U32 setupseek(U32 dLBA, U32 nBlks)
\r
642 if (nBlks > 256) return ErcTooManyBlks;
\r
643 if (nBlks == 0) return ErcZeroBlks;
\r
645 hd_nsectors = nBlks;
\r
646 if (hd_nsectors == 256) hd_nsectors = 0; /* 0==256 for controller */
\r
648 if (hd_drive == 0)
\r
651 cyl = dLBA / (hd0_heads * hd0_secpertrk);
\r
652 j = dLBA % (hd0_heads * hd0_secpertrk); /* remainder */
\r
654 /* we now know what cylinder, calculate head and sector */
\r
656 hd_head = j / hd0_secpertrk;
\r
657 hd_sector = j % hd0_secpertrk + 1; /* sector number start at 1 !!! */
\r
663 cyl = dLBA / (hd1_heads * hd1_secpertrk);
\r
664 j = dLBA % (hd1_heads * hd1_secpertrk); /* remainder */
\r
666 /* We now know what cylinder. Calculate head and sector */
\r
668 hd_head = j / hd1_secpertrk;
\r
669 hd_sector = j % hd1_secpertrk + 1; /* sector number start at 1 !!! */
\r
672 hd_Cmd[2] = nBlks; /* How many sectors */
\r
673 hd_Cmd[3] = hd_sector; /* Which sector to start on */
\r
674 hd_Cmd[4] = cyl & 0xff; /* cylinder lobyte */
\r
675 hd_Cmd[5] = (cyl >> 8) & 0xff; /* cylinder hibyte */
\r
676 hd_Cmd[6] = (hd_drive << 4) | (hd_head & 0x0f) | 0xa0;
\r
682 /*******************************************************
\r
683 Move the head to the selected track (cylinder).
\r
684 *********************************************************/
\r
686 static U32 hd_seek(U32 dLBA)
\r
690 erc = setupseek(dLBA, 1); /* sets up for implied seek */
\r
691 if (!erc) erc = send_command(HDC_SEEK); /* Not implied anymore... */
\r
692 if (!erc) erc = hd_wait(); /* wait for interrupt */
\r
693 if (!erc) erc = hd_status(HDC_SEEK);
\r
694 hdstatus.LastSeekErc0 = erc;
\r
699 /*******************************************************
\r
700 Called to read status and errors from the controller
\r
701 after an interrupt generated by a command we sent.
\r
702 The error checking is based on the command that we sent.
\r
703 This is done because certain bits in the status and error
\r
704 registers are actually not errors, but simply indicate
\r
705 status or indicate an action we must take next.
\r
706 ZERO returned indicates no errors for the command status
\r
708 *********************************************************/
\r
710 static U32 hd_status(U8 LastCmd)
\r
713 U8 statbyte, errbyte;
\r
715 /* We shouldn't see the controller busy. After all,
\r
716 he interrupted us with status.
\r
719 erc = check_busy(); /* puts status byte into global StatByte */
\r
721 statbyte = InByte(HD_PORT+7);
\r
725 hdstatus.LastStatByte1 = statbyte;
\r
727 hdstatus.LastStatByte0 = statbyte;
\r
729 if ((statbyte & ERROR) == 0)
\r
730 { /* Error bit not set in status reg */
\r
731 erc = ok; /* default */
\r
736 case HDC_READ_LONG:
\r
738 case HDC_WRITE_LONG:
\r
741 if (statbyte & WRITE_FAULT) erc = ErcWriteFault;
\r
743 if ((statbyte & SEEKOK) == 0) erc = ErcBadSeek;
\r
745 case HDC_SET_PARAMS:
\r
757 erc = check_busy();
\r
759 errbyte = InByte(HD_PORT+1);
\r
763 hdstatus.LastErcByte1 = errbyte;
\r
765 hdstatus.LastErcByte0 = errbyte;
\r
767 if (errbyte & BAD_ADDRESS) erc = ErcAddrMark;
\r
768 else if (errbyte & BAD_SEEK) erc = ErcBadSeek;
\r
769 else if (errbyte & BAD_CMD) erc = ErcBadCmd;
\r
770 else if (errbyte & BAD_IDMARK) erc = ErcSectNotFound;
\r
771 else if (errbyte & BAD_ECC) erc = ErcBadECC;
\r
772 else if (errbyte & BAD_SECTOR) erc = ErcBadBlock;
\r
773 else erc = ErcBadHDC; /* no error bits found but should have been! */
\r
778 /*************************************************************
\r
779 This is called for the DeviceOp code Read.
\r
780 This reads 1 or more whole sectors from the calculated values
\r
781 in hd_head, hd_sector, and hd_cyl
\r
782 *************************************************************/
\r
784 static U32 hd_read(U32 dLBA, U32 dnBlocks, U8 *pDataRet)
\r
786 U32 erc, nleft, nBPS;
\r
788 nBPS = hdcb[hd_drive].nBPB; /* From nBytesPerBlock in DCB */
\r
790 erc = setupseek(dLBA, dnBlocks); /* sets up for implied seek */
\r
791 if (!erc) erc = send_command(HDC_READ);
\r
793 while ((nleft) && (!erc))
\r
795 erc = hd_wait(); /* wait for interrupt */
\r
797 erc = hd_status(HDC_READ);
\r
798 if (!erc) /* && (statbyte & DATA_REQ)) */
\r
800 InWords(HD_PORT, pDataRet, nBPS);
\r
808 /*************************************************************
\r
809 This is called for the DeviceOp code Write.
\r
810 This writes 1 or more whole sectors from the calculated values
\r
811 in hd_head, hd_sector, and hd_cyl
\r
812 *************************************************************/
\r
814 static U32 hd_write(U32 dLBA, U32 dnBlocks, U8 *pDataOut)
\r
816 U32 erc, nSoFar, nBPS;
\r
818 nBPS = hdcb[hd_drive].nBPB; /* From n BytesPerBlock in DCB */
\r
820 erc = setupseek(dLBA, dnBlocks); /* sets up for implied seek */
\r
821 erc = send_command(HDC_WRITE);
\r
822 erc = check_busy(); /* No INT occurs for first sector of write */
\r
824 if ((!erc) && (statbyte & DATA_REQ))
\r
826 OutWords(HD_PORT, pDataOut, nBPS);
\r
831 while ((nSoFar < dnBlocks ) && (erc==ok))
\r
833 erc = hd_wait(); /* wait for interrupt */
\r
834 if (erc==ok) erc = hd_status(HDC_WRITE);
\r
835 if ((erc==ok) && (statbyte & DATA_REQ))
\r
837 OutWords(HD_PORT, pDataOut, nBPS);
\r
842 if (!erc) erc = hd_wait(); /* wait for final interrupt */
\r
843 if (!erc) erc = hd_status(HDC_WRITE);
\r
849 /*************************************************************
\r
850 This formats the track beginning at the block address given
\r
851 in dLBA. dLBA must always be a multiple of the number of
\r
852 sectors per track minus 1 for the disk type.
\r
853 *************************************************************/
\r
855 static U32 hd_format_track(U32 dLBA, U32 dnBlocks)
\r
858 erc = setupseek(dLBA, dnBlocks); /* sets up for implied seek */
\r
859 erc = send_command(HDC_FORMAT);
\r
860 erc = hd_wait(); /* wait for interrupt */
\r
862 erc = hd_status(HDC_FORMAT);
\r
866 /******************************************************************
\r
867 ReadSector is the only device specific call in the IDE/MFM hard
\r
868 disk device driver. This allows you to read ONE sector
\r
869 specified by Cylinder, head and Sector number.
\r
870 Cylinder is LoWord of dLBA in DeviceOp call,
\r
871 Head is LoWord of dnBlocks in DeviceOp call, and
\r
872 Sector number is HiWord in dnBlocks.
\r
873 *******************************************************************/
\r
875 static U32 ReadSector(U32 Cylinder, U32 HdSect, U8 *pDataRet)
\r
881 hd_head = HdSect & 0xffff;
\r
882 hd_sector = (HdSect >> 16) & 0xffff;
\r
885 xprintf("\r\nCYL %d, HD %d, SEC %d\r\n", cyl, hd_head, hd_sector);
\r
888 hd_Cmd[2] = 1; /* How many sectors */
\r
889 hd_Cmd[3] = hd_sector; /* Which sector to start on */
\r
890 hd_Cmd[4] = cyl & 0xff; /* cylinder lobyte */
\r
891 hd_Cmd[5] = (cyl >> 8) & 0xff; /* cylinder hibyte */
\r
892 hd_Cmd[6] = (hd_drive << 4) | (hd_head & 0x0f) | 0xa0;
\r
894 erc = send_command(HDC_READ);
\r
895 erc = hd_wait(); /* wait for interrupt */
\r
896 if (!erc) erc = hd_status(HDC_READ);
\r
898 InWords(HD_PORT, pDataRet, 512);
\r
902 /***************************************************************************
\r
903 Now begins the PUBLIC routines that are used for all DEVICE DRIVERS
\r
906 /******************************************
\r
907 Called for all device operations. This
\r
908 assigns physical device from logical number
\r
909 that outside callers use. For Hard disk,
\r
910 12=0 and 13=1. This will check to make sure a
\r
911 drive type is assigned and check to see if
\r
912 they are going to exceed max logical blocks.
\r
913 *******************************************/
\r
915 static U32 hddev_op(U32 dDevice,
\r
923 hdstatus.blocks_done = 0; /* Reset values in Status record */
\r
927 /* Set drive internal drive number */
\r
934 /* Check to see if we have a leftover interrupt message from last
\r
935 command. If so then we eat it (and do nothing) */
\r
937 CheckMsg(hd_exch, &hd_msg); /* Ignore error */
\r
942 erc = ErcInvalidDrive;
\r
947 erc = ErcInvalidDrive;
\r
950 /* make sure they don't exceed max blocks */
\r
953 if (dLBA > hdcb[hd_drive].nBlocks) erc = ErcBadLBA;
\r
961 erc = ok; /* Null Command */
\r
963 case(CmdRead): /* Read */
\r
964 erc = hd_read(dLBA, dnBlocks, pData);
\r
966 case(CmdWrite): /* Write */
\r
967 erc = hd_write(dLBA, dnBlocks, pData);
\r
969 case(CmdVerify): /* Verify */
\r
970 erc = ErcNotSupported;
\r
972 /* hd_verify is not supported in this version of the driver */
\r
973 /* erc = hd_verify(dLBA, dnBlocks, pData); */
\r
975 case(CmdSeekTrk): /* Seek Track */
\r
976 erc = hd_seek(dLBA);
\r
978 case(CmdFmtTrk): /* Format Track */
\r
979 erc = hd_format_track(dLBA, dnBlocks);
\r
981 case(CmdResetHdw): /* Reset Ctrlr */
\r
985 case(CmdReadSect): /* Read Sector(s) */
\r
986 erc = ReadSector(dLBA, dnBlocks, pData);
\r
993 hdcb[hd_drive].last_erc = erc; /* update DCB erc */
\r
997 /******************************************
\r
998 Called for indepth status report on ctrlr
\r
999 and drive specified. Returns 64 byte block
\r
1000 of data including current drive geometery.
\r
1001 This is called by the PUBLIC call DeviceStat!
\r
1002 *******************************************/
\r
1004 static U32 hddev_stat(U32 dDevice,
\r
1011 /* Set status for proper device */
\r
1013 if (dDevice == 12)
\r
1015 hdstatus.erc = hdcb[0].last_erc;
\r
1016 hdstatus.type_now = hd0_type;
\r
1017 hdstatus.nCyl = hd0_cyls;
\r
1018 hdstatus.nHead = hd0_heads;
\r
1019 hdstatus.nSectors = hd0_secpertrk;
\r
1020 hdstatus.nBPS = hdcb[0].nBPB;
\r
1024 hdstatus.erc = hdcb[1].last_erc;
\r
1025 hdstatus.type_now = hd1_type;
\r
1026 hdstatus.nCyl = hd1_cyls;
\r
1027 hdstatus.nHead = hd1_heads;
\r
1028 hdstatus.nSectors = hd1_secpertrk;
\r
1029 hdstatus.nBPS = hdcb[1].nBPB;
\r
1032 /* Calculate size of status to return. Return no more than asked for! */
\r
1034 if (dStatusMax <= sStatus) i = dStatusMax;
\r
1037 CopyData(&hdstatus, pStatRet, i); /* copy to their status block */
\r
1039 *pdStatusRet = i; /* tell em how much it was */
\r
1044 /******************************************
\r
1045 Called to reset the hard disk controller
\r
1046 and set drive parameters. The Initdata
\r
1047 is a copy of the 64 byte status block
\r
1048 that is read from status. The caller
\r
1049 normally reads the block (DeviceStat),
\r
1050 makes changes to certain fields and
\r
1051 calls DeviceInit pointing to the block
\r
1052 for the changes to take effect.
\r
1053 This should ONLY be called once for each HD
\r
1054 to set it's parameters before it is used
\r
1055 the first time after the driver is loaded,
\r
1056 or after a fatal error is received that
\r
1057 indicates the controller may need to be
\r
1058 reset (multiple timeouts etc.).
\r
1059 The DCB values are updated if this is
\r
1061 This is called by the PUBLIC call DeviceInit.
\r
1062 *******************************************/
\r
1064 static U32 hddev_init(U32 dDevice,
\r
1073 /* Read the init status block in */
\r
1075 if (sdInitData > sStatus) i = sStatus; /* no more than 64 bytes! */
\r
1076 else i = sdInitData;
\r
1078 CopyData(pInitData, &HDStatTmp, i); /* copy in their init data */
\r
1080 /* Set internal drive number */
\r
1081 if (dDevice == 12) hd_drive=0;
\r
1082 else hd_drive = 1;
\r
1086 hd0_type = HDStatTmp.type_now;
\r
1089 hd0_cyls = HDStatTmp.nCyl;
\r
1090 hd0_heads = HDStatTmp.nHead;
\r
1091 hd0_secpertrk = HDStatTmp.nSectors;
\r
1093 else erc = ErcInvalidDrive;
\r
1097 hd1_type = HDStatTmp.type_now;
\r
1100 hd1_cyls = HDStatTmp.nCyl;
\r
1101 hd1_heads = HDStatTmp.nHead;
\r
1102 hd1_secpertrk = HDStatTmp.nSectors;
\r
1104 else erc = ErcInvalidDrive;
\r
1107 /* If no error, initialize it and recal */
\r
1109 if (!erc) erc = hd_init(hd_drive);
\r
1110 if (!erc) erc = hd_recal(hd_drive);
\r
1112 /* If no error, update corresponding DCB values */
\r
1116 hdcb[hd_drive].nBPB = HDStatTmp.nBPS;
\r
1117 hdcb[hd_drive].last_erc = 0;
\r
1118 hdcb[hd_drive].nBlocks =
\r
1119 HDStatTmp.nCyl * HDStatTmp.nSectors * HDStatTmp.nHead;
\r
1122 hdcb[hd_drive].last_erc = erc; /* update DCB erc */
\r
1127 /*=========== THE END =========================================*/
\r