|
|
1.1 root 1: /*
2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7: * Reserved. This file contains Original Code and/or Modifications of
8: * Original Code as defined in and that are subject to the Apple Public
9: * Source License Version 1.1 (the "License"). You may not use this file
10: * except in compliance with the License. Please obtain a copy of the
11: * License at http://www.apple.com/publicsource and read it before using
12: * this file.
13: *
14: * The Original Code and all software distributed under the License are
15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19: * License for the specific language governing rights and limitations
20: * under the License.
21: *
22: * @APPLE_LICENSE_HEADER_END@
23: */
24:
25: // Copyright 1997 by Apple Computer, Inc., all rights reserved.
26: /*
27: * Copyright (c) 1994-1997 NeXT Software, Inc. All rights reserved.
28: *
29: * IdeCntCmds.m - Implementation of Commands category for IDE Controller
30: * device.
31: *
32: * It contains implementation of the ATA command set.
33: *
34: *
35: * HISTORY
36: *
37: * 1-Aug-1995 Rakesh Dubey at NeXT
38: * Reduced the timeout in IDE_IDENTIFY_DRIVE method.
39: *
40: * 17-July-1994 Rakesh Dubey at NeXT
41: * Created.
42: */
43:
44: #import "IdeCnt.h"
45: #import "IdeCntInit.h"
46: #import "IdeCntDma.h"
47: #import <kern/assert.h>
48: #import <driverkit/kernelDriver.h>
49: #import <driverkit/interruptMsg.h>
50: #import <mach/mach_interface.h>
51: #import <driverkit/IODevice.h>
52: #import <driverkit/align.h>
53: #import <machkit/NXLock.h>
54: #import "io_inline.h"
55: #import "IdeDDM.h"
56:
57: /*
58: * All methods in this file implement one or more of the IDE commands. These
59: * commands get invoked by IdeDisk objects.
60: */
61:
62: @implementation IdeController(Commands)
63:
64: /*
65: * Returns a struct containing IDE registers values for a given sector
66: * address and size. Depending upon whether the drive supports LBA or CHS we
67: * fill in different values. The calling routine must make sure that these
68: * values are not overwritten. The only thing that they need to fill in is
69: * the drive number.
70: */
71: - (ideRegsVal_t)logToPhys:(unsigned)block numOfBlocks:(unsigned)nblk
72: {
73: ideRegsVal_t rv;
74: unsigned int cyl, nheads;
75: unsigned int track, spt;
76:
77: if (_addressMode[_driveNum] == ADDRESS_MODE_CHS)
78: {
79: nheads = _ideInfo[_driveNum].heads;
80: spt = _ideInfo[_driveNum].sectors_per_trk;
81:
82: track = (block / spt);
83: cyl = track / nheads;
84: rv.sectNum = block % spt + 1;
85:
86: rv.drHead = track % nheads;
87: rv.cylLow = (cyl & 0xff);
88: rv.cylHigh = ((cyl & 0xff00) >> 8);
89: }
90: else
91: {
92: rv.sectNum = block & 0x0ff;
93: rv.cylLow = (block >> 8) & 0xff;
94: rv.cylHigh = (block >> 16) & 0xff;
95: rv.drHead = (block >> 24) & 0x0f;
96: }
97:
98: rv.sectCnt = (unsigned char)nblk;
99:
100: rv.drHead |= _addressMode[_driveNum];
101: rv.drHead |= (_driveNum ? SEL_DRIVE1 : SEL_DRIVE0);
102:
103: return rv;
104: }
105:
106: /*
107: * Commands to the IDE controller.
108: */
109:
110:
111: - (ide_return_t)ideDiagnose:(unsigned *)diagError
112: {
113: ide_return_t rtn;
114: unsigned char status;
115:
116: rtn = [self waitForDeviceReady];
117: if (rtn != IDER_SUCCESS)
118: return IDER_CMD_ERROR;
119:
120: [self enableInterrupts];
121: outb(_ideRegsAddrs.command, IDE_DIAGNOSE);
122:
123: rtn = [self ideWaitForInterrupt:IDE_DIAGNOSE ideStatus:&status];
124: if (rtn != IDER_SUCCESS)
125: {
126: [self getIdeRegisters:NULL Print:"Diagnose"];
127: return IDER_CMD_ERROR;
128: }
129:
130: rtn = [self waitForDeviceReady];
131: if (rtn != IDER_SUCCESS)
132: return IDER_CMD_ERROR;
133:
134: *diagError = inb(_ideRegsAddrs.error);
135:
136: if (*diagError == 0x01)
137: {
138: /* FIXME: do we need to soft reset ATAPI devices? */
139: return IDER_SUCCESS;
140: }
141:
142: /*
143: * At least one of the drives is bad.
144: */
145: if (*diagError & 0x080)
146: {
147: IOLog("%s: Drive 1 has failed diagnostics.\n", [self name]);
148: _ideInfo[1].type = 0;
149:
150: if ((*diagError & 0x07f) != 1)
151: {
152: IOLog("%s: Drive 0 has failed diagnostics, error %d\n",
153: [self name], (*diagError & 0x07f));
154: return IDER_CMD_ERROR;
155: }
156: }
157: else
158: {
159: _ideInfo[0].type = 0;
160: IOLog("%s: Drive 0 has failed diagnostics, error %d\n",
161: [self name], (*diagError & 0x07f));
162: }
163:
164: return IDER_CMD_ERROR;
165: }
166:
167: - (ide_return_t)ideSetParams:(unsigned)sectCnt numHeads:(unsigned)nHeads
168: ForDrive:(unsigned)drive
169: {
170: unsigned char dh = _addressMode[drive];
171: ide_return_t rtn;
172:
173: rtn = [self waitForDeviceReady];
174: if (rtn != IDER_SUCCESS)
175: return rtn;
176:
177: dh |= ((drive ? SEL_DRIVE1 : SEL_DRIVE0) | ((nHeads - 1) & 0x0f));
178: outb(_ideRegsAddrs.drHead, dh);
179: outb(_ideRegsAddrs.sectCnt, (sectCnt & 0xff));
180:
181: [self enableInterrupts];
182: outb(_ideRegsAddrs.command, IDE_SET_PARAMS);
183:
184: rtn = [self ideWaitForInterrupt:IDE_SET_PARAMS ideStatus:NULL];
185: if (rtn != IDER_SUCCESS)
186: {
187: [self getIdeRegisters:NULL Print:"SetParams"];
188: return rtn;
189: }
190:
191: return rtn;
192: }
193:
194: - (ide_return_t)ideSetDriveFeature:(unsigned)feature value:(unsigned)val
195: {
196: unsigned char dh = _addressMode[_driveNum];
197: unsigned char status;
198: ide_return_t rtn;
199:
200: rtn = [self waitForDeviceReady];
201: if (rtn != IDER_SUCCESS)
202: return rtn;
203:
204: dh |= (_driveNum ? SEL_DRIVE1 : SEL_DRIVE0);
205: outb(_ideRegsAddrs.drHead, dh);
206: outb(_ideRegsAddrs.sectCnt, (val & 0xff));
207:
208: outb(_ideRegsAddrs.features, feature);
209:
210: [self enableInterrupts];
211: outb(_ideRegsAddrs.command, IDE_SET_FEATURES);
212:
213: rtn = [self ideWaitForInterrupt:IDE_SET_FEATURES ideStatus:&status];
214: if (rtn != IDER_SUCCESS)
215: {
216: [self getIdeRegisters:NULL Print:"SetFeatures"];
217: return rtn;
218: }
219:
220: if (status & ERROR)
221: return IDER_ERROR;
222:
223: return rtn;
224: }
225:
226: - (ide_return_t)ideRestore:(ideRegsVal_t *)ideRegs
227: {
228: ide_return_t rtn;
229: unsigned char status;
230: unsigned char dh = _addressMode[_driveNum];
231:
232: rtn = [self waitForDeviceReady];
233: if (rtn != IDER_SUCCESS)
234: {
235: return rtn;
236: }
237:
238: dh |= (_driveNum ? SEL_DRIVE1 : SEL_DRIVE0);
239: outb(_ideRegsAddrs.drHead, dh);
240:
241: [self enableInterrupts];
242: outb(_ideRegsAddrs.command, IDE_RESTORE);
243:
244: rtn = [self ideWaitForInterrupt:IDE_RESTORE ideStatus: &status];
245: if (rtn != IDER_SUCCESS)
246: {
247: [self getIdeRegisters:NULL Print:"Restore"];
248: return rtn;
249: }
250:
251: rtn = [self waitForDeviceReady];
252: if (rtn == IDER_SUCCESS)
253: {
254: if (status & ERROR)
255: {
256: [self getIdeRegisters:ideRegs Print:"Restore"];
257: rtn = IDER_CMD_ERROR;
258: }
259: }
260:
261: return (rtn);
262: }
263:
264: - (ide_return_t)ideReadGetInfoCommon:(ideRegsVal_t *)ideRegs
265: client:(struct vm_map *)client
266: addr:(caddr_t)xferAddr
267: command:(unsigned int)cmd
268: {
269: ide_return_t rtn;
270: unsigned int sec_cnt = ideRegs->sectCnt;
271: int i;
272: unsigned char *taddr;
273: unsigned char status;
274: unsigned char dh = _addressMode[_driveNum];
275:
276: if (sec_cnt == 0)
277: sec_cnt = MAX_BLOCKS_PER_XFER;
278:
279: taddr = xferAddr;
280:
281: /*
282: * We have to define this for the IDE_IDENTIFY_DRIVE command.
283: */
284: if (cmd == IDE_IDENTIFY_DRIVE)
285: {
286: ideRegs->sectCnt = 1;
287: sec_cnt = 1;
288: }
289:
290: /*
291: * Select the drive first. This routine is invoked by the initialization
292: * code as well (-resetAndInit) so it is necessary to do this here.
293: */
294: dh |= (_driveNum ? SEL_DRIVE1 : SEL_DRIVE0);
295: outb(_ideRegsAddrs.drHead, dh);
296:
297:
298: rtn = [self waitForDeviceReady];
299: if (rtn != IDER_SUCCESS)
300: {
301: return (rtn);
302: }
303:
304: if (cmd == IDE_READ)
305: {
306: outb(_ideRegsAddrs.drHead, ideRegs->drHead);
307: outb(_ideRegsAddrs.sectNum, ideRegs->sectNum);
308: outb(_ideRegsAddrs.sectCnt, ideRegs->sectCnt);
309: outb(_ideRegsAddrs.cylLow, ideRegs->cylLow);
310: outb(_ideRegsAddrs.cylHigh, ideRegs->cylHigh);
311: }
312: else
313: {
314: /* probably unnecessary */
315: outb(_ideRegsAddrs.drHead, dh);
316: outb(_ideRegsAddrs.sectCnt, ideRegs->sectCnt);
317: }
318:
319: [self enableInterrupts];
320: outb(_ideRegsAddrs.command, cmd);
321:
322: for (i = 0; i < sec_cnt; i++)
323: {
324: rtn = [self ideWaitForInterrupt:cmd ideStatus:&status];
325: if (rtn != IDER_SUCCESS)
326: {
327: return rtn;
328: }
329: else
330: {
331: /*
332: if (status & ERROR_CORRECTED) {
333: IOLog("%s: Corrected error during read.\n", [self name]);
334: }
335: */
336: }
337:
338: /*
339: * Same as waitForDataReady but with a quick timeout.
340: */
341: rtn = [self ataIdeReadGetInfoCommonWaitForDataReady];
342: if (rtn != IDER_SUCCESS)
343: {
344: return (rtn);
345: }
346:
347: [self xferData:taddr read:YES client:client length:IDE_SECTOR_SIZE];
348: taddr += IDE_SECTOR_SIZE;
349: }
350:
351: return rtn;
352: }
353:
354: - (ide_return_t)ideWrite:(ideRegsVal_t *)ideRegs
355: client:(struct vm_map *)client
356: addr:(caddr_t)xferAddr
357: {
358: ide_return_t rtn;
359: unsigned int sec_cnt = ideRegs->sectCnt;
360: int i;
361: unsigned char *taddr;
362: unsigned char status;
363:
364: if (sec_cnt == 0)
365: sec_cnt = MAX_BLOCKS_PER_XFER;
366:
367: taddr = xferAddr;
368:
369: rtn = [self waitForDeviceReady];
370: if (rtn != IDER_SUCCESS)
371: {
372: return (rtn);
373: }
374:
375: outb(_ideRegsAddrs.drHead, ideRegs->drHead);
376: outb(_ideRegsAddrs.sectNum, ideRegs->sectNum);
377: outb(_ideRegsAddrs.sectCnt, ideRegs->sectCnt);
378: outb(_ideRegsAddrs.cylLow, ideRegs->cylLow);
379: outb(_ideRegsAddrs.cylHigh, ideRegs->cylHigh);
380:
381: [self enableInterrupts];
382: outb(_ideRegsAddrs.command, IDE_WRITE);
383:
384: for (i = 0; i < sec_cnt; i++)
385: {
386: rtn = [self waitForDataReady];
387: if (rtn != IDER_SUCCESS)
388: {
389: return (rtn);
390: }
391:
392: [self xferData:taddr read:NO client:client length:IDE_SECTOR_SIZE];
393: taddr += IDE_SECTOR_SIZE;
394:
395: rtn = [self ideWaitForInterrupt:IDE_WRITE ideStatus:&status];
396:
397: if (rtn != IDER_SUCCESS)
398: {
399: [self getIdeRegisters:ideRegs Print:"Write"];
400: return (rtn);
401: }
402: else
403: {
404: /*
405: if (status & ERROR_CORRECTED) {
406: IOLog("%s: Corrected error during write.\n", [self name]);
407: }
408: */
409: }
410: }
411:
412: return (rtn);
413: }
414:
415: - (ide_return_t)ideReadVerifySeekCommon:(ideRegsVal_t *)ideRegs
416: command:(unsigned int)cmd
417: {
418: ide_return_t rtn;
419: unsigned char status;
420:
421: rtn = [self waitForDeviceReady];
422: if (rtn != IDER_SUCCESS)
423: {
424: return (rtn);
425: }
426:
427: outb(_ideRegsAddrs.drHead, ideRegs->drHead);
428: outb(_ideRegsAddrs.sectNum, ideRegs->sectNum);
429: if (cmd == IDE_READ_VERIFY)
430: outb(_ideRegsAddrs.sectCnt, ideRegs->sectCnt);
431: outb(_ideRegsAddrs.cylLow, ideRegs->cylLow);
432: outb(_ideRegsAddrs.cylHigh, ideRegs->cylHigh);
433:
434: [self enableInterrupts];
435: outb(_ideRegsAddrs.command, cmd);
436:
437: rtn = [self ideWaitForInterrupt:cmd ideStatus: &status];
438: if (rtn != IDER_SUCCESS)
439: {
440: [self getIdeRegisters:NULL Print:"ReadVerify/Seek"];
441: return (rtn);
442: }
443:
444: if (status & (ERROR | WRITE_FAULT))
445: {
446: rtn = IDER_CMD_ERROR;
447: }
448: else
449: {
450: if ((cmd == IDE_SEEK) && (!(status & SEEK_COMPLETE)))
451: rtn = IDER_CMD_ERROR;
452: }
453:
454: return (rtn);
455: }
456:
457: - (ide_return_t)ideSetMultiSectorMode:(ideRegsVal_t *)ideRegs
458: numSectors:(unsigned char)nSectors
459: {
460: ide_return_t rtn;
461: unsigned char status;
462: unsigned char dh = _addressMode[_driveNum];
463:
464: rtn = [self waitForDeviceReady];
465: if (rtn != IDER_SUCCESS)
466: {
467: return (rtn);
468: }
469:
470: dh |= (_driveNum ? SEL_DRIVE1 : SEL_DRIVE0);
471: outb(_ideRegsAddrs.drHead, dh);
472: outb(_ideRegsAddrs.sectCnt, nSectors);
473:
474: [self enableInterrupts];
475: outb(_ideRegsAddrs.command, IDE_SET_MULTIPLE);
476:
477: rtn = [self ideWaitForInterrupt:IDE_SET_MULTIPLE ideStatus:&status];
478: if (rtn != IDER_SUCCESS)
479: {
480: return (rtn);
481: }
482:
483: rtn = [self waitForDeviceReady];
484: if (rtn == IDER_SUCCESS)
485: {
486: if (status & ERROR)
487: {
488: rtn = IDER_CMD_ERROR;
489: [self getIdeRegisters:ideRegs Print:NULL];
490: }
491: else
492: rtn = IDER_SUCCESS;
493: }
494:
495: return (rtn);
496: }
497:
498: /*
499: * Note: Never read the status register at the end of data transfer, you may
500: * clobber the next interrupt from the drive. If it is necessary to get
501: * status use the alternate status register.
502: */
503: - (ide_return_t)ideReadMultiple:(ideRegsVal_t *)ideRegs
504: client:(struct vm_map *)client
505: addr:(caddr_t)xferAddr
506: {
507: ide_return_t rtn;
508: unsigned char status;
509: unsigned sec_cnt = ideRegs->sectCnt;
510: unsigned int nSectors;
511: unsigned char *taddr;
512: unsigned int length;
513:
514: if (sec_cnt == 0)
515: sec_cnt = MAX_BLOCKS_PER_XFER;
516:
517: taddr = xferAddr;
518:
519: rtn = [self waitForDeviceReady];
520: if (rtn != IDER_SUCCESS)
521: {
522: return (rtn);
523: }
524:
525: outb(_ideRegsAddrs.drHead, ideRegs->drHead);
526: outb(_ideRegsAddrs.sectNum, ideRegs->sectNum);
527: outb(_ideRegsAddrs.sectCnt, ideRegs->sectCnt);
528: outb(_ideRegsAddrs.cylLow, ideRegs->cylLow);
529: outb(_ideRegsAddrs.cylHigh, ideRegs->cylHigh);
530:
531: [self enableInterrupts];
532: outb(_ideRegsAddrs.command, IDE_READ_MULTIPLE);
533:
534: while (sec_cnt > 0)
535: {
536: rtn = [self ideWaitForInterrupt:IDE_READ_MULTIPLE
537: ideStatus: &status];
538:
539: if (rtn != IDER_SUCCESS)
540: {
541: [self getIdeRegisters:ideRegs Print:"Read Multiple"];
542: return (rtn);
543: }
544:
545: #if 1
546: rtn = [self waitForDataReady];
547: if (rtn != IDER_SUCCESS)
548: {
549: return (rtn);
550: }
551: #endif
552:
553: if (status & (ERROR | WRITE_FAULT))
554: {
555: [self getIdeRegisters:ideRegs Print:"Read Multiple"];
556: return IDER_CMD_ERROR;
557: }
558:
559: /*
560: * Any drive formatted with 63 sector/track (which most over 400 MB
561: * are) reporting this status (ERROR_CORRECTED) will cause an
562: * fallacious error (possibly uncorrectable) due to a long-standing
563: * bug in DOS. This status bit should be made vendor specific, like
564: * IDX. It has outlived its usefulness.
565: * -- [email protected]
566: */
567:
568: /*
569: if (status & ERROR_CORRECTED)
570: {
571: IOLog("%s: Corrected error during read.\n", [self name]);
572: }
573: */
574:
575: /*
576: * All is well. Read in the data.
577: */
578: if (sec_cnt > _multiSector[_driveNum])
579: nSectors = _multiSector[_driveNum];
580: else
581: nSectors = sec_cnt;
582:
583: sec_cnt -= nSectors;
584:
585: while (nSectors)
586: {
587: if (nSectors > PAGE_SIZE / IDE_SECTOR_SIZE)
588: {
589: length = PAGE_SIZE;
590: nSectors -= (PAGE_SIZE / IDE_SECTOR_SIZE);
591: }
592: else
593: {
594: length = nSectors * IDE_SECTOR_SIZE;
595: nSectors = 0;
596: }
597:
598: [self xferData:taddr read:YES client:client length:length];
599: taddr += length;
600: }
601: }
602:
603: return (rtn);
604: }
605:
606: - (ide_return_t)ideWriteMultiple:(ideRegsVal_t *)ideRegs
607: client:(struct vm_map *)client
608: addr:(caddr_t)xferAddr
609: {
610: ide_return_t rtn;
611: unsigned char status;
612: unsigned sec_cnt = ideRegs->sectCnt;
613: unsigned int nSectors;
614: unsigned char *taddr;
615: unsigned int length;
616:
617: if (sec_cnt == 0)
618: sec_cnt = MAX_BLOCKS_PER_XFER;
619:
620: taddr = xferAddr;
621:
622: rtn = [self waitForDeviceReady];
623: if (rtn != IDER_SUCCESS)
624: {
625: return (rtn);
626: }
627:
628: outb(_ideRegsAddrs.drHead, ideRegs->drHead);
629: outb(_ideRegsAddrs.sectNum, ideRegs->sectNum);
630: outb(_ideRegsAddrs.sectCnt, ideRegs->sectCnt);
631: outb(_ideRegsAddrs.cylLow, ideRegs->cylLow);
632: outb(_ideRegsAddrs.cylHigh, ideRegs->cylHigh);
633:
634: [self enableInterrupts];
635: outb(_ideRegsAddrs.command, IDE_WRITE_MULTIPLE);
636:
637: while (sec_cnt > 0)
638: {
639:
640: rtn = [self waitForDataReady];
641: if (rtn != IDER_SUCCESS)
642: {
643: return (rtn);
644: }
645:
646: if (sec_cnt > _multiSector[_driveNum])
647: nSectors = _multiSector[_driveNum];
648: else
649: nSectors = sec_cnt;
650:
651: sec_cnt -= nSectors;
652:
653: while (nSectors)
654: {
655: if (nSectors > PAGE_SIZE / IDE_SECTOR_SIZE)
656: {
657: length = PAGE_SIZE;
658: nSectors -= (PAGE_SIZE / IDE_SECTOR_SIZE);
659: }
660: else
661: {
662: length = nSectors * IDE_SECTOR_SIZE;
663: nSectors = 0;
664: }
665:
666: [self xferData:taddr read:NO client:client length:length];
667: taddr += length;
668: }
669: rtn = [self ideWaitForInterrupt:IDE_WRITE_MULTIPLE
670: ideStatus:&status];
671:
672: if (rtn != IDER_SUCCESS)
673: {
674: [self getIdeRegisters:ideRegs Print:"Write Multiple"];
675: return (rtn);
676: }
677:
678: if (status & (ERROR | WRITE_FAULT))
679: {
680: [self getIdeRegisters:ideRegs Print:"Write Multiple"];
681: return IDER_CMD_ERROR;
682: }
683:
684: /*
685: if (status & ERROR_CORRECTED)
686: {
687: IOLog("%s: Corrected error during write.\n", [self name]);
688: }
689: */
690:
691: }
692:
693: return (rtn);
694: }
695:
696: /*
697: * All I/O to to controller object is done through this method. We first
698: * acquire a lock before executing any IDE commands since the IDE controller
699: * can do only one thing at a time (both drivers can not be active
700: * simultaneously except for reset and disgnostics).
701: *
702: * If it necessary to call any of the IDE command methods (which are invoked by
703: * the switch() below, like ideReadGetInfoCommon:client:addr:command) it is
704: * necessary to acquire the lock. The IDE command methods should not be
705: * invoked directly by the Disk object.
706: *
707: * This method will in turn call one of several methods which deal with
708: * hardware.
709: */
710:
711:
712: #define MAX_COMMAND_RETRY 3
713:
714: - (IOReturn) _ideExecuteCmd:(ideIoReq_t *)ideIoReq ToDrive:(unsigned char)drive
715: {
716: int retry;
717: ideRegsVal_t irv;
718: unsigned block, cnt;
719: unsigned error;
720: unsigned int maxSectors;
721: unsigned char dh;
722:
723: /*
724: * If the controller wishes to put the drive to sleep, it sets this flag
725: * to YES and tries to acquire the lock. This method should not try to
726: * get the lock (and execute any more commands) if the flag is set. This
727: * is needed in order to enter sleep mode as soon as the current command
728: * is finished. If we do not do this there is contention for lock between
729: * the controller (which wants to put the drive to sleep) and this method
730: * (which wants to service more requests). Note that this does not do
731: * away with the need for a lock, it only gives the controller a little
732: * head-start.
733: */
734:
735: while (_driveSleepRequest)
736: {
737: IOSleep(100);
738: }
739:
740: [self ideCntrlrLock];
741:
742: _driveNum = drive; /* used by IDE command methods. */
743:
744: /*
745: * Select the drive first. We don't know the head number at this time so
746: * this register will be rewritten by the specific routine later.
747: */
748: dh = _addressMode[_driveNum];
749: dh |= (_driveNum ? SEL_DRIVE1 : SEL_DRIVE0);
750: outb(_ideRegsAddrs.drHead, dh);
751:
752: /*
753: * Check if we need to do a media access to get the drive respinning
754: * after a suspend operation.
755: */
756: if ([self drivePowerState] != IDE_PM_ACTIVE)
757: {
758: (void)[self startUpAttachedDevices];
759: }
760:
761: ideIoReq->status = IDER_CMD_ERROR;
762: ideIoReq->blocks_xfered = 0;
763:
764: for (retry = 0; retry < MAX_COMMAND_RETRY; retry++)
765: {
766: [self clearInterrupts];
767:
768: switch (ideIoReq->cmd)
769: {
770: case IDE_READ:
771: case IDE_READ_MULTIPLE:
772:
773: block = ideIoReq->block;
774: cnt = ideIoReq->blkcnt;
775: if ((cnt > MAX_BLOCKS_PER_XFER) || (cnt > (IDE_MAX_PHYS_IO/IDE_SECTOR_SIZE)))
776: {
777: ideIoReq->status = IDER_REJECT;
778: break;
779: }
780: [self setTransferRate: _driveNum UseDMA:NO];
781: ideIoReq->regValues = [self logToPhys:block numOfBlocks:cnt];
782: if (ideIoReq->cmd == IDE_READ)
783: ideIoReq->status =
784: [self ideReadGetInfoCommon:&(ideIoReq->regValues)
785: client:(ideIoReq->map)
786: addr:(ideIoReq->addr) command:IDE_READ];
787: else
788: ideIoReq->status =
789: [self ideReadMultiple:&(ideIoReq->regValues)
790: client:(ideIoReq->map) addr:(ideIoReq->addr)];
791:
792: if (ideIoReq->status == IDER_SUCCESS)
793: ideIoReq->blocks_xfered = ideIoReq->blkcnt;
794: break;
795:
796: case IDE_WRITE:
797: case IDE_WRITE_MULTIPLE:
798:
799: block = ideIoReq->block;
800: cnt = ideIoReq->blkcnt;
801: if ((cnt > MAX_BLOCKS_PER_XFER) || (cnt > (IDE_MAX_PHYS_IO/IDE_SECTOR_SIZE)))
802: {
803: ideIoReq->status = IDER_REJECT;
804: break;
805: }
806: [self setTransferRate: _driveNum UseDMA:NO];
807: ideIoReq->regValues = [self logToPhys:block numOfBlocks:cnt];
808: if (ideIoReq->cmd == IDE_WRITE)
809: ideIoReq->status = [self ideWrite:&(ideIoReq->regValues)
810: client:(ideIoReq->map)
811: addr:(ideIoReq->addr)];
812: else
813: ideIoReq->status =
814: [self ideWriteMultiple:&(ideIoReq->regValues)
815: client:(ideIoReq->map) addr:(ideIoReq->addr)];
816:
817: if (ideIoReq->status == IDER_SUCCESS)
818: ideIoReq->blocks_xfered = ideIoReq->blkcnt;
819: break;
820:
821: case IDE_WRITE_DMA:
822: case IDE_READ_DMA:
823: block = ideIoReq->block;
824: cnt = ideIoReq->blkcnt;
825: if ((cnt > MAX_BLOCKS_PER_XFER) || (cnt > (IDE_MAX_PHYS_IO / IDE_SECTOR_SIZE)))
826: {
827: ideIoReq->status = IDER_REJECT;
828: break;
829: }
830: [self setTransferRate: _driveNum UseDMA:YES];
831: ideIoReq->status = [self ideDmaRwCommon:ideIoReq];
832: if (ideIoReq->status == IDER_SUCCESS)
833: ideIoReq->blocks_xfered = ideIoReq->blkcnt;
834: break;
835:
836: case IDE_SEEK:
837: block = ideIoReq->block;
838: cnt = 1;
839: ideIoReq->regValues = [self logToPhys:block numOfBlocks:cnt];
840: ideIoReq->status =
841: [self ideReadVerifySeekCommon:&(ideIoReq->regValues)
842: command:IDE_SEEK];
843: break;
844:
845: case IDE_RESTORE:
846: ideIoReq->status = [self ideRestore:&(ideIoReq->regValues)];
847: break;
848:
849: case IDE_READ_VERIFY:
850: block = ideIoReq->block;
851: cnt = ideIoReq->blkcnt;
852: if (cnt > MAX_BLOCKS_PER_XFER) {
853: ideIoReq->status = IDER_REJECT;
854: break;
855: }
856: ideIoReq->regValues = [self logToPhys:block numOfBlocks:cnt];
857: ideIoReq->status =
858: [self ideReadVerifySeekCommon:&(ideIoReq->regValues)
859: command:IDE_READ_VERIFY];
860: break;
861:
862: case IDE_DIAGNOSE:
863: [self ideDiagnose:&error];
864: ideIoReq->diagResult = error;
865: ideIoReq->status = IDER_SUCCESS;
866: break;
867:
868: case IDE_SET_PARAMS:
869: ideIoReq->status =
870: [self ideSetParams:_ideInfo[_driveNum].sectors_per_trk
871: numHeads:_ideInfo[_driveNum].heads ForDrive:_driveNum];
872: break;
873:
874: case IDE_IDENTIFY_DRIVE:
875: [self setTransferRate: _driveNum UseDMA:NO];
876: ideIoReq->status =
877: [self ideReadGetInfoCommon:&(ideIoReq->regValues)
878: client :(ideIoReq->map) addr :(ideIoReq->addr)
879: command:IDE_IDENTIFY_DRIVE];
880:
881: if (ideIoReq->status == IDER_SUCCESS)
882: ideIoReq->blocks_xfered = 1;
883: break;
884:
885: case IDE_SET_MULTIPLE:
886: maxSectors = (_ideIdentifyInfo[_driveNum].multipleSectors) &
887: IDE_MULTI_SECTOR_MASK;
888: if (ideIoReq->maxSectorsPerIntr > maxSectors)
889: {
890: ideIoReq->status = IDER_REJECT;
891: }
892: else
893: {
894: ideIoReq->status = [self ideSetMultiSectorMode:
895: &(ideIoReq->regValues)
896: numSectors:ideIoReq->maxSectorsPerIntr];
897: if (ideIoReq->status == IDER_SUCCESS)
898: _multiSector[_driveNum] = ideIoReq->maxSectorsPerIntr;
899: else
900: _multiSector[_driveNum] = 0;
901: }
902: break;
903:
904: default:
905: ideIoReq->status = IDER_REJECT;
906: [self ideCntrlrUnLock];
907: return (IDER_REJECT);
908: }
909:
910: #if 0
911: kprintf("Disk(ATA): Cmd = %02x LBA = %08x Length = %08x Addr=%08x:%08x Status = %d\n\r",
912: ideIoReq->cmd, (int)ideIoReq->block, (int)ideIoReq->blkcnt, (int)ideIoReq->addr, (int)ideIoReq->map,
913: ideIoReq->status);
914: #endif
915:
916: /*
917: * Return if command has been executed successfully or summarily
918: * rejected.
919: */
920: if (ideIoReq->status == IDER_SUCCESS)
921: {
922: [self ideCntrlrUnLock];
923: return IDER_SUCCESS;
924: }
925:
926: if (ideIoReq->status == IDER_REJECT)
927: {
928: [self ideCntrlrUnLock];
929: return IDER_REJECT;
930: }
931:
932: /*
933: * The command failed to exceute properly but was accepted by the
934: * drive. Reset the drives and try again.
935: */
936: IOLog("%s: ATA command %x failed. Retrying..\n", [self name],
937: ideIoReq->cmd);
938: [self getIdeRegisters:NULL Print:"ATA Command"];
939: [self resetAndInit];
940: (void) [self ideRestore:&irv];
941: }
942:
943: /*
944: * If we get here then this is a catastrophic failure.
945: */
946: [self ideCntrlrUnLock];
947: return ideIoReq->status;
948: }
949:
950: @end
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.