|
|
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: * AtapiCntCmds.m - ATAPI command implementation for ATA interface.
29: *
30: * HISTORY
31: *
32: * 4-Jan-1998 Joe Liu at Apple
33: * Merged the various wait routines into a single routine.
34: * Wait routine now sleeps longer to generate a more accurate wait
35: * interval.
36: * Check the BSY bit before sending the packet command.
37: * Detect shadow/phantom drives and timeout more quickly.
38: * Sprinkled some IODelays before checking the BSY bit. Since according
39: * to the spec, a drive may take up to 400ns to set the BSY bit, and
40: * we don't want to read it before it has enough time to assert itself.
41: *
42: * 3-Sep-1996 Becky Divinski at NeXT
43: * Moved LBA, IORDY, and buffer capabilities out
44: * from under DEBUG statements, so they will
45: * always print out during startup.
46: *
47: * 13-Feb-1996 Rakesh Dubey at NeXT
48: * More resistant to broken firmwares.
49: *
50: * 13-Jul-1995 Rakesh Dubey at NeXT
51: * Improved device detection and log messages.
52: *
53: * 1-Sep-1994 Rakesh Dubey at NeXT
54: * Created.
55: */
56:
57: #import "AtapiCntCmds.h"
58: #import "IdePIIX.h"
59:
60: //#define DEBUG
61:
62: /*
63: * Max timeout while waiting for BSY == 0.
64: */
65: #define ATAPI_MAX_WAIT_FOR_NOTBUSY (5 * 1000) // 5 secs
66:
67: @implementation IdeController(ATAPI)
68:
69: /*
70: * Method: atapiWaitStatusBitsFor:on:off:alt:
71: *
72: * General purpose wait routine. Wait for BSY bit in the Status/AltStatus
73: * register to clear, then make sure that the "on" bits are set, and the
74: * "off" bits are cleared in the status register.
75: *
76: * The routine busy waits for an initial count, then it uses IOSleeps to
77: * do non-blocking delays. IOSleep() has a minimum delay of around 15ms.
78: * Anything smaller will yield a longer than expected delay.
79: *
80: * Arguments:
81: * timeout - How long to wait for BSY bit to clear in milliseconds.
82: * on - Set bit mask.
83: * off - Cleared bit mask (BSY bit is implicitly checked).
84: * alt - YES to poll using AltStatus instead of Status register.
85: *
86: * Returns:
87: * IDER_SUCCESS - successful completion.
88: * IDER_TIMEOUT - timeout or bits check failed.
89: *
90: */
91:
92: #define ATAPI_WAIT_DELAYS 5 // how many initial 1ms busy waits
93: #define ATAPI_SLEEP_DURATION 20 // how long to sleep using IOSleep
94:
95: - (atapi_return_t) atapiWaitStatusBitsFor:(unsigned int)timeout
96: on:(unsigned char)on
97: off:(unsigned char)off
98: alt:(BOOL)alt
99: {
100: unsigned char status;
101: int delays = ATAPI_WAIT_DELAYS;
102:
103: if (timeout == 0)
104: return IDER_TIMEOUT;
105:
106: IODelay(1); /* give the drive 400ns to assert BSY bit */
107: do {
108: status = alt ? inb(_ideRegsAddrs.altStatus) :
109: inb(_ideRegsAddrs.status);
110: if (!(status & BUSY))
111: break;
112: if (delays-- > 0) { // use IODelay for initial wait
113: IODelay(1000); // busy-wait for 1ms
114: timeout--;
115: }
116: else { // too long, use IOSleep instead
117: int sleep_interval = ATAPI_SLEEP_DURATION;
118: if (timeout < sleep_interval)
119: sleep_interval = timeout;
120: IOSleep(sleep_interval);
121: timeout -= sleep_interval;
122: }
123: } while (timeout > 0);
124: if (timeout == 0)
125: return IDER_TIMEOUT;
126:
127: IODelay(1); /* give the drive another 400ns to update Status Register */
128: if (((status & on) == on) && ((~status & off) == off))
129: return IDER_SUCCESS;
130:
131: return IDER_TIMEOUT;
132: }
133:
134: - (void) printAtapiInfo:(ideIdentifyInfo_t *)ideIdentifyInfo
135: Device:(unsigned char)unit
136: {
137: int i;
138: char name[50];
139: char firmware[9];
140: atapiGenConfig_t *atapiGenConfig;
141: char *protocolTypeStr, *deviceTypeStr, *cmdDrqTypeStr;
142: char *removableStr, *cmdPacketSizeStr;
143:
144: // IOLog("Capability: %04x\n", ideIdentifyInfo->capabilities);
145:
146: /*
147: * Print drive name with firmware revision number after doing byte swaps.
148: */
149: for (i = 0; i < 20; i++) {
150: name[2*i] = ideIdentifyInfo->modelNumber[2*i+1];
151: name[2*i+1] = ideIdentifyInfo->modelNumber[2*i];
152: }
153: name[40] = '\0';
154:
155: for (i = 0; i < 4; i++) {
156: firmware[2*i] = ideIdentifyInfo->firmwareRevision[2*i+1];
157: firmware[2*i+1] = ideIdentifyInfo->firmwareRevision[2*i];
158: }
159: firmware[8] = '\0';
160:
161: for (i = 38; i >= 0; i--) {
162: if (name[i] != ' ')
163: break;
164: }
165: strcpy(name+i+2, firmware);
166:
167: #ifdef DEBUG
168: IOLog("%s: %s\n", [self name], name);
169: #endif DEBUG
170:
171: /*
172: * This information should be printed since it is not duplicated
173: * elsewhere.
174: */
175: atapiGenConfig = (atapiGenConfig_t *) &ideIdentifyInfo->genConfig;
176:
177: #ifdef undef
178: IOLog("%s: gen config: %x\n", [self name], ideIdentifyInfo->genConfig);
179: #endif undef
180:
181: if (atapiGenConfig->protocolType == 0 || atapiGenConfig->protocolType == 1)
182: protocolTypeStr = "ATA";
183: else if (atapiGenConfig->protocolType == 2)
184: protocolTypeStr = "ATAPI";
185: else
186: protocolTypeStr = "UNKNOWN PROTOCOL";
187:
188: if (atapiGenConfig->deviceType == 0)
189: deviceTypeStr = "DIRECT ACCESS";
190: else if (atapiGenConfig->deviceType == 5)
191: deviceTypeStr = "CD-ROM";
192: else if (atapiGenConfig->deviceType == 7)
193: deviceTypeStr = "OPTICAL";
194: else if (atapiGenConfig->deviceType == 1)
195: deviceTypeStr = "TAPE";
196: else
197: deviceTypeStr = "UNKNOWN DEVICE TYPE";
198:
199: if (atapiGenConfig->cmdDrqType == 0)
200: cmdDrqTypeStr = "SLOW DRQ";
201: else if (atapiGenConfig->cmdDrqType == 1)
202: cmdDrqTypeStr = "INTR DRQ";
203: else if (atapiGenConfig->cmdDrqType == 2)
204: cmdDrqTypeStr = "FAST DRQ";
205: else
206: cmdDrqTypeStr = "UNKNOWN DRQ TYPE";
207:
208: if (atapiGenConfig->removable == 0)
209: removableStr = "NOT REMOVABLE";
210: else if (atapiGenConfig->removable == 1)
211: removableStr = "REMOVABLE";
212:
213: if (atapiGenConfig->cmdPacketSize == 0)
214: cmdPacketSizeStr = "CMD PKT LEN=12";
215: else if (atapiGenConfig->cmdPacketSize == 1)
216: cmdPacketSizeStr = "CMD PKT LEN=16";
217: else
218: cmdPacketSizeStr = "CMD PKT LEN=UNKNOWN";
219:
220:
221: IOLog("%s: Drive %d: %s %s (%s, %s, %s)\n", [self name], unit,
222: protocolTypeStr,
223: deviceTypeStr, cmdDrqTypeStr,
224: removableStr, cmdPacketSizeStr);
225:
226: #ifdef DEBUG
227: if (ideIdentifyInfo->capabilities & IDE_CAP_LBA_SUPPORTED) {
228: IOLog("%s: LBA supported.\n", [self name]);
229: }
230: if (ideIdentifyInfo->capabilities & IDE_CAP_IORDY_SUPPORTED) {
231: IOLog("%s: IORDY supported.\n", [self name]);
232: }
233:
234: if (ideIdentifyInfo->bufferType != 0) {
235: IOLog("%s: buffer type %d, %d sectors.\n", [self name],
236: ideIdentifyInfo->bufferType, ideIdentifyInfo->bufferSize);
237: }
238:
239: IOLog("%s: PIO timing cycle: %d ns.\n", [self name],
240: ideIdentifyInfo->pioDataTransferCyleTimingMode &
241: IDE_PIO_TIMING_MODE_MASK);
242:
243: if (ideIdentifyInfo->capabilities & IDE_CAP_DMA_SUPPORTED) {
244: IOLog("%s: DMA timing cycle: %d ns.\n", [self name],
245: ideIdentifyInfo->dmaDataTransferCyleTimingMode &
246: IDE_DMA_TIMING_MODE_MASK);
247: }
248:
249: #endif DEBUG
250: }
251:
252: /*
253: * There are lots of ATAPI CD-ROMs that shadow the task file register and
254: * hence show up as two devices. They also might issue a valid interrupt when
255: * ATAPI Identify Device command is sent so we need to really make sure
256: * whether the device has data for us.
257: */
258: - (atapi_return_t) _atapiIdentifyDevice:(struct vm_map *)client
259: addr:(caddr_t)xferAddr
260: {
261: unsigned int cmd = ATAPI_IDENTIFY_DRIVE;
262: unsigned char dh = ADDRESS_MODE_LBA; /* ALWAYS */
263: unsigned char status;
264: atapi_return_t rtn;
265:
266: unsigned int oldTimeout;
267:
268: #ifdef DEBUG
269: IOLog("ATAPI Identify Device\n");
270: #endif DEBUG
271:
272: rtn = [self atapiWaitStatusBitsFor:ATAPI_MAX_WAIT_FOR_NOTBUSY
273: on:0 off:0 alt:NO];
274: if (rtn != IDER_SUCCESS)
275: return (rtn);
276:
277: dh |= _driveNum ? SEL_DRIVE1 : SEL_DRIVE0;
278: outb(_ideRegsAddrs.driveSelect, dh);
279:
280: bzero(xferAddr, IDE_SECTOR_SIZE);
281:
282: [self enableInterrupts];
283: [self clearInterrupts];
284:
285: outb(_ideRegsAddrs.command, ATAPI_IDENTIFY_DRIVE);
286:
287: /* Wait for BSY bit to clear before reading from AltStatus.
288: * We do this to avoid a long interrupt timeout when probing
289: * "phantom" CD-ROM drives shadowed by another device on the same
290: * IDE connector.
291: /* Read from AltStatus instead of Status register to avoid
292: * ack'ing any pending interrupts.
293: */
294: rtn = [self atapiWaitStatusBitsFor:ATAPI_MAX_WAIT_FOR_NOTBUSY
295: on:0 off:0 alt:YES];
296: if (rtn != IDER_SUCCESS) {
297: IOLog("%s: Polling BSY bit timed-out\n", [self name]);
298: return (rtn);
299: }
300:
301: /* Shadow (false) devices should set the ABORT bit in the ATA
302: * Error register. We check for ABORT bit and return an error
303: * if that bit is set.
304: */
305: if ((inb(_ideRegsAddrs.altStatus) & ERROR) &&
306: (inb(_ideRegsAddrs.error) & CMD_ABORTED)) {
307: // Don't bother waiting for an interrupt, abort immediately.
308: #ifdef DEBUG
309: IOLog("%s: Phantom ATAPI drive detected. Status:0x%02x\n",
310: [self name], inb(_ideRegsAddrs.altStatus));
311: #endif DEBUG
312: return IDER_ERROR;
313: }
314:
315: oldTimeout = [self interruptTimeOut];
316: [self setInterruptTimeOut:4000]; // four seconds
317: rtn = [self ideWaitForInterrupt:cmd ideStatus:&status];
318: [self setInterruptTimeOut:oldTimeout];
319:
320: if (rtn != IDER_SUCCESS) {
321: [self getIdeRegisters:NULL Print:"Atapi Identify"];
322: return (rtn);
323: }
324:
325: // Make sure DRQ is set
326: rtn = [self atapiWaitStatusBitsFor:ATAPI_MAX_WAIT_FOR_NOTBUSY
327: on:DREQUEST off:0 alt:NO];
328: if (rtn != IDER_SUCCESS)
329: return (rtn);
330:
331: /*
332: * FIXME: We need to do some sanity check on this data to be really sure
333: * that there is an ATAPI device out here.
334: */
335: [self xferData:xferAddr read:YES client:client length:IDE_SECTOR_SIZE];
336: return IDER_SUCCESS;
337: }
338:
339: /*
340: * Some CD-ROMS (like SONY CDU-55D) fail the first request so we reset the
341: * device and retry.
342: */
343: #define ATAPI_IDENTIFY_DEVICE_RETRIES 3
344:
345: - (atapi_return_t) atapiIdentifyDevice:(struct vm_map *)client
346: addr:(caddr_t)xferAddr
347: unit:(unsigned char)unit
348: {
349: int i;
350: atapi_return_t ret;
351:
352: for (i = 0; i < ATAPI_IDENTIFY_DEVICE_RETRIES; i++) {
353:
354: ret = [self _atapiIdentifyDevice:client addr:xferAddr];
355: if (ret == IDER_SUCCESS)
356: break;
357:
358: /* Reset hardware and try again */
359: [self atapiSoftReset:unit];
360: IOSleep(500);
361: if (_ide_debug) {
362: IOLog("%s: Drive %d: ATAPI Identify Device failed "
363: "(error %d). Retrying..\n", [self name], unit, ret);
364: }
365: }
366: #ifdef DEBUG
367: if (i == ATAPI_IDENTIFY_DEVICE_RETRIES) {
368: IOLog("%s: FATAL: Drive %d: ATAPI Identify Device.\n",
369: [self name], unit);
370: }
371: #endif DEBUG
372: return ret;
373: }
374:
375: - (void) atapiInitParameters:(ideIdentifyInfo_t *)infoPtr
376: Device:(unsigned char)unit
377: {
378: atapiGenConfig_t *atapiGenConfig =
379: (atapiGenConfig_t *) &infoPtr->genConfig;
380:
381: if (atapiGenConfig->cmdPacketSize == 0x01)
382: _drives[unit].atapiCmdLen = 16;
383: else
384: _drives[unit].atapiCmdLen = 12;
385:
386: /*
387: * The command len is 12. However some devices think it is 16 which is
388: * actually reserved for SAM compatibility. See page 58, SFF 8020, rev
389: * 1.2. This is a workaround.
390: */
391: if (_drives[unit].atapiCmdLen != 12) {
392: IOLog("%s: ATAPI: command len changed to 12 from %d.\n",
393: [self name], _drives[unit].atapiCmdLen);
394: _drives[unit].atapiCmdLen = 12;
395: }
396:
397: _drives[unit].atapiCmdDrqType = atapiGenConfig->cmdDrqType;
398: }
399:
400: /*
401: * Identify ATAPI device must have been executed first before callling this
402: * method.
403: */
404: - (unsigned char) atapiCommandPacketSize:(unsigned char)unit
405: {
406: if (unit < MAX_IDE_DRIVES)
407: return _drives[unit].atapiCmdLen;
408: else
409: return 0;
410: }
411:
412:
413: /*
414: * The amount of time in milliseconds it takes for an ATAPI device to post
415: * its signature after a reset. Some CD-ROMs take a long time to respond. Do
416: * not decrease it without testing with various makes of ATAPI devices.
417: */
418: #define ATAPI_RESET_DELAY 2500
419:
420: - (atapi_return_t) atapiSoftReset:(unsigned char)unit
421: {
422: unsigned char dh = ADDRESS_MODE_LBA; /* ALWAYS */
423:
424: #ifdef DEBUG
425: IOLog("%s: atapiSoftReset:device %d\n", [self name], unit);
426: #endif DEBUG
427:
428: dh |= unit ? SEL_DRIVE1 : SEL_DRIVE0;
429:
430: outb(_ideRegsAddrs.driveSelect, dh);
431: outb(_ideRegsAddrs.command, ATAPI_SOFT_RESET);
432:
433: IOSleep(50); /* Enough time to assert busy */
434:
435: if ([self atapiWaitStatusBitsFor:ATAPI_RESET_DELAY on:0 off:0 alt:NO] ==
436: IDER_SUCCESS)
437: return IDER_SUCCESS;
438:
439: #ifdef DEBUG
440: IOLog("%s: atapiSoftReset: FAILED. Status = %x\n", [self name], status);
441: #endif DEBUG
442:
443: return IDER_ERROR;
444: }
445:
446: /*
447: * Method: issuePacketCommand
448: *
449: * This method will issue the Packet Command code (0xA0) to the command
450: * register. Then wait for an interrupt (INT DRQ devices only) and poll
451: * the Ireason/Status for:
452: *
453: * BSY = 0
454: * CoD = 1
455: * IO = 0
456: *
457: * We assume that the task file has been initialized prior to calling
458: * this method.
459: *
460: * Returns:
461: * IDER_SUCCESS - DRQ is set and ready to send the 12-byte command.
462: * IDER_ERROR - Abort and send a ATAPI soft reset.
463: */
464: #define MAX_DRQ_WAIT (100 * 1000 * 5) // 5 second wait
465:
466: - (atapi_return_t) issuePacketCommand
467: {
468: int i;
469: unsigned char interruptReason;
470: unsigned char status;
471:
472: #ifdef DEBUG
473: IOLog("%s: issuePacketCommand\n", [self name]);
474: #endif DEBUG
475:
476: /*
477: * Send the packet command.
478: */
479: outb(_ideRegsAddrs.command, ATAPI_PACKET);
480:
481: /*
482: * Some devices might have interrupted so we should take care of that
483: * first.
484: */
485: if (_drives[_driveNum].atapiCmdDrqType == ATAPI_CMD_DRQ_INT) {
486: atapi_return_t rtn;
487: rtn = [self ideWaitForInterrupt:ATAPI_PACKET ideStatus:&status];
488: if (rtn != IDER_SUCCESS)
489: return rtn;
490: }
491:
492: /*
493: * Wait till we get okay from the device.
494: */
495: IODelay(1);
496: for (i = 0; i < MAX_DRQ_WAIT; i++) {
497: interruptReason = inb(_ideRegsAddrs.interruptReason);
498: status = inb(_ideRegsAddrs.status);
499:
500: if (!(status & BUSY) &&
501: (interruptReason & CMD_OR_DATA) &&
502: !(interruptReason & IO_DIRECTION))
503: break;
504: IODelay(10);
505: }
506:
507: if (i == MAX_DRQ_WAIT) {
508: IOLog("%s: ATAPI Drive %d: Invalid Interrupt Reason: %x.\n",
509: [self name], _driveNum, interruptReason);
510: return IDER_ERROR;
511: }
512:
513: /*
514: * Now DRQ should be set.
515: */
516: status = inb(_ideRegsAddrs.status);
517: if (status & DREQUEST) {
518: return IDER_SUCCESS;
519: }
520:
521: IOLog("%s: ATAPI Drive %d: DRQ not set: %x\n",
522: [self name], _driveNum, status);
523: return IDER_ERROR;
524: }
525:
526: /*
527: * Method: sendAtapiCommand:cmdLen:
528: *
529: * Send the ATAPI command packet bytes.
530: * Note that the command is sent out as words in little endian format.
531: */
532: - (void) sendAtapiCommand:(unsigned char *)atapiCmd
533: cmdLen:(unsigned char)len
534: {
535: int i;
536:
537: for (i = 0; i < len/2; i++) {
538: outw(_ideRegsAddrs.data, atapiCmd[2*i+1] << 8 | atapiCmd[2*i]);
539: }
540: }
541:
542: #define MAX_SENDPACKET_RETRIES 3
543: #define MAX_BUSY_WAIT (1000*100)
544:
545: /*
546: * Transfer data between host and the ATAPI device through PIO.
547: *
548: * Before calling this method, the packet command and command data bytes
549: * have been issued to the drive. This method will transfer data until
550: * DRQ = 0, or if the maximum transfer count is reached, whichever
551: * occurs first. This method will require an interrupt for every iteration
552: * of the loop.
553: */
554: - (sc_status_t) atapiPIODataTransfer:(atapiIoReq_t *)atapiIoReq
555: buffer:(void *)buffer
556: client:(struct vm_map *)client
557: {
558: int i;
559: atapi_return_t rtn;
560: unsigned char status;
561: unsigned int offset;
562: unsigned char cmd = atapiIoReq->atapiCmd[0];
563: unsigned int bytes;
564:
565: /*
566: * Zero the counters.
567: */
568: atapiIoReq->bytesTransferred = 0;
569: offset = 0;
570:
571: for (;;) {
572:
573: /* At this point, the drive is executing the packet command.
574: * For commands such as FORMAT_UNIT (0x04), the may take a very
575: * long time. Probably much longer than IDE_INTR_TIMEOUT.
576: *
577: * To guard against those cases, we take the maximum of
578: * IDE_INTR_TIMEOUT vs. scsiReq.timeout.
579: */
580: if (atapiIoReq->timeout > IDE_INTR_TIMEOUT) {
581: u_int current_timeout = [self interruptTimeOut];
582:
583: //IOLog("using SCSI timeout:%d\n", atapiIoReq->timeout);
584: [self setInterruptTimeOut:atapiIoReq->timeout];
585: rtn = [self ideWaitForInterrupt:cmd ideStatus:&status];
586: [self setInterruptTimeOut:current_timeout];
587: }
588: else {
589: rtn = [self ideWaitForInterrupt:cmd ideStatus:&status];
590: }
591:
592: if (rtn != IDER_SUCCESS) {
593: IOLog("%s: FATAL: ATAPI Drive: %d Command %x failed.\n",
594: [self name], _driveNum, atapiIoReq->atapiCmd[0]);
595: [self getIdeRegisters:NULL Print:"ATAPI Command"];
596: [self atapiSoftReset:_driveNum];
597: atapiIoReq->scsiStatus = STAT_CHECK;
598: return SR_IOST_CHKSNV;
599: }
600:
601: /*
602: * This is stupid but the Chinon drive fires off an interrupt first
603: * and then updates the status register. It appears that any drive
604: * based on Western Digital chipset will do this. At any rate, this
605: * code is harmless and should be left here.
606: */
607: for (i = 0; i < MAX_BUSY_WAIT; i++) {
608: if (status & BUSY)
609: IODelay(10);
610: else
611: break;
612: status = inb(_ideRegsAddrs.status);
613: }
614:
615: /*
616: * If DRQ == 0 then host has terminated the command.
617: */
618: if (!(status & DREQUEST)) {
619: /*
620: * Check for command completion status.
621: */
622: if (status & ERROR) {
623: #ifdef DEBUG
624: // Don't complain for TEST UNIT READY command
625: if (cmd != 0x00) {
626: [self dumpStatus: atapiIoReq];
627: }
628: IOLog("%s: ATAPI command %x failed. "
629: "Error: %x Status: %x\n", [self name],
630: atapiIoReq->atapiCmd[0],
631: inb(_ideRegsAddrs.error), status);
632: #endif DEBUG
633:
634: atapiIoReq->scsiStatus = STAT_CHECK;
635: return SR_IOST_CHKSNV;
636: }
637: else {
638: #ifdef DEBUG
639: IOLog("%s: Comamnd %x completed. status %x\n",
640: [self name], atapiIoReq->atapiCmd[0], status);
641: #endif DEBUG
642: atapiIoReq->scsiStatus = STAT_GOOD;
643: return SR_IOST_GOOD;
644: }
645: }
646:
647: /*
648: * Command is not completed. We need to transfer data as requested by
649: * the device.
650: */
651: bytes = inb(_ideRegsAddrs.byteCountHigh) << 8 |
652: inb(_ideRegsAddrs.byteCountLow);
653:
654: #ifdef DEBUG
655: IOLog("%s: ATAPI Drive %d: completed: %x, request: %x max: %x\n",
656: [self name], _driveNum, atapiIoReq->bytesTransferred,
657: bytes, atapiIoReq->maxTransfer);
658: #endif DEBUG
659:
660: /*
661: * If the device requests more data to be transferred than required
662: * by the command protocol, then we should transfer null data.
663: */
664:
665: if (atapiIoReq->bytesTransferred + bytes > atapiIoReq->maxTransfer) {
666:
667: IOLog("%s: ATAPI Drive %d: "
668: "ERROR: Transfer limit (%x bytes) exceeded\n",
669: [self name], _driveNum, atapiIoReq->maxTransfer);
670:
671: IOLog("%s: Bytes already transfered: %x, next request: %x\n",
672: [self name], atapiIoReq->bytesTransferred, bytes);
673:
674: [self dumpStatus: atapiIoReq];
675:
676: /*
677: * This thing is probably hosed but let's do the best we can.
678: */
679: {
680: int diff = atapiIoReq->maxTransfer-atapiIoReq->bytesTransferred;
681: IOLog("%s: Transferring %x bytes instead of %x\n",
682: [self name], diff, bytes);
683: [self xferData:buffer+offset read:atapiIoReq->read
684: client:client length:diff];
685: atapiIoReq->bytesTransferred += diff;
686: offset += diff;
687: [self atapiSoftReset:_driveNum]; // reset hardware as well
688: }
689:
690: atapiIoReq->scsiStatus = STAT_GOOD;
691: return SR_IOST_GOOD;
692: #if 0
693: /* this was old behavior */
694: atapiIoReq->scsiStatus = STAT_CHECK;
695: return SR_IOST_CMDREJ;
696: #endif 0
697: }
698:
699: /*
700: * Now transfer data between device and memory.
701: */
702: [self xferData:buffer+offset read:atapiIoReq->read client:client
703: length:bytes];
704:
705: atapiIoReq->bytesTransferred += bytes;
706: offset += bytes;
707: }
708:
709: /*
710: * Will never get here.
711: */
712: atapiIoReq->scsiStatus = STAT_GOOD;
713: return SR_IOST_GOOD;
714: }
715:
716: /*
717: * Prints command and result in case of error.
718: */
719: - (void) dumpStatus:(atapiIoReq_t *)atapiIoReq
720: {
721: int i;
722:
723: IOLog("%s: Failed command: drive: %d lun: %d len: %d read: %d\n",
724: [self name],
725: atapiIoReq->drive, atapiIoReq->lun, atapiIoReq->cmdLen,
726: atapiIoReq->read);
727: IOLog("%s: Failed command: ", [self name]);
728: for (i = 0; i < atapiIoReq->cmdLen; i++)
729: IOLog("%x ", atapiIoReq->atapiCmd[i]);
730: IOLog("\n");
731:
732: [self getIdeRegisters:NULL Print:"dumpStatus"];
733: }
734:
735: /*
736: * Execute the ATAPI command specified in 'atapiIoReq'.
737: */
738: - (sc_status_t) atapiExecuteCmd:(atapiIoReq_t *)atapiIoReq
739: buffer : (void *)buffer
740: client : (struct vm_map *)client
741: {
742: int i;
743: atapi_return_t rtn;
744: unsigned char dh = ADDRESS_MODE_LBA; /* ALWAYS */
745: sc_status_t sc_ret;
746: unsigned char cmd = atapiIoReq->atapiCmd[0];
747: BOOL useDMA = NO;
748:
749: /*
750: * Reject command if there are no ATAPI devices detected.
751: */
752: if ((atapiIoReq->drive >= MAX_IDE_DRIVES) ||
753: (atapiIoReq->lun != 0) ||
754: ([self isAtapiDevice:atapiIoReq->drive] == NO)) {
755: return SR_IOST_SELTO;
756: }
757:
758: /* Now execute the SCSI command. */
759:
760: #ifdef DEBUG
761: /* Print out the command received. */
762: IOLog("%s: atapiExecuteCmd: drive: %d lun: %d len: %d read %d\n",
763: [self name], atapiIoReq->drive, atapiIoReq->lun, atapiIoReq->cmdLen,
764: atapiIoReq->read);
765: IOLog("%s: Command: ", [self name]);
766: if (atapiIoReq->atapiCmd[4] == 0x41)
767: atapiIoReq->atapiCmd[4] = 0x24;
768: for (i = 0; i < atapiIoReq->cmdLen; i++)
769: IOLog("%x ", atapiIoReq->atapiCmd[i]);
770: IOLog("\n");
771: //IOBreakToDebugger();
772: #endif DEBUG
773:
774: _driveNum = atapiIoReq->drive;
775:
776: /*
777: * We are very particular on the type of commands that we allow
778: * DMA to be used.
779: *
780: * 1. It must be a Read/Write data command.
781: * 2. Buffer must be 4-byte aligned.
782: # 3. The drive must be DMA capable.
783: */
784: useDMA = ((_drives[_driveNum].transferType != IDE_TRANSFER_PIO) &&
785: (((vm_offset_t)buffer & (PIIX_BUF_ALIGN - 1)) == 0) &&
786: ((cmd == 0x28) || (cmd == 0xa8) || // read 10 and read 12
787: (cmd == 0x2a) || (cmd == 0xaa) || // write 10 and write 12
788: (cmd == 0x2f) || (cmd == 0x2e))); // write and verify
789:
790: for (i = 0; i < MAX_SENDPACKET_RETRIES; i++) {
791:
792: /*
793: * Select the drive. Make sure the BSY bit is off before
794: * changing the drv bit.
795: */
796: [self atapiWaitStatusBitsFor:ATAPI_MAX_WAIT_FOR_NOTBUSY
797: on:0 off:0 alt:NO];
798: dh |= _driveNum ? SEL_DRIVE1 : SEL_DRIVE0;
799: outb(_ideRegsAddrs.driveSelect, dh);
800:
801: /*
802: * Wait for BSY = 0, DRQ = 0.
803: */
804: rtn = [self atapiWaitStatusBitsFor:ATAPI_MAX_WAIT_FOR_NOTBUSY
805: on:0 off:DREQUEST alt:NO];
806: if (rtn != IDER_SUCCESS) {
807: IOLog("%s: ATAPI Drive %d: Not Ready For Packet command.\n",
808: [self name], _driveNum);
809: [self atapiSoftReset:_driveNum];
810: continue;
811: }
812:
813: /*
814: * Send our preferred data transfer size (2048 bytes).
815: */
816: outb(_ideRegsAddrs.byteCountLow, 0x00);
817: outb(_ideRegsAddrs.byteCountHigh, 0x08);
818:
819: /*
820: * We will use PIO for data transfers.
821: */
822: if (useDMA == YES)
823: outb(_ideRegsAddrs.features, 1);
824: else
825: outb(_ideRegsAddrs.features, 0);
826:
827: [self enableInterrupts];
828: [self clearInterrupts];
829:
830: /*
831: * First tell the ATAPI device that we are going to send it a packet
832: * command. If this command fails the ATAPI device needs to be reset.
833: */
834: if ([self issuePacketCommand] == IDER_SUCCESS) {
835: break;
836: }
837:
838: IOLog("%s: ATAPI Drive %d: Packet command failed. Retrying...\n",
839: [self name], _driveNum);
840: [self atapiSoftReset:_driveNum];
841: }
842:
843: /*
844: * Are we hosed?
845: */
846: if (i == MAX_SENDPACKET_RETRIES) {
847: atapiIoReq->scsiStatus = STAT_CHECK;
848: IOLog("%s: ATAPI Drive %d: FATAL: Packet command.\n",
849: [self name], _driveNum);
850: return SR_IOST_CMDREJ;
851: }
852:
853: // [self clearInterrupts];
854:
855: /*
856: * Send the ATAPI command packet bytes (usually 12-bytes) to the device.
857: */
858: [self sendAtapiCommand:atapiIoReq->atapiCmd cmdLen:atapiIoReq->cmdLen];
859:
860: /*
861: * Peform data transfer (if any) and return the result code.
862: */
863: if (useDMA == YES)
864: sc_ret = [self performATAPIDMA:atapiIoReq buffer:buffer client:client];
865: else
866: sc_ret = [self atapiPIODataTransfer:atapiIoReq buffer:buffer
867: client:client];
868:
869: return sc_ret;
870: }
871:
872: #if 0
873: #define ATAPI_SET_CDROM_SPEED 0xbb
874:
875: /*
876: * Doesn't seem to make any difference.
877: */
878: - (void)setMaxSpeedForATAPICDROM:(unsigned char)unit
879: {
880: atapiIoReq_t atapiIoReq;
881:
882: bzero(&atapiIoReq, sizeof(atapiIoReq_t));
883:
884: atapiIoReq.cmdLen = [self atapiCommandPacketSize:unit];
885: atapiIoReq.drive = unit;
886:
887: atapiIoReq.atapiCmd[0] = ATAPI_SET_CDROM_SPEED;
888: atapiIoReq.atapiCmd[2] = 0xff;
889: atapiIoReq.atapiCmd[3] = 0xff;
890:
891: (void) [self atapiExecuteCmd:&atapiIoReq
892: buffer:NULL client:(struct vm_map *)IOVmTaskSelf()];
893: }
894: #endif 0
895:
896: @end
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.