|
|
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: * AtapiCntCmds.m - ATAPI command implementation for ATA interface.
30: *
31: * HISTORY
32: *
33: */
34:
35: #import "AtapiCntCmds.h"
36: #import "IdeCntInit.h"
37: #import "IdeCntCmds.h"
38: #import "IdeCntDma.h"
39:
40: @implementation IdeController(ATAPI)
41:
42: #define ATAPI_MAX_WAIT_FOR_NOTBUSY (5 * 1000)
43:
44: /*
45: * We could use the ATA version instead of rolling our own here.
46: */
47: - (atapi_return_t)atapiWaitForNotBusy
48: {
49: int i;
50: unsigned char status;
51:
52: for (i = 0; i < ATAPI_MAX_WAIT_FOR_NOTBUSY; i++)
53: {
54: status = inb(_ideRegsAddrs.status);
55:
56: if (!(status & BUSY))
57: {
58: return IDER_SUCCESS;
59: }
60: IOSleep(1);
61: }
62: return IDER_TIMEOUT;
63: }
64:
65: /*
66: * Before sending a packet to ATAPI device, we test if BSY == 0 and DRQ == 0.
67: */
68: #define ATAPI_MAX_WAIT_READY_FOR_PACKET (5 * 1000)
69:
70: - (atapi_return_t)atapiWaitReadyForPacket
71: {
72: int i;
73: unsigned char status;
74:
75: for (i = 0; i < ATAPI_MAX_WAIT_READY_FOR_PACKET; i++)
76: {
77: status = inb(_ideRegsAddrs.status);
78:
79: if (!(status & BUSY) && !(status & DREQUEST))
80: {
81: return IDER_SUCCESS;
82: }
83: IOSleep(1);
84: }
85:
86: return IDER_DEV_NOT_READY;
87: }
88:
89: -(void)printAtapiInfo:(ideIdentifyInfo_t *)ideIdentifyInfo
90: Device:(unsigned char)unit
91: {
92: int i;
93: char name[50];
94: char firmware[9];
95: atapiGenConfig_t *atapiGenConfig;
96: char *protocolTypeStr, *deviceTypeStr, *cmdDrqTypeStr;
97: char *removableStr, *cmdPacketSizeStr;
98:
99: /*
100: * Print drive name with firmware revision number after doing byte swaps.
101: */
102: for (i = 0; i < 20; i++)
103: {
104: name[2*i] = ideIdentifyInfo->modelNumber[2*i+1];
105: name[2*i+1] = ideIdentifyInfo->modelNumber[2*i];
106: }
107: name[40] = '\0';
108:
109: for (i = 0; i < 4; i++)
110: {
111: firmware[2*i] = ideIdentifyInfo->firmwareRevision[2*i+1];
112: firmware[2*i+1] = ideIdentifyInfo->firmwareRevision[2*i];
113: }
114: firmware[8] = '\0';
115:
116: for (i = 38; i >= 0; i--) {
117: if (name[i] != ' ')
118: break;
119: }
120: strcpy(name+i+2, firmware);
121:
122: /*
123: * This information should be printed since it is not duplicated
124: * elsewhere.
125: */
126: atapiGenConfig = (atapiGenConfig_t *) &ideIdentifyInfo->genConfig;
127:
128: if (atapiGenConfig->protocolType == 0 || atapiGenConfig->protocolType == 1)
129: protocolTypeStr = "ATA";
130: else if (atapiGenConfig->protocolType == 2)
131: protocolTypeStr = "ATAPI";
132: else
133: protocolTypeStr = "UNKNOWN PROTOCOL";
134:
135: if (atapiGenConfig->deviceType == 0)
136: deviceTypeStr = "DIRECT ACCESS";
137: else if (atapiGenConfig->deviceType == 5)
138: deviceTypeStr = "CD-ROM";
139: else if (atapiGenConfig->deviceType == 7)
140: deviceTypeStr = "OPTICAL";
141: else if (atapiGenConfig->deviceType == 1)
142: deviceTypeStr = "TAPE";
143: else
144: deviceTypeStr = "UNKNOWN DEVICE TYPE";
145:
146: if (atapiGenConfig->cmdDrqType == 0)
147: cmdDrqTypeStr = "SLOW DRQ";
148: else if (atapiGenConfig->cmdDrqType == 1)
149: cmdDrqTypeStr = "INTR DRQ";
150: else if (atapiGenConfig->cmdDrqType == 2)
151: cmdDrqTypeStr = "FAST DRQ";
152: else
153: cmdDrqTypeStr = "UNKNOWN DRQ TYPE";
154:
155: if (atapiGenConfig->removable == 0)
156: removableStr = "NOT REMOVABLE";
157: else if (atapiGenConfig->removable == 1)
158: removableStr = "REMOVABLE";
159:
160: if (atapiGenConfig->cmdPacketSize == 0)
161: cmdPacketSizeStr = "CMD PKT LEN=12";
162: else if (atapiGenConfig->cmdPacketSize == 1)
163: cmdPacketSizeStr = "CMD PKT LEN=16";
164: else
165: cmdPacketSizeStr = "CMD PKT LEN=UNKNOWN";
166: }
167:
168: /*
169: * This is a private version for ATAPI Identify command below. It has a short
170: * delay time.
171: */
172: - (ide_return_t)atapiIdentifyDeviceWaitForDataReady
173: {
174: int delay = (100 * 1000);
175: unsigned char status;
176:
177: delay -= 2;
178: while (delay > 0)
179: {
180: status = inb(_ideRegsAddrs.altStatus);
181: if ((!(status & BUSY)) && (status & DREQUEST))
182: return (IDER_SUCCESS);
183: if (delay % 1000)
184: {
185: IODelay(2);
186: delay -= 2;
187: }
188: else
189: {
190: IOSleep(1);
191: delay -= 1000;
192: }
193: }
194:
195: return IDER_DEV_NOT_READY;
196: }
197:
198: /*
199: * There are lots of ATAPI CD-ROMs that shadow the task file register and
200: * hence show up as two devices. They also might issue a valid interrupt when
201: * ATAPI Identify Device command is sent so we need to really make sure
202: * whether the device has data for us.
203: */
204: -(atapi_return_t)_atapiIdentifyDevice:(struct vm_map *)client
205: addr:(caddr_t)xferAddr
206: {
207: unsigned int cmd = ATAPI_IDENTIFY_DRIVE;
208: unsigned char dh = ADDRESS_MODE_LBA; /* ALWAYS */
209: unsigned char status;
210: atapi_return_t rtn;
211:
212: unsigned int oldTimeout;
213:
214: rtn = [self atapiWaitForNotBusy];
215: if (rtn != IDER_SUCCESS)
216: {
217: return (rtn);
218: }
219:
220: [self setTransferRate: _driveNum UseDMA:NO];
221:
222: dh |= _driveNum ? SEL_DRIVE1 : SEL_DRIVE0;
223: outb(_ideRegsAddrs.driveSelect, dh);
224:
225: bzero(xferAddr, IDE_SECTOR_SIZE);
226:
227: [self enableInterrupts];
228:
229: outb(_ideRegsAddrs.command, ATAPI_IDENTIFY_DRIVE);
230:
231: oldTimeout = [self interruptTimeOut];
232: [self setInterruptTimeOut:4000]; // four seconds
233:
234: rtn = [self ideWaitForInterrupt:cmd ideStatus:&status];
235:
236: if (rtn != IDER_SUCCESS) {
237: [self getIdeRegisters:NULL Print:"Atapi Identify"];
238: [self setInterruptTimeOut:oldTimeout];
239: return rtn;
240: }
241:
242: /*
243: * Let's see if it really has data for us.
244: */
245: rtn = [self atapiIdentifyDeviceWaitForDataReady];
246: if (rtn != IDER_SUCCESS)
247: {
248: [self setInterruptTimeOut:oldTimeout];
249: return (rtn);
250: }
251:
252: /*
253: * FIXME: We need to do some sanity check on this data to be really sure
254: * that there is an ATAPI device out here.
255: */
256: [self xferData:xferAddr read:YES client:client length:IDE_SECTOR_SIZE];
257:
258: [self setInterruptTimeOut:oldTimeout];
259:
260: return IDER_SUCCESS;
261: }
262:
263: /*
264: * Some CD-ROMS (like SONY CDU-55D) fail the first request so we reset the
265: * device and retry.
266: */
267: #define ATAPI_IDENTIFY_DEVICE_RETRIES 5
268:
269: -(atapi_return_t)atapiIdentifyDevice:(struct vm_map *)client
270: addr:(caddr_t)xferAddr
271: unit:(unsigned char)unit
272: {
273: int i;
274: atapi_return_t ret;
275:
276: for (i = 0; i < ATAPI_IDENTIFY_DEVICE_RETRIES; i++)
277: {
278: ret = [self _atapiIdentifyDevice:client addr:xferAddr];
279: if (ret == IDER_SUCCESS)
280: break;
281:
282: /* Reset hardware and try again */
283: [self atapiSoftReset:unit];
284: IOSleep(500);
285: }
286:
287: if (i == ATAPI_IDENTIFY_DEVICE_RETRIES) {
288: IOLog("%s: FATAL: Device %d: ATAPI Identify Device.\n",
289: [self name], unit);
290: }
291:
292: return ret;
293: }
294:
295: -(void)atapiInitParameters:(ideIdentifyInfo_t *)infoPtr
296: Device:(unsigned char)unit
297: {
298: atapiGenConfig_t *atapiGenConfig =
299: (atapiGenConfig_t *) &infoPtr->genConfig;
300:
301: if (atapiGenConfig->cmdPacketSize == 0x01)
302: _atapiCmdLen[unit] = 16;
303: else
304: _atapiCmdLen[unit] = 12;
305:
306: /*
307: * The command len is 12. However some devices think it is 16 which is
308: * actually reserved for SAM compatibility. See page 58, SFF 8020, rev
309: * 1.2. This is a workaround.
310: */
311: if (_atapiCmdLen[unit] != 12)
312: {
313: IOLog("%s: ATAPI: command len changed to 12 from %d.\n",
314: [self name], _atapiCmdLen[unit]);
315: _atapiCmdLen[unit] = 12;
316: }
317:
318: _atapiCmdDrqType[unit] = atapiGenConfig->cmdDrqType;
319:
320: if (infoPtr->capabilities & IDE_CAP_DMA_SUPPORTED)
321: {
322: if ( [self allocDmaMemory] == IDER_SUCCESS )
323: {
324: _dmaSupported[unit] = YES;
325: }
326: }
327:
328: [self getTransferModes:infoPtr Unit:unit];
329:
330: /*
331: * Set the Disk/CDROM transfer mode (Set Features SC=3)
332: */
333: [self setTransferMode: unit];
334: }
335:
336: /*
337: * Identify ATAPI device must have been executed first before callling this
338: * method.
339: */
340: -(unsigned char)atapiCommandPacketSize:(unsigned char)unit
341: {
342: if (unit < MAX_IDE_DRIVES)
343: return _atapiCmdLen[unit];
344: else
345: return 0;
346: }
347:
348:
349: /*
350: * The amount of time in milliseconds it takes for an ATAPI device to post
351: * its signature after a reset. Some CD-ROMs take a long time to respond. Do
352: * not decrease it without testing with various makes of ATAPI devices.
353: */
354: #define ATAPI_RESET_DELAY 2500
355:
356: -(atapi_return_t)atapiSoftReset:(unsigned char)unit
357: {
358: int delay;
359: unsigned char status;
360: atapi_return_t rtn;
361: unsigned char dh = ADDRESS_MODE_LBA; /* ALWAYS */
362:
363: _driveReset[unit] = YES;
364:
365: dh |= unit ? SEL_DRIVE1 : SEL_DRIVE0;
366:
367: outb(_ideRegsAddrs.driveSelect, dh);
368: outb(_ideRegsAddrs.command, ATAPI_SOFT_RESET);
369:
370: delay = ATAPI_RESET_DELAY;
371:
372: IOSleep(50); /* Enough time to assert busy */
373:
374: rtn = IDER_ERROR;
375:
376: while (delay > 0)
377: {
378: status = inb(_ideRegsAddrs.status);
379: if (!(status & BUSY))
380: {
381: rtn = IDER_SUCCESS;
382: break;
383: }
384:
385: IOSleep(10);
386: delay -= 10;
387: }
388:
389: return rtn;
390: }
391:
392:
393: #define MAX_DRQ_WAIT (1000 * 2) // milliseconds
394:
395: -(atapi_return_t)atapiPacketCommand
396: {
397: int i;
398: atapi_return_t rtn;
399: unsigned char interruptReason;
400: unsigned char status;
401:
402: outb(_ideRegsAddrs.command, ATAPI_PACKET);
403:
404: /*
405: * Some devices might have interrupted so we should take care of that
406: * first.
407: */
408: if (_atapiCmdDrqType[_driveNum] == ATAPI_CMD_DRQ_INT)
409: {
410: rtn = [self ideWaitForInterrupt:ATAPI_PACKET ideStatus:&status];
411: }
412:
413: /*
414: * Wait till we get okay from the device.
415: */
416: for (i = 0; i < MAX_DRQ_WAIT; i++)
417: {
418: interruptReason = inb(_ideRegsAddrs.interruptReason);
419: if ((interruptReason & CMD_OR_DATA) && !(interruptReason & IO_DIRECTION))
420: break;
421: IOSleep(1);
422: }
423:
424: if (i == MAX_DRQ_WAIT)
425: {
426: IOLog("%s: ATAPI Device %d: Invalid Interrupt Reason: %x.\n",
427: [self name], _driveNum, interruptReason);
428: return IDER_ERROR;
429: }
430:
431: /*
432: * Now DRQ should be set.
433: */
434: status = inb(_ideRegsAddrs.status);
435: if (status & DREQUEST)
436: {
437: return IDER_SUCCESS;
438: }
439:
440: IOLog("%s: ATAPI Device %d: No Data Request: %x.\n",
441: [self name], _driveNum, status);
442:
443: return IDER_ERROR;
444: }
445:
446: /*
447: * Note that the command is sent out as words in little endian format.
448: */
449: - (void) sendAtapiCommand:(unsigned char *)atapiCmd
450: cmdLen:(unsigned char)len
451: {
452: int i;
453:
454: for (i = 0; i < len/2; i++)
455: {
456: outw(_ideRegsAddrs.data, (atapiCmd[2*i] << 8) | atapiCmd[2*i+1]);
457: }
458: }
459:
460: /*
461: * Prints command and result in case of error.
462: */
463: - (void)dumpStatus:(atapiIoReq_t *)atapiIoReq
464: {
465: int i;
466:
467: IOLog("%s: Failed command: drive: %d lun: %d len: %d read: %d\n",
468: [self name],
469: atapiIoReq->drive, atapiIoReq->lun, atapiIoReq->cmdLen,
470: atapiIoReq->read);
471: IOLog("%s: Failed command: ", [self name]);
472: for (i = 0; i < atapiIoReq->cmdLen; i++)
473: IOLog("%x ", atapiIoReq->atapiCmd[i]);
474: IOLog("\n");
475:
476: [self getIdeRegisters:NULL Print:"dumpStatus"];
477: }
478:
479:
480: #define C10OP_MODESELECT 0x55 /* OPT: set device parameters */
481: #define C10OP_MODESENSE 0x5a /* OPT: get device parameters */
482:
483: #define MAX_SENDPACKET_RETRIES 3
484:
485: #define MAX_BUSY_WAIT (1000*100)
486:
487: - (sc_status_t) atapiExecuteCmd:(atapiIoReq_t *)atapiIoReq
488: buffer : (void *)buffer
489: client : (struct vm_map *)client
490: {
491: int i;
492: atapi_return_t rtn;
493: unsigned int offset;
494: unsigned char dh = ADDRESS_MODE_LBA; /* ALWAYS */
495: unsigned char xferType;
496: BOOL dmaAllowed;
497:
498: /*
499: * Reject command if there are no ATAPI devices detected.
500: */
501: if ((atapiIoReq->drive >= MAX_IDE_DRIVES) || (atapiIoReq->lun != 0))
502: {
503: return SR_IOST_SELTO;
504: }
505:
506: if ([self isAtapiDevice:atapiIoReq->drive] == NO)
507: {
508: return SR_IOST_SELTO;
509: }
510:
511: [self clearInterrupts];
512:
513: _driveNum = atapiIoReq->drive;
514:
515: dmaAllowed = [self atapiDmaAllowed: buffer];
516:
517: if ( atapiIoReq->maxTransfer != 0 )
518: {
519: [self setTransferRate: _driveNum UseDMA:dmaAllowed];
520: }
521:
522: if ( _driveReset[_driveNum] == YES )
523: {
524: [self setTransferMode: _driveNum];
525: _driveReset[_driveNum] = NO;
526: }
527:
528: /* Now execute the SCSI command. */
529:
530: for (i = 0; i < MAX_SENDPACKET_RETRIES; i++)
531: {
532: rtn = [self atapiWaitReadyForPacket];
533: if (rtn != IDER_SUCCESS)
534: {
535: IOLog("%s: ATAPI Device %d: Not Ready For Packet command.\n",
536: [self name], _driveNum);
537: [self atapiSoftReset:_driveNum];
538: continue;
539: }
540:
541: /*
542: * Select the drive first.
543: */
544: dh |= _driveNum ? SEL_DRIVE1 : SEL_DRIVE0;
545: outb(_ideRegsAddrs.driveSelect, dh);
546:
547: /*
548: * Send our preferred data transfer size (2048 bytes).
549: */
550: outb(_ideRegsAddrs.byteCountLow, 0x00);
551: outb(_ideRegsAddrs.byteCountHigh, 0x08);
552:
553: /*
554: * Set data transfer mode PIO = 0x00 / DMA = 0x01
555: */
556: xferType = (dmaAllowed == YES) ? 0x01 : 0x00;
557: outb(_ideRegsAddrs.features, xferType);
558:
559: /*
560: * First tell the ATAPI device that we are going to send it a packet
561: * command. If this command fails the ATAPI device needs to be reset.
562: */
563: if ([self atapiPacketCommand] == IDER_SUCCESS)
564: {
565: break;
566: }
567:
568: IOLog("%s: ATAPI Device %d: Packet command failed. Retrying...\n",
569: [self name], _driveNum);
570: [self atapiSoftReset:_driveNum];
571: }
572:
573: /*
574: * Are we hosed?
575: */
576: if (i == MAX_SENDPACKET_RETRIES)
577: {
578: atapiIoReq->scsiStatus = STAT_CHECK;
579: IOLog("%s: ATAPI Device %d: FATAL: Packet command.\n",
580: [self name], _driveNum);
581: return SR_IOST_CMDREJ;
582: }
583:
584: /*
585: * Send the actual command to the device.
586: */
587: [self sendAtapiCommand:atapiIoReq->atapiCmd cmdLen:atapiIoReq->cmdLen];
588:
589: atapiIoReq->bytesTransferred = 0;
590: offset = 0;
591:
592: [self enableInterrupts];
593:
594: if ( dmaAllowed == YES )
595: {
596: rtn = [self atapiXferDMA:(atapiIoReq_t *)atapiIoReq buffer: (void *)buffer client: (struct vm_map *)client];
597: }
598: else
599: {
600: rtn =[self atapiXferPIO:(atapiIoReq_t *)atapiIoReq buffer: (void *)buffer client: (struct vm_map *)client];
601: }
602:
603: #if 0
604: kprintf("Disk(ATAPI): Cmd = %02x Length = %08x Addr=%08x:%08x Status = %d\n\r",
605: atapiIoReq->atapiCmd[0], (int)atapiIoReq->maxTransfer, (int)buffer, (int)client,
606: rtn);
607: #endif
608:
609: return rtn;
610: }
611:
612: - (sc_status_t) atapiXferPIO:(atapiIoReq_t *)atapiIoReq
613: buffer : (void *)buffer
614: client : (struct vm_map *)client
615: {
616: int i;
617: atapi_return_t rtn;
618: unsigned char status;
619: unsigned int bytes;
620: unsigned int offset = 0;
621: unsigned char cmd = atapiIoReq->atapiCmd[0];
622:
623: for (;;)
624: {
625: rtn = [self ideWaitForInterrupt:cmd ideStatus:&status];
626:
627: if (rtn != IDER_SUCCESS)
628: {
629: IOLog("%s: FATAL: ATAPI Device: %d Command %x failed.\n",
630: [self name], _driveNum, atapiIoReq->atapiCmd[0]);
631: [self getIdeRegisters:NULL Print:"ATAPI Command"];
632: [self atapiSoftReset:_driveNum];
633: atapiIoReq->scsiStatus = STAT_CHECK;
634: return SR_IOST_CHKSNV;
635: }
636:
637: for (i = 0; i < MAX_BUSY_WAIT; i++)
638: {
639: if (status & BUSY)
640: {
641: IODelay(10);
642: }
643: else
644: {
645: break;
646: }
647: status = inb(_ideRegsAddrs.status);
648: }
649:
650: /*
651: * If DRQ == 0 then host has terminated the command.
652: */
653: if (!(status & DREQUEST))
654: {
655: /*
656: * Check for command completion status.
657: */
658: if (status & ERROR)
659: {
660: atapiIoReq->scsiStatus = STAT_CHECK;
661: return SR_IOST_CHKSNV;
662: }
663: else
664: {
665: atapiIoReq->scsiStatus = STAT_GOOD;
666: return SR_IOST_GOOD;
667: }
668: }
669:
670: /*
671: * Command is not completed. We need to transfer data as requested by
672: * the device.
673: */
674: bytes = inb(_ideRegsAddrs.byteCountHigh) << 8 |
675: inb(_ideRegsAddrs.byteCountLow);
676:
677: /*
678: * If the device requests more data to be transferred than required
679: * by the command protocol, then we should transfer null data.
680: */
681:
682:
683: if (atapiIoReq->bytesTransferred + bytes > atapiIoReq->maxTransfer)
684: {
685: IOLog("%s: ATAPI Device %d: "
686: "ERROR: Transfer limit (%x bytes) exceeded\n",
687: [self name], _driveNum, atapiIoReq->maxTransfer);
688:
689: IOLog("%s: Bytes already transfered: %x, next request: %x\n",
690: [self name], atapiIoReq->bytesTransferred, bytes);
691:
692: [self dumpStatus: atapiIoReq];
693:
694: /*
695: * This thing is probably hosed but let's do the best we can.
696: */
697: {
698: int diff = atapiIoReq->maxTransfer-atapiIoReq->bytesTransferred;
699: IOLog("%s: Transferring %x bytes instead of %x\n",
700: [self name], diff, bytes);
701: [self xferData:buffer+offset read:atapiIoReq->read
702: client:client length:diff];
703: atapiIoReq->bytesTransferred += diff;
704: offset += diff;
705: [self atapiSoftReset:_driveNum]; // reset hardware as well
706: }
707:
708: atapiIoReq->scsiStatus = STAT_GOOD;
709: return SR_IOST_GOOD;
710: }
711:
712: /*
713: * Now transfer data from device to memory.
714: */
715: [self xferData:buffer+offset read:atapiIoReq->read client:client
716: length:bytes];
717:
718: atapiIoReq->bytesTransferred += bytes;
719: offset += bytes;
720: }
721:
722: /*
723: * Will never get here.
724: */
725: atapiIoReq->scsiStatus = STAT_GOOD;
726: return SR_IOST_GOOD;
727: }
728:
729:
730: - (sc_status_t) atapiXferDMA:(atapiIoReq_t *)atapiIoReq
731: buffer : (void *)buffer
732: client : (struct vm_map *)client
733: {
734: int i;
735: atapi_return_t rtn;
736: unsigned char status;
737: unsigned char cmd = atapiIoReq->atapiCmd[0];
738: unsigned long cfgReg;
739:
740: [self setupDMA:(vm_offset_t) buffer client:(vm_task_t) client length:(int)atapiIoReq->maxTransfer fRead:(BOOL)atapiIoReq->read];
741: if ( _controllerType != kControllerTypeCmd646X )
742: {
743: IODBDMAContinue( _ideDMARegs );
744: }
745: else
746: {
747: [[self deviceDescription] configReadLong:0x70 value: &cfgReg];
748: cfgReg &= ~0x08;
749: cfgReg |= 0x01 | ((atapiIoReq->read) ? 0x08 : 0x00);
750: [[self deviceDescription] configWriteLong:0x70 value: cfgReg];
751: }
752:
753: rtn = [self ideWaitForInterrupt:cmd ideStatus:&status];
754:
755: if (rtn != IDER_SUCCESS)
756: {
757: IOLog("%s: FATAL: ATAPI Device: %d Command %x failed.\n", [self name], _driveNum, atapiIoReq->atapiCmd[0]);
758: [self getIdeRegisters:NULL Print:"ATAPI Command"];
759: [self atapiSoftReset:_driveNum];
760: atapiIoReq->scsiStatus = STAT_CHECK;
761: return SR_IOST_CHKSNV;
762: }
763:
764: for (i = 0; i < MAX_BUSY_WAIT; i++)
765: {
766: if (status & BUSY)
767: {
768: IODelay(10);
769: }
770: else
771: {
772: break;
773: }
774: status = inb(_ideRegsAddrs.status);
775: }
776:
777: if ( _controllerType != kControllerTypeCmd646X )
778: {
779: atapiIoReq->bytesTransferred = [self stopDBDMA];
780: }
781: else
782: {
783: [[self deviceDescription] configReadLong: 0x70 value: &cfgReg];
784: cfgReg &= ~0x01;
785: [[self deviceDescription] configWriteLong:0x70 value: cfgReg];
786:
787: atapiIoReq->bytesTransferred = atapiIoReq->maxTransfer;
788: }
789:
790: /*
791: * The DMA has handled all the data movement.
792: * Must have final command status at this point.
793: */
794: if ( status & (ERROR) )
795: {
796: atapiIoReq->scsiStatus = STAT_CHECK;
797: return SR_IOST_CHKSNV;
798: }
799: else
800: {
801: atapiIoReq->scsiStatus = STAT_GOOD;
802: return SR_IOST_GOOD;
803: }
804: }
805:
806: - (BOOL) atapiDmaAllowed: (void *)buffer
807: {
808: if ( _dmaSupported[_driveNum] == NO )
809: {
810: return NO;
811: }
812:
813: if ( (_controllerType == kControllerTypeCmd646X) && ((u_int)buffer & 1) )
814: {
815: return NO;
816: }
817:
818: return YES;
819: }
820:
821:
822: @end
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.