|
|
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.0 (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-1998 by Apple Computer, Inc., All rights reserved.
26: * Copyright 1994-1997 NeXT Software, Inc., All rights reserved.
27: *
28: * IdeCntCmds.m - Implementation of Commands category for IDE Controller
29: * device.
30: *
31: * It contains implementation of the ATA command set.
32: *
33: *
34: * HISTORY
35: *
36: * 23-Feb-1998 Joe Liu at Apple
37: * startUpAttachedDevices method is called immediately after acquiring
38: * the lock.
39: *
40: * 1-Feb-1998 Joe Liu at Apple
41: * ideSetDriveFeature method changed to support all EIDE transfer modes.
42: * Added support for Bus Master DMA.
43: * ideExecuteCmd now sets _driveNum within the retry loop.
44: *
45: * 1-Aug-1995 Rakesh Dubey at NeXT
46: * Reduced the timeout in IDE_IDENTIFY_DRIVE method.
47: *
48: * 17-July-1994 Rakesh Dubey at NeXT
49: * Created.
50: */
51:
52: //#define DEBUG
53:
54: #import "IdeCnt.h"
55: #import "IdeCntInit.h"
56: #import "IdePIIX.h"
57: #import <kern/assert.h>
58: #import <driverkit/kernelDriver.h>
59: #import <driverkit/interruptMsg.h>
60: #import <mach/mach_interface.h>
61: #import <driverkit/IODevice.h>
62: #import <driverkit/align.h>
63: #import <machkit/NXLock.h>
64: #import <machdep/i386/io_inline.h>
65: #import "IdeDDM.h"
66:
67: /*
68: * All methods in this file implement one or more of the IDE commands. These
69: * commands get invoked by IdeDisk objects.
70: */
71:
72: @implementation IdeController(Commands)
73:
74: /*
75: * Returns a struct containing IDE registers values for a given sector
76: * address and size. Depending upon whether the drive supports LBA or CHS we
77: * fill in different values. The calling routine must make sure that these
78: * values are not overwritten. The only thing that they need to fill in is
79: * the drive number.
80: */
81: - (ideRegsVal_t)logToPhys:(unsigned)block numOfBlocks:(unsigned)nblk
82: {
83: ideRegsVal_t rv;
84: unsigned int cyl, nheads;
85: unsigned int track, spt;
86:
87: if (_drives[_driveNum].addressMode == ADDRESS_MODE_CHS) {
88: nheads = _drives[_driveNum].ideInfo.heads;
89: spt = _drives[_driveNum].ideInfo.sectors_per_trk;
90:
91: track = (block / spt);
92: cyl = track / nheads;
93: rv.sectNum = block % spt + 1;
94:
95: rv.drHead = track % nheads;
96: rv.cylLow = (cyl & 0xff);
97: rv.cylHigh = ((cyl & 0xff00) >> 8);
98: } else {
99: rv.sectNum = block & 0x0ff;
100: rv.cylLow = (block >> 8) & 0xff;
101: rv.cylHigh = (block >> 16) & 0xff;
102: rv.drHead = (block >> 24) & 0x0f;
103: }
104:
105: rv.sectCnt = (nblk == MAX_BLOCKS_PER_XFER) ? 0 : nblk;
106:
107: rv.drHead |= _drives[_driveNum].addressMode;
108: rv.drHead |= (_driveNum ? SEL_DRIVE1 : SEL_DRIVE0);
109:
110: return rv;
111: }
112:
113: /*
114: * Commands to the IDE controller.
115: */
116:
117:
118: - (ide_return_t)ideDiagnose:(unsigned *)diagError
119: {
120: ide_return_t rtn;
121: unsigned char status;
122:
123: rtn = [self waitForDeviceReady];
124: if (rtn != IDER_SUCCESS)
125: return IDER_CMD_ERROR;
126:
127: [self enableInterrupts];
128: outb(_ideRegsAddrs.command, IDE_DIAGNOSE);
129:
130: rtn = [self ideWaitForInterrupt:IDE_DIAGNOSE ideStatus:&status];
131: if (rtn != IDER_SUCCESS) {
132: [self getIdeRegisters:NULL Print:"Diagnose"];
133: return IDER_CMD_ERROR;
134: }
135:
136: rtn = [self waitForDeviceReady];
137: if (rtn != IDER_SUCCESS)
138: return IDER_CMD_ERROR;
139:
140: *diagError = inb(_ideRegsAddrs.error);
141:
142: if (*diagError == 0x01) {
143: /* FIXME: do we need to soft reset ATAPI devices? */
144: return IDER_SUCCESS;
145: }
146:
147: /*
148: * At least one of the drives is bad.
149: */
150: if (*diagError & 0x080) {
151: IOLog("%s: Drive 1 has failed diagnostics.\n", [self name]);
152: _drives[1].ideInfo.type = 0;
153:
154: if ((*diagError & 0x07f) != 1) {
155: IOLog("%s: Drive 0 has failed diagnostics, error %d\n",
156: [self name], (*diagError & 0x07f));
157: return IDER_CMD_ERROR;
158: }
159: } else {
160: _drives[0].ideInfo.type = 0;
161: IOLog("%s: Drive 0 has failed diagnostics, error %d\n",
162: [self name], (*diagError & 0x07f));
163: }
164:
165: return IDER_CMD_ERROR;
166: }
167:
168: - (ide_return_t)ideSetParams:(unsigned)sectCnt numHeads:(unsigned)nHeads
169: ForDrive:(unsigned)drive
170: {
171: unsigned char dh = _drives[drive].addressMode;
172: ide_return_t rtn;
173:
174: rtn = [self waitForDeviceReady];
175: if (rtn != IDER_SUCCESS)
176: return rtn;
177:
178: dh |= ((drive ? SEL_DRIVE1 : SEL_DRIVE0) | ((nHeads - 1) & 0x0f));
179: outb(_ideRegsAddrs.drHead, dh);
180: outb(_ideRegsAddrs.sectCnt, (sectCnt & 0xff));
181:
182: [self enableInterrupts];
183: outb(_ideRegsAddrs.command, IDE_SET_PARAMS);
184:
185: rtn = [self ideWaitForInterrupt:IDE_SET_PARAMS ideStatus:NULL];
186: if (rtn != IDER_SUCCESS) {
187: [self getIdeRegisters:NULL Print:"SetParams"];
188: return rtn;
189: }
190:
191: return rtn;
192: }
193:
194: - (ide_return_t)ideSetDriveFeature:(unsigned char)feature
195: value:(unsigned char)val
196: transferType:(ideTransferType_t)type
197: {
198: unsigned char dh = _drives[_driveNum].addressMode;
199: unsigned char status;
200: ide_return_t rtn;
201: // unsigned char tmp;
202:
203: #ifdef DEBUG
204: IOLog("Setting drive feature %x to %x\n", feature, val);
205: #endif DEBUG
206:
207: /*
208: * We are not going to do anything if EIDE support is disabled.
209: *
210: * Currently, this is useful only for setting the transfer mode.
211: */
212: if ((_EIDESupport == NO) || (feature != FEATURE_SET_TRANSFER_MODE) ||
213: (val == ATA_MODE_NONE))
214: return IDER_SUCCESS;
215:
216: val = ata_mode_to_num(val);
217: // IOLog("Mode num: %d\n", val);
218:
219: rtn = [self waitForDeviceReady];
220: if (rtn != IDER_SUCCESS)
221: return rtn;
222:
223: dh |= (_driveNum ? SEL_DRIVE1 : SEL_DRIVE0);
224: outb(_ideRegsAddrs.drHead, dh);
225:
226: val &= 0x07;
227: switch (type) {
228: case IDE_TRANSFER_PIO:
229: val |= (1 << 3);
230: break;
231: case IDE_TRANSFER_SW_DMA:
232: val |= (1 << 4);
233: break;
234: case IDE_TRANSFER_MW_DMA:
235: val |= (1 << 5);
236: break;
237: case IDE_TRANSFER_ULTRA_DMA:
238: val |= (1 << 6);
239: break;
240: default:
241: val = 0;
242: }
243: outb(_ideRegsAddrs.sectCnt, val);
244: outb(_ideRegsAddrs.features, feature);
245:
246: [self enableInterrupts];
247: outb(_ideRegsAddrs.command, IDE_SET_FEATURES);
248:
249: rtn = [self ideWaitForInterrupt:IDE_SET_FEATURES ideStatus:&status];
250: if (rtn != IDER_SUCCESS) {
251: [self getIdeRegisters:NULL Print:"SetFeatures"];
252: return rtn;
253: }
254:
255: if (status & ERROR)
256: return IDER_ERROR;
257:
258: return rtn;
259: }
260:
261: - (ide_return_t)ideRestore:(ideRegsVal_t *)ideRegs
262: {
263: ide_return_t rtn;
264: unsigned char status;
265: unsigned char dh = _drives[_driveNum].addressMode;
266:
267: rtn = [self waitForDeviceReady];
268: if (rtn != IDER_SUCCESS) {
269: return rtn;
270: }
271:
272: dh |= (_driveNum ? SEL_DRIVE1 : SEL_DRIVE0);
273: outb(_ideRegsAddrs.drHead, dh);
274:
275: [self enableInterrupts];
276: outb(_ideRegsAddrs.command, IDE_RESTORE);
277:
278: rtn = [self ideWaitForInterrupt:IDE_RESTORE ideStatus: &status];
279: if (rtn != IDER_SUCCESS) {
280: [self getIdeRegisters:NULL Print:"Restore"];
281: return rtn;
282: }
283:
284: rtn = [self waitForDeviceReady];
285: if (rtn == IDER_SUCCESS) {
286: if (status & ERROR) {
287: [self getIdeRegisters:ideRegs Print:"Restore"];
288: rtn = IDER_CMD_ERROR;
289: }
290: }
291:
292: return (rtn);
293: }
294:
295: - (ide_return_t)ideReadGetInfoCommon:(ideRegsVal_t *)ideRegs
296: client:(struct vm_map *)client
297: addr:(caddr_t)xferAddr
298: command:(unsigned int)cmd
299: {
300: ide_return_t rtn;
301: unsigned int sec_cnt = ideRegs->sectCnt;
302: int i;
303: unsigned char *taddr;
304: unsigned char status;
305: unsigned char dh = _drives[_driveNum].addressMode;
306:
307: if (sec_cnt == 0)
308: sec_cnt = MAX_BLOCKS_PER_XFER;
309:
310: taddr = xferAddr;
311:
312: /*
313: * We have to define this for the IDE_IDENTIFY_DRIVE command.
314: */
315: if (cmd == IDE_IDENTIFY_DRIVE) {
316: ideRegs->sectCnt = 1;
317: sec_cnt = 1;
318: }
319:
320: /*
321: * Select the drive first. This routine is invoked by the initialization
322: * code as well (-resetAndInit) so it is necessary to do this here.
323: */
324: dh |= (_driveNum ? SEL_DRIVE1 : SEL_DRIVE0);
325: outb(_ideRegsAddrs.drHead, dh);
326:
327:
328: rtn = [self waitForDeviceReady];
329: if (rtn != IDER_SUCCESS) {
330: if (_ide_debug) {
331: IOLog("ideReadGetInfoCommon: waitForDeviceReady\n");
332: [self getIdeRegisters:ideRegs Print:NULL];
333: }
334: return (rtn);
335: }
336:
337: if (cmd == IDE_READ) {
338: outb(_ideRegsAddrs.drHead, ideRegs->drHead);
339: outb(_ideRegsAddrs.sectNum, ideRegs->sectNum);
340: outb(_ideRegsAddrs.sectCnt, ideRegs->sectCnt);
341: outb(_ideRegsAddrs.cylLow, ideRegs->cylLow);
342: outb(_ideRegsAddrs.cylHigh, ideRegs->cylHigh);
343: } else {
344: /* probably unnecessary */
345: outb(_ideRegsAddrs.drHead, dh);
346: outb(_ideRegsAddrs.sectCnt, ideRegs->sectCnt);
347: }
348:
349: [self enableInterrupts];
350: outb(_ideRegsAddrs.command, cmd);
351:
352: for (i = 0; i < sec_cnt; i++) {
353:
354: rtn = [self ideWaitForInterrupt:cmd ideStatus:&status];
355: if (rtn != IDER_SUCCESS) {
356: if (_ide_debug) {
357: IOLog("ideReadGetInfoCommon: ideWaitForInterrupt\n");
358: [self getIdeRegisters:ideRegs Print:NULL];
359: }
360: return rtn;
361: } else {
362: /*
363: if (status & ERROR_CORRECTED) {
364: IOLog("%s: Corrected error during read.\n", [self name]);
365: }
366: */
367: }
368:
369: /*
370: * Same as waitForDataReady but with a quick timeout.
371: */
372: rtn = [self ataIdeReadGetInfoCommonWaitForDataReady];
373: if (rtn != IDER_SUCCESS) {
374: if (_ide_debug) {
375: IOLog("ideReadGetInfoCommon: "
376: "ataIdeReadGetInfoCommonWaitForDataReady\n");
377: [self getIdeRegisters:ideRegs Print:NULL];
378: }
379: return (rtn);
380: }
381:
382: [self xferData:taddr read:YES client:client length:IDE_SECTOR_SIZE];
383: taddr += IDE_SECTOR_SIZE;
384: }
385:
386: return rtn;
387: }
388:
389: - (ide_return_t)ideWrite:(ideRegsVal_t *)ideRegs
390: client:(struct vm_map *)client
391: addr:(caddr_t)xferAddr
392: {
393: ide_return_t rtn;
394: unsigned int sec_cnt = ideRegs->sectCnt;
395: int i;
396: unsigned char *taddr;
397: unsigned char status;
398:
399: if (sec_cnt == 0)
400: sec_cnt = MAX_BLOCKS_PER_XFER;
401:
402: taddr = xferAddr;
403:
404: rtn = [self waitForDeviceReady];
405: if (rtn != IDER_SUCCESS) {
406: return (rtn);
407: }
408:
409: outb(_ideRegsAddrs.drHead, ideRegs->drHead);
410: outb(_ideRegsAddrs.sectNum, ideRegs->sectNum);
411: outb(_ideRegsAddrs.sectCnt, ideRegs->sectCnt);
412: outb(_ideRegsAddrs.cylLow, ideRegs->cylLow);
413: outb(_ideRegsAddrs.cylHigh, ideRegs->cylHigh);
414:
415: [self enableInterrupts];
416: outb(_ideRegsAddrs.command, IDE_WRITE);
417:
418: for (i = 0; i < sec_cnt; i++) {
419:
420: rtn = [self waitForDataReady];
421: if (rtn != IDER_SUCCESS) {
422: return (rtn);
423: }
424:
425: [self xferData:taddr read:NO client:client length:IDE_SECTOR_SIZE];
426: taddr += IDE_SECTOR_SIZE;
427:
428: rtn = [self ideWaitForInterrupt:IDE_WRITE ideStatus:&status];
429:
430: if (rtn != IDER_SUCCESS) {
431: [self getIdeRegisters:ideRegs Print:"Write"];
432: return (rtn);
433: } else {
434: /*
435: if (status & ERROR_CORRECTED) {
436: IOLog("%s: Corrected error during write.\n", [self name]);
437: }
438: */
439: }
440: }
441:
442: return (rtn);
443: }
444:
445: - (ide_return_t)ideReadVerifySeekCommon:(ideRegsVal_t *)ideRegs
446: command:(unsigned int)cmd
447: {
448: ide_return_t rtn;
449: unsigned char status;
450:
451: rtn = [self waitForDeviceReady];
452: if (rtn != IDER_SUCCESS) {
453: return (rtn);
454: }
455:
456: outb(_ideRegsAddrs.drHead, ideRegs->drHead);
457: outb(_ideRegsAddrs.sectNum, ideRegs->sectNum);
458: if (cmd == IDE_READ_VERIFY)
459: outb(_ideRegsAddrs.sectCnt, ideRegs->sectCnt);
460: outb(_ideRegsAddrs.cylLow, ideRegs->cylLow);
461: outb(_ideRegsAddrs.cylHigh, ideRegs->cylHigh);
462:
463: [self enableInterrupts];
464: outb(_ideRegsAddrs.command, cmd);
465:
466: rtn = [self ideWaitForInterrupt:cmd ideStatus: &status];
467: if (rtn != IDER_SUCCESS) {
468: [self getIdeRegisters:NULL Print:"ReadVerify/Seek"];
469: return (rtn);
470: }
471:
472: if (status & (ERROR | WRITE_FAULT)) {
473: rtn = IDER_CMD_ERROR;
474: } else {
475: if ((cmd == IDE_SEEK) && (!(status & SEEK_COMPLETE)))
476: rtn = IDER_CMD_ERROR;
477: }
478:
479: return (rtn);
480: }
481:
482: - (ide_return_t)ideSetMultiSectorMode:(ideRegsVal_t *)ideRegs
483: numSectors:(unsigned char)nSectors
484: {
485: ide_return_t rtn;
486: unsigned char status;
487: unsigned char dh = _drives[_driveNum].addressMode;
488:
489: rtn = [self waitForDeviceReady];
490: if (rtn != IDER_SUCCESS) {
491: return (rtn);
492: }
493:
494: dh |= (_driveNum ? SEL_DRIVE1 : SEL_DRIVE0);
495: outb(_ideRegsAddrs.drHead, dh);
496: outb(_ideRegsAddrs.sectCnt, nSectors);
497:
498: [self enableInterrupts];
499: outb(_ideRegsAddrs.command, IDE_SET_MULTIPLE);
500:
501: rtn = [self ideWaitForInterrupt:IDE_SET_MULTIPLE ideStatus:&status];
502: if (rtn != IDER_SUCCESS) {
503: return (rtn);
504: }
505:
506: rtn = [self waitForDeviceReady];
507: if (rtn == IDER_SUCCESS) {
508: if (status & ERROR) {
509: rtn = IDER_CMD_ERROR;
510: [self getIdeRegisters:ideRegs Print:NULL];
511: } else
512: rtn = IDER_SUCCESS;
513: }
514:
515: return (rtn);
516: }
517:
518: /*
519: * Note: Never read the status register at the end of data transfer, you may
520: * clobber the next interrupt from the drive. If it is necessary to get
521: * status use the alternate status register.
522: */
523: - (ide_return_t)ideReadMultiple:(ideRegsVal_t *)ideRegs
524: client:(struct vm_map *)client
525: addr:(caddr_t)xferAddr
526: {
527: ide_return_t rtn;
528: unsigned char status;
529: unsigned sec_cnt = ideRegs->sectCnt;
530: unsigned int nSectors;
531: unsigned char *taddr;
532: unsigned int length;
533:
534: if (sec_cnt == 0)
535: sec_cnt = MAX_BLOCKS_PER_XFER;
536:
537: taddr = xferAddr;
538:
539: rtn = [self waitForDeviceReady];
540: if (rtn != IDER_SUCCESS) {
541: return (rtn);
542: }
543:
544: outb(_ideRegsAddrs.drHead, ideRegs->drHead);
545: outb(_ideRegsAddrs.sectNum, ideRegs->sectNum);
546: outb(_ideRegsAddrs.sectCnt, ideRegs->sectCnt);
547: outb(_ideRegsAddrs.cylLow, ideRegs->cylLow);
548: outb(_ideRegsAddrs.cylHigh, ideRegs->cylHigh);
549:
550: [self enableInterrupts];
551: outb(_ideRegsAddrs.command, IDE_READ_MULTIPLE);
552:
553: ddm_ide_cmd("ideReadMultiple: sec_cnt %d sectors\n", sec_cnt, 2,3,4,5);
554:
555: while (sec_cnt > 0) {
556:
557: ddm_ide_cmd("ideReadMultiple: waiting for interrupt\n",1,2,3,4,5);
558: rtn = [self ideWaitForInterrupt:IDE_READ_MULTIPLE
559: ideStatus: &status];
560: ddm_ide_cmd("ideReadMultiple: received interrupt\n",1,2,3,4,5);
561:
562: if (rtn != IDER_SUCCESS) {
563: [self getIdeRegisters:ideRegs Print:"Read Multiple"];
564: return (rtn);
565: }
566:
567: #if 1
568: rtn = [self waitForDataReady];
569: if (rtn != IDER_SUCCESS) {
570: return (rtn);
571: }
572: #endif 1
573:
574: if (status & (ERROR | WRITE_FAULT)) {
575: [self getIdeRegisters:ideRegs Print:"Read Multiple"];
576: return IDER_CMD_ERROR;
577: }
578:
579: /*
580: * Any drive formatted with 63 sector/track (which most over 400 MB
581: * are) reporting this status (ERROR_CORRECTED) will cause an
582: * fallacious error (possibly uncorrectable) due to a long-standing
583: * bug in DOS. This status bit should be made vendor specific, like
584: * IDX. It has outlived its usefulness.
585: * -- [email protected]
586: */
587:
588: /*
589: if (status & ERROR_CORRECTED) {
590: IOLog("%s: Corrected error during read.\n", [self name]);
591: }
592: */
593:
594: /*
595: * All is well. Read in the data.
596: */
597: if (sec_cnt > _drives[_driveNum].multiSector)
598: nSectors = _drives[_driveNum].multiSector;
599: else
600: nSectors = sec_cnt;
601:
602: sec_cnt -= nSectors;
603:
604: ddm_ide_cmd("ideReadMultiple: starting data transfer\n",1,2,3,4,5);
605:
606: while (nSectors) {
607: if (nSectors > PAGE_SIZE / IDE_SECTOR_SIZE) {
608: length = PAGE_SIZE;
609: nSectors -= (PAGE_SIZE / IDE_SECTOR_SIZE);
610: } else {
611: length = nSectors * IDE_SECTOR_SIZE;
612: nSectors = 0;
613: }
614:
615: [self xferData:taddr read:YES client:client length:length];
616: taddr += length;
617: }
618:
619: ddm_ide_cmd("ideReadMultiple: data transfer done\n",1,2,3,4,5);
620: }
621:
622: ddm_ide_cmd("ideReadMultiple: completed\n",1,2,3,4,5);
623:
624: return (rtn);
625: }
626:
627: - (ide_return_t)ideWriteMultiple:(ideRegsVal_t *)ideRegs
628: client:(struct vm_map *)client
629: addr:(caddr_t)xferAddr
630: {
631: ide_return_t rtn;
632: unsigned char status;
633: unsigned sec_cnt = ideRegs->sectCnt;
634: unsigned int nSectors;
635: unsigned char *taddr;
636: unsigned int length;
637:
638: if (sec_cnt == 0)
639: sec_cnt = MAX_BLOCKS_PER_XFER;
640:
641: taddr = xferAddr;
642:
643: rtn = [self waitForDeviceReady];
644: if (rtn != IDER_SUCCESS) {
645: return (rtn);
646: }
647:
648: outb(_ideRegsAddrs.drHead, ideRegs->drHead);
649: outb(_ideRegsAddrs.sectNum, ideRegs->sectNum);
650: outb(_ideRegsAddrs.sectCnt, ideRegs->sectCnt);
651: outb(_ideRegsAddrs.cylLow, ideRegs->cylLow);
652: outb(_ideRegsAddrs.cylHigh, ideRegs->cylHigh);
653:
654: [self enableInterrupts];
655: outb(_ideRegsAddrs.command, IDE_WRITE_MULTIPLE);
656:
657: ddm_ide_cmd("ideWriteMultiple: sec_cnt %d sectors\n", sec_cnt, 2,3,4,5);
658:
659: while (sec_cnt > 0) {
660:
661: rtn = [self waitForDataReady];
662: if (rtn != IDER_SUCCESS) {
663: return (rtn);
664: }
665:
666: if (sec_cnt > _drives[_driveNum].multiSector)
667: nSectors = _drives[_driveNum].multiSector;
668: else
669: nSectors = sec_cnt;
670:
671: sec_cnt -= nSectors;
672:
673: ddm_ide_cmd("ideWriteMultiple: starting data transfer\n",1,2,3,4,5);
674:
675: while (nSectors) {
676: if (nSectors > PAGE_SIZE / IDE_SECTOR_SIZE) {
677: length = PAGE_SIZE;
678: nSectors -= (PAGE_SIZE / IDE_SECTOR_SIZE);
679: } else {
680: length = nSectors * IDE_SECTOR_SIZE;
681: nSectors = 0;
682: }
683:
684: [self xferData:taddr read:NO client:client length:length];
685: taddr += length;
686: }
687: ddm_ide_cmd("ideWriteMultiple: data transfer done\n",1,2,3,4,5);
688:
689: ddm_ide_cmd("ideWriteMultiple: waiting for interrupt\n",1,2,3,4,5);
690: rtn = [self ideWaitForInterrupt:IDE_WRITE_MULTIPLE
691: ideStatus:&status];
692: ddm_ide_cmd("ideWriteMultiple: received interrupt\n",1,2,3,4,5);
693:
694: if (rtn != IDER_SUCCESS) {
695: [self getIdeRegisters:ideRegs Print:"Write Multiple"];
696: return (rtn);
697: }
698:
699: if (status & (ERROR | WRITE_FAULT)) {
700: [self getIdeRegisters:ideRegs Print:"Write Multiple"];
701: return IDER_CMD_ERROR;
702: }
703:
704: /*
705: if (status & ERROR_CORRECTED) {
706: IOLog("%s: Corrected error during write.\n", [self name]);
707: }
708: */
709:
710: }
711:
712: ddm_ide_cmd("ideWriteMultiple: completed\n",1,2,3,4,5);
713:
714: return (rtn);
715: }
716:
717: /*
718: * Method: performDMATestOnDrive:(unsigned char)drive
719: *
720: * Purpose:
721: * Read a few sectors and make sure DMA really "seems" to works.
722: *
723: * NOTE: _driveNum must be set prior to calling this method.
724: */
725: - (ide_return_t)performDMATest
726: {
727: ideIoReq_t ideIoReq;
728: ide_return_t status;
729: vm_offset_t tempDmaBuf;
730: vm_offset_t alignBuf;
731: unsigned int currentTimeout;
732: unsigned char dh;
733:
734: /*
735: * The hardware claims to supports DMA. Verify by reading a
736: * few sectors. Allocate memory for dummy buffer.
737: */
738: tempDmaBuf = (vm_offset_t)IOMalloc(PAGE_SIZE);
739: if (tempDmaBuf == NULL) {
740: IOLog("%s: memory allocation failed\n", [self name]);
741: return IDER_REJECT;
742: }
743:
744: /*
745: * Advance the pointer and make the buffer 4 byte aligned.
746: */
747: alignBuf = (tempDmaBuf + 3) & ~3;
748:
749: bzero((unsigned char *)&ideIoReq, sizeof(ideIoReq_t));
750: ideIoReq.cmd = IDE_READ_DMA;
751: ideIoReq.block = 0;
752: ideIoReq.blkcnt = (PAGE_SIZE - 4)/IDE_SECTOR_SIZE;
753: ideIoReq.addr = (caddr_t)alignBuf;
754: ideIoReq.timeout = 5000;
755: ideIoReq.map = (struct vm_map *)IOVmTaskSelf();
756:
757: /*
758: * Select the drive first.
759: */
760: if ([self waitForDeviceIdle] != IDER_SUCCESS) {
761: IOLog("%s: Drive %d DMA test FAILED\n", [self name], _driveNum);
762: return IDER_TIMEOUT;
763: }
764: dh = _drives[_driveNum].addressMode;
765: dh |= (_driveNum ? SEL_DRIVE1 : SEL_DRIVE0);
766: outb(_ideRegsAddrs.drHead, dh);
767:
768: /*
769: * Wait 400ns before reading the status register and make sure the
770: * currently selected drive is ready to accept a command.
771: */
772: IODelay(1);
773: if ([self waitForDeviceIdle] != IDER_SUCCESS) {
774: IOLog("%s: Drive %d DMA test FAILED\n", [self name], _driveNum);
775: return IDER_TIMEOUT;
776: }
777:
778: /*
779: * Clear any unwanted interrupts which may have accumulated.
780: */
781: [self enableInterrupts];
782: IOSleep(100);
783:
784: /*
785: * Set a smaller (3 sec) timeout for this test.
786: */
787: currentTimeout = [self interruptTimeOut];
788: [self setInterruptTimeOut:3000];
789: [self clearInterrupts];
790:
791: /*
792: * Perform test.
793: */
794: if (([self performDMA:(ideIoReq_t *)&ideIoReq]) == IDER_SUCCESS) {
795: status = IDER_SUCCESS;
796: // IOLog("%s: Drive %d: DMA test PASSED\n", [self name], _driveNum);
797: }
798: else {
799: status = IDER_REJECT;
800: IOLog("%s: Drive %d: DMA test FAILED\n", [self name], _driveNum);
801: }
802:
803: /*
804: * Revert the original timeout value and free allocated memory.
805: */
806: [self setInterruptTimeOut:currentTimeout];
807: IOFree((void *)tempDmaBuf, PAGE_SIZE);
808: return status;
809: }
810:
811: /*
812: * All I/O to to controller object is done through this method. We first
813: * acquire a lock before executing any IDE commands since the IDE controller
814: * can do only one thing at a time (both drivers can not be active
815: * simultaneously except for reset and disgnostics).
816: *
817: * If it necessary to call any of the IDE command methods (which are invoked by
818: * the switch() below, like ideReadGetInfoCommon:client:addr:command) it is
819: * necessary to acquire the lock. The IDE command methods should not be
820: * invoked directly by the Disk object.
821: *
822: * This method will in turn call one of several methods which deal with
823: * hardware.
824: */
825:
826: static unsigned char unaligned_warnings;
827: #define UNALIGNED_WARNINGS_MAX 20
828:
829: #define MAX_COMMAND_RETRY 3
830:
831: - (IOReturn) ideExecuteCmd:(ideIoReq_t *)ideIoReq ToDrive:(unsigned char)drive
832: {
833: int retry;
834: ideRegsVal_t irv;
835: unsigned block, cnt;
836: unsigned error;
837: unsigned int maxSectors;
838: unsigned char dh;
839:
840: ddm_ide_cmd("ideExecuteCmd: executing %x\n", ideIoReq->cmd,2,3,4,5);
841:
842: /*
843: * If the controller wishes to put the drive to sleep, it sets this flag
844: * to YES and tries to acquire the lock. This method should not try to
845: * get the lock (and execute any more commands) if the flag is set. This
846: * is needed in order to enter sleep mode as soon as the current command
847: * is finished. If we do not do this there is contention for lock between
848: * the controller (which wants to put the drive to sleep) and this method
849: * (which wants to service more requests). Note that this does not do
850: * away with the need for a lock, it only gives the controller a little
851: * head-start.
852: */
853:
854: while (_driveSleepRequest) {
855: IOSleep(100);
856: }
857:
858: ddm_ide_lock("ideExecuteCmd: acquiring lock\n",1,2,3,4,5);
859: [self ideCntrlrLock];
860: ddm_ide_lock("ideExecuteCmd: acquired lock\n",1,2,3,4,5);
861:
862: /*
863: * Check if we need to do a media access to get the drive respinning
864: * after a suspend operation.
865: */
866: if ([self drivePowerState] != IDE_PM_ACTIVE) {
867: [self startUpAttachedDevices];
868: }
869:
870: _driveNum = drive; /* used by IDE command methods. */
871:
872: for (retry = 0; retry < MAX_COMMAND_RETRY; retry++) {
873:
874: /*
875: * Select the drive first. We don't know the head number at this time so
876: * this register will be rewritten by the specific routine later.
877: *
878: * The Device Selection protocol is defined as follows:
879: * HOST: Read Status or AltStatus register
880: * HOST: Continue reading until BSY = 0, and DRQ = 0
881: * HOST: Write Device/Head register with appropriate DEV bit value
882: * HOST: Wait 400ns
883: * HOST: Read Status or AltStatus register
884: * HOST: Continue reading until BSY = 0, and DRQ = 0
885: *
886: */
887: // [self waitForDeviceIdle]; // Devices should be already in an idle state
888: dh = _drives[_driveNum].addressMode;
889: dh |= (_driveNum ? SEL_DRIVE1 : SEL_DRIVE0);
890: outb(_ideRegsAddrs.drHead, dh);
891: IODelay(1);
892: // [self waitForDeviceIdle]; // Each method below will do their own wait
893:
894: ideIoReq->status = IDER_CMD_ERROR;
895: ideIoReq->blocks_xfered = 0;
896:
897: [self clearInterrupts];
898:
899: switch (ideIoReq->cmd) {
900:
901: case IDE_READ_DMA:
902: if (((vm_offset_t)ideIoReq->addr & 0x03) == 0) {
903: block = ideIoReq->block;
904: cnt = ideIoReq->blkcnt;
905: ddm_ide_log("IDE_READ_DMA: %d\n", cnt, 2, 3, 4, 5);
906: if (cnt > MAX_BLOCKS_PER_XFER) {
907: ideIoReq->status = IDER_REJECT;
908: break;
909: }
910:
911: ideIoReq->status = [self performDMA:ideIoReq];
912: if (ideIoReq->status == IDER_SUCCESS)
913: ideIoReq->blocks_xfered = ideIoReq->blkcnt;
914: break;
915: }
916:
917: /*
918: * If we reached here, it means that the buffer is not 4-byte
919: * aligned. This should not happen.
920: */
921: if (unaligned_warnings < UNALIGNED_WARNINGS_MAX) {
922: IOLog("%s: READ DMA: buffer not 4-byte aligned\n", [self name]);
923: unaligned_warnings++;
924: }
925:
926: case IDE_READ:
927: case IDE_READ_MULTIPLE:
928:
929: block = ideIoReq->block;
930: cnt = ideIoReq->blkcnt;
931: ddm_ide_log("IDE_READ: %d\n", cnt, 2, 3, 4, 5);
932: if (cnt > MAX_BLOCKS_PER_XFER) {
933: ideIoReq->status = IDER_REJECT;
934: break;
935: }
936: ideIoReq->regValues = [self logToPhys:block numOfBlocks:cnt];
937: if (ideIoReq->cmd == IDE_READ)
938: ideIoReq->status =
939: [self ideReadGetInfoCommon:&(ideIoReq->regValues)
940: client:(ideIoReq->map)
941: addr:(ideIoReq->addr) command:IDE_READ];
942: else
943: ideIoReq->status =
944: [self ideReadMultiple:&(ideIoReq->regValues)
945: client:(ideIoReq->map) addr:(ideIoReq->addr)];
946:
947: if (ideIoReq->status == IDER_SUCCESS)
948: ideIoReq->blocks_xfered = ideIoReq->blkcnt;
949: break;
950:
951: case IDE_WRITE_DMA:
952: if (((vm_offset_t)ideIoReq->addr & 0x03) == 0) {
953: block = ideIoReq->block;
954: cnt = ideIoReq->blkcnt;
955: ddm_ide_log("IDE_WRITE_DMA: %d\n", cnt, 2, 3, 4, 5);
956: if (cnt > MAX_BLOCKS_PER_XFER) {
957: ideIoReq->status = IDER_REJECT;
958: break;
959: }
960:
961: ideIoReq->status = [self performDMA:ideIoReq];
962: if (ideIoReq->status == IDER_SUCCESS)
963: ideIoReq->blocks_xfered = ideIoReq->blkcnt;
964: break;
965: }
966:
967: /*
968: * If we reached here, it means that the buffer is not 4-byte
969: * aligned. This should not happen.
970: */
971: if (unaligned_warnings < UNALIGNED_WARNINGS_MAX) {
972: IOLog("%s: WRITE DMA: buffer not 4-byte aligned\n", [self name]);
973: unaligned_warnings++;
974: }
975:
976: case IDE_WRITE:
977: case IDE_WRITE_MULTIPLE:
978:
979: block = ideIoReq->block;
980: cnt = ideIoReq->blkcnt;
981: ddm_ide_log("IDE_WRITE: %d\n", cnt, 2, 3, 4, 5);
982: if (cnt > MAX_BLOCKS_PER_XFER) {
983: ideIoReq->status = IDER_REJECT;
984: break;
985: }
986: ideIoReq->regValues = [self logToPhys:block numOfBlocks:cnt];
987: if (ideIoReq->cmd == IDE_WRITE)
988: ideIoReq->status = [self ideWrite:&(ideIoReq->regValues)
989: client:(ideIoReq->map)
990: addr:(ideIoReq->addr)];
991: else
992: ideIoReq->status =
993: [self ideWriteMultiple:&(ideIoReq->regValues)
994: client:(ideIoReq->map) addr:(ideIoReq->addr)];
995:
996: if (ideIoReq->status == IDER_SUCCESS)
997: ideIoReq->blocks_xfered = ideIoReq->blkcnt;
998: break;
999:
1000: case IDE_SEEK:
1001: block = ideIoReq->block;
1002: cnt = 1;
1003: ideIoReq->regValues = [self logToPhys:block numOfBlocks:cnt];
1004: ideIoReq->status =
1005: [self ideReadVerifySeekCommon:&(ideIoReq->regValues)
1006: command:IDE_SEEK];
1007: break;
1008:
1009: case IDE_RESTORE:
1010: ideIoReq->status = [self ideRestore:&(ideIoReq->regValues)];
1011: break;
1012:
1013: case IDE_READ_VERIFY:
1014: block = ideIoReq->block;
1015: cnt = ideIoReq->blkcnt;
1016: ddm_ide_log("IDE_READ_VERIFY: %d\n", cnt, 2, 3, 4, 5);
1017: if (cnt > MAX_BLOCKS_PER_XFER) {
1018: ideIoReq->status = IDER_REJECT;
1019: break;
1020: }
1021: ideIoReq->regValues = [self logToPhys:block numOfBlocks:cnt];
1022: ideIoReq->status =
1023: [self ideReadVerifySeekCommon:&(ideIoReq->regValues)
1024: command:IDE_READ_VERIFY];
1025: break;
1026:
1027: case IDE_DIAGNOSE:
1028: [self ideDiagnose:&error];
1029: ideIoReq->diagResult = error;
1030: ideIoReq->status = IDER_SUCCESS;
1031: break;
1032:
1033: case IDE_SET_PARAMS:
1034: ideIoReq->status =
1035: [self ideSetParams:_drives[_driveNum].ideInfo.sectors_per_trk
1036: numHeads:_drives[_driveNum].ideInfo.heads ForDrive:_driveNum];
1037: break;
1038:
1039: case IDE_IDENTIFY_DRIVE:
1040: ideIoReq->status =
1041: [self ideReadGetInfoCommon:&(ideIoReq->regValues)
1042: client :(ideIoReq->map) addr :(ideIoReq->addr)
1043: command:IDE_IDENTIFY_DRIVE];
1044:
1045: if (ideIoReq->status == IDER_SUCCESS)
1046: ideIoReq->blocks_xfered = 1;
1047: break;
1048:
1049: case IDE_SET_MULTIPLE:
1050: maxSectors = (_drives[_driveNum].ideIdentifyInfo->multipleSectors)
1051: & IDE_MULTI_SECTOR_MASK;
1052: if (ideIoReq->maxSectorsPerIntr > maxSectors) {
1053: ideIoReq->status = IDER_REJECT;
1054: } else {
1055: ideIoReq->status = [self ideSetMultiSectorMode:
1056: &(ideIoReq->regValues)
1057: numSectors:ideIoReq->maxSectorsPerIntr];
1058: if (ideIoReq->status == IDER_SUCCESS)
1059: _drives[_driveNum].multiSector = ideIoReq->maxSectorsPerIntr;
1060: else
1061: _drives[_driveNum].multiSector = 0;
1062: }
1063: break;
1064:
1065: default:
1066: ideIoReq->status = IDER_REJECT;
1067: ddm_ide_lock("ideExecuteCmd: releasing lock, bad cmd\n",1,2,3,4,5);
1068: [self ideCntrlrUnLock];
1069: return (IDER_REJECT);
1070: }
1071:
1072: /*
1073: * Return if command has been executed successfully or summarily
1074: * rejected.
1075: */
1076: if (ideIoReq->status == IDER_SUCCESS) {
1077: [self ideCntrlrUnLock];
1078: ddm_ide_lock("ideExecuteCmd: releasing lock, success\n",1,2,3,4,5);
1079: return IDER_SUCCESS;
1080: }
1081:
1082: if (ideIoReq->status == IDER_REJECT) {
1083: [self ideCntrlrUnLock];
1084: ddm_ide_lock("ideExecuteCmd: releasing lock, reject\n",1,2,3,4,5);
1085: return IDER_REJECT;
1086: }
1087:
1088: /*
1089: * The command failed to exceute properly but was accepted by the
1090: * drive. Reset the drives and try again.
1091: */
1092: IOLog("%s: ATA command %x failed. Retrying...\n", [self name],
1093: ideIoReq->cmd);
1094: [self getIdeRegisters:NULL Print:"ATA Command"];
1095: [self resetAndInit];
1096:
1097: /*
1098: * resetAndInit will change the value of _driveNum.
1099: * Revert _driveNum to the original value before retrying the
1100: * command.
1101: */
1102: _driveNum = drive;
1103: (void) [self ideRestore:&irv];
1104: }
1105:
1106: /*
1107: * If we get here then this is a catastrophic failure.
1108: */
1109: ddm_ide_lock("ideExecuteCmd: releasing lock, failed\n",1,2,3,4,5);
1110: [self ideCntrlrUnLock];
1111: return ideIoReq->status;
1112: }
1113:
1114: @end
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.