|
|
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: /* Copyright (c) 1991-1997 NeXT Software, Inc. All rights reserved.
27: *
28: * IdeCntDma.m - Implementation for Dma category of Ide Controller device.
29: *
30: */
31:
32: #import <driverkit/generalFuncs.h>
33: #import <driverkit/kernelDriver.h>
34: #import <driverkit/ppc/IODBDMA.h>
35: #import <driverkit/align.h>
36: #import <machdep/ppc/powermac.h>
37: #import <sys/systm.h>
38:
39: #import "IdeCntDma.h"
40: #import "io_inline.h"
41:
42: extern IOReturn kmem_alloc_wired();
43:
44: static void *bitBucketAddr;
45: static uint bitBucketPhysAddr;
46:
47: @implementation IdeController(Dma)
48:
49: /*
50: * Called once during initialization to figure out if the hardware
51: * supports dma
52: */
53:
54: - (ide_return_t) initIdeDma:(unsigned int)unit
55: {
56: ideIoReq_t ideIoReq;
57: vm_offset_t tempDmaBuf;
58: ide_return_t status;
59:
60: /*
61: * The hardware claims to supports DMA. Verify that by trying to read a
62: * few sectors.
63: */
64: tempDmaBuf = (vm_offset_t)IOMalloc(PAGE_SIZE);
65: if (tempDmaBuf == NULL)
66: {
67: _dmaSupported[unit] = NO;
68: return IDER_REJECT;
69: }
70:
71: bzero((unsigned char *)&ideIoReq, sizeof(ideIoReq_t));
72: ideIoReq.cmd = IDE_READ_DMA;
73: ideIoReq.block = 0;
74: ideIoReq.blkcnt = (PAGE_SIZE/IDE_SECTOR_SIZE);
75: ideIoReq.addr = (caddr_t)tempDmaBuf;
76: ideIoReq.timeout = 5000;
77: ideIoReq.map = (struct vm_map *)IOVmTaskSelf();
78:
79: [self setTransferRate: unit UseDMA: YES];
80:
81: if ([self ideDmaRwCommon:(ideIoReq_t *)&ideIoReq] == IDER_SUCCESS)
82: {
83: status = IDER_SUCCESS;
84: }
85: else
86: {
87: _dmaSupported[unit] = NO;
88: status = IDER_REJECT;
89: }
90:
91: IOFree((void *)tempDmaBuf, PAGE_SIZE);
92:
93: return status;
94: }
95:
96: - (ide_return_t) allocDmaMemory
97: {
98: IOReturn rc;
99:
100: if ( !_ideDMACommands )
101: {
102: rc = kmem_alloc_wired(IOVmTaskSelf(), (vm_offset_t *) &_ideDMACommands, PAGE_SIZE );
103:
104: if ( rc != KERN_SUCCESS )
105: {
106: return IDER_REJECT;
107: }
108: rc = IOPhysicalFromVirtual( IOVmTaskSelf(), (vm_offset_t)_ideDMACommands, (vm_offset_t *)&_ideDMACommandsPhys );
109: if ( rc != IO_R_SUCCESS )
110: {
111: return IDER_REJECT;
112: }
113: }
114:
115: if ( !bitBucketAddr )
116: {
117: bitBucketAddr = IOMalloc(32);
118: bitBucketAddr = IOAlign(void *, bitBucketAddr, 16);
119: rc = IOPhysicalFromVirtual( IOVmTaskSelf(), (vm_offset_t) bitBucketAddr, (vm_offset_t *)&bitBucketPhysAddr );
120: if ( rc != IO_R_SUCCESS )
121: {
122: return IDER_REJECT;
123: }
124: }
125:
126: return IDER_SUCCESS;
127: }
128:
129:
130: - (ide_return_t) ideDmaRwCommon: (ideIoReq_t *)ideIoReq
131: {
132: vm_offset_t startAddr = (vm_offset_t)ideIoReq->addr;
133: unsigned blocksToGo = ideIoReq->blkcnt;
134: unsigned startBlock = ideIoReq->block;
135: ide_return_t rc = IDER_SUCCESS;
136: BOOL fRead = (ideIoReq->cmd == IDE_READ_DMA);
137:
138: /*
139: * Do read or write DMA.
140: */
141: ideIoReq->regValues = [self logToPhys:startBlock numOfBlocks:blocksToGo];
142:
143: rc = [self setupDMA: startAddr client:(vm_task_t)ideIoReq->map length:blocksToGo * IDE_SECTOR_SIZE fRead:(BOOL)fRead];
144: if ( rc != IDER_SUCCESS )
145: {
146: return ( rc );
147: }
148:
149: rc = [self ideReadWriteDma: &ideIoReq->regValues fRead:fRead];
150:
151: return(rc);
152: }
153:
154: - (ide_return_t) ideReadWriteDma:(ideRegsVal_t *)ideRegs fRead:(BOOL)read
155: {
156: ide_return_t rtn;
157: ideRegsAddrs_t *rp = &_ideRegsAddrs;
158: unsigned char status;
159: unsigned long cfgReg;
160:
161: rtn = [self waitForDeviceReady];
162: if (rtn != IDER_SUCCESS)
163: {
164: return (rtn);
165: }
166:
167: outb(rp->drHead, ideRegs->drHead);
168: outb(rp->sectNum, ideRegs->sectNum);
169: outb(rp->sectCnt, ideRegs->sectCnt);
170: outb(rp->cylLow, ideRegs->cylLow);
171: outb(rp->cylHigh, ideRegs->cylHigh);
172:
173: [self enableInterrupts];
174: outb(rp->command, (read ? IDE_READ_DMA : IDE_WRITE_DMA));
175:
176: if ( _controllerType != kControllerTypeCmd646X )
177: {
178: IODBDMAContinue( _ideDMARegs );
179: }
180: else
181: {
182: [[self deviceDescription] configReadLong:0x70 value: &cfgReg];
183: cfgReg &= ~0x08;
184: cfgReg |= 0x01 | ((read) ? 0x08 : 0x00);
185: [[self deviceDescription] configWriteLong:0x70 value: cfgReg];
186: }
187:
188: rtn = [self ideWaitForInterrupt:(read ? IDE_READ_DMA : IDE_WRITE_DMA)
189: ideStatus: &status];
190:
191: #if 0
192: {
193: uint dmaStatus;
194:
195: dmaStatus = IOGetDBDMAChannelStatus( _ideDMARegs );
196: kprintf( "DMA Status = %04x IDE Status = %02x\n\r", dmaStatus, status );
197: }
198: #endif
199:
200: if ( _controllerType != kControllerTypeCmd646X )
201: {
202: IODBDMAStop( _ideDMARegs );
203: }
204: else
205: {
206: [[self deviceDescription] configReadLong: 0x70 value: &cfgReg];
207: cfgReg &= ~0x01;
208: [[self deviceDescription] configWriteLong:0x70 value: cfgReg];
209: }
210:
211: if ( (rtn == IDER_SUCCESS) )
212: {
213: if ((rtn = [self waitForDeviceReady]) == IDER_SUCCESS)
214: {
215: if (status & (ERROR | WRITE_FAULT))
216: {
217: [self getIdeRegisters:ideRegs Print:"Read Dma error"];
218: return IDER_CMD_ERROR;
219: }
220:
221: /*
222: if (status & ERROR_CORRECTED) {
223: IOLog("%s: Error during data transfer (corrected).\n",
224: [self name]);
225: }
226: */
227: }
228: else
229: {
230: return IDER_CMD_ERROR;
231: }
232:
233: }
234: else
235: {
236: [self getIdeRegisters:ideRegs Print:NULL];
237: IODBDMAReset( _ideDMARegs );
238: return IDER_CMD_ERROR;
239: }
240:
241: return (rtn);
242: }
243:
244: /*
245: *
246: *
247: */
248: -(ide_return_t) setupDMA:(vm_offset_t) startAddr client:(vm_task_t) client length:(int)length fRead:(BOOL)fRead
249: {
250: ide_return_t rc;
251:
252: if ( _controllerType == kControllerTypeCmd646X )
253: {
254: rc = [self setupDMAList: startAddr client:client length:length fRead:fRead];
255: }
256: else
257: {
258: rc = [self setupDBDMA: startAddr client:client length:length fRead:fRead];
259: }
260: return rc;
261: }
262:
263: -(ide_return_t) setupDBDMA:(vm_offset_t) startAddr client:(vm_task_t) client length:(int)length fRead:(BOOL)fRead
264: {
265: uint count;
266: uint addr;
267: uint physAddr;
268: uint len;
269: uint bytesLeft;
270: uint i;
271: IOReturn rc;
272: uint maxDescriptors;
273:
274: /*
275: * This is for the benefit of - getTransferCount in case of a zero length transfer.
276: */
277: bzero( (unsigned char *)_ideDMACommands, sizeof(IODBDMADescriptor) );
278:
279: if ( length == 0 )
280: {
281: return IDER_SUCCESS;
282: }
283:
284: bytesLeft = length;
285: count = PAGE_SIZE - (startAddr & (PAGE_SIZE-1));
286: addr = startAddr;
287:
288: maxDescriptors = MAX_IDE_DESCRIPTORS - 1 - ((length & 1) ? 1 : 0);
289:
290: for ( i=0; i < maxDescriptors && bytesLeft; i++ )
291: {
292: len = ( count > bytesLeft ) ? bytesLeft : count;
293:
294: rc = IOPhysicalFromVirtual( client, trunc_page(addr), &physAddr );
295: if ( rc != IO_R_SUCCESS )
296: {
297: IOLog("IDE Disk - IOPhysicalFromVirtual rc = %d\n\r", rc);
298: return IDER_MEMFAIL;
299: }
300: physAddr = (physAddr & ~(PAGE_SIZE-1)) | (addr & (PAGE_SIZE-1));
301:
302: IOMakeDBDMADescriptor( &_ideDMACommands[i],
303: ((fRead) ? kdbdmaInputMore : kdbdmaOutputMore),
304: kdbdmaKeyStream0,
305: kdbdmaIntNever,
306: kdbdmaBranchNever,
307: kdbdmaWaitNever,
308: len,
309: physAddr );
310: bytesLeft -= len;
311: addr += len;
312: count = PAGE_SIZE;
313: }
314:
315: /*
316: * Note: ATAPI always transfers even byte-counts. Send the extra byte to/from the bit-bucket
317: * if the requested transfer length is odd.
318: */
319: if ( length & 1 )
320: {
321: IOMakeDBDMADescriptor( &_ideDMACommands[i++],
322: ((fRead) ? kdbdmaInputMore : kdbdmaOutputMore),
323: kdbdmaKeyStream0,
324: kdbdmaIntNever,
325: kdbdmaBranchNever,
326: kdbdmaWaitNever,
327: 1,
328: bitBucketPhysAddr );
329: }
330:
331:
332: if ( bytesLeft )
333: {
334: IOLog("IDE I/O request too large - Length = %d\n\r", length);
335: return IDER_REJECT;
336: }
337:
338: IOMakeDBDMADescriptor( &_ideDMACommands[i],
339: kdbdmaStop,
340: kdbdmaKeyStream0,
341: kdbdmaIntNever,
342: kdbdmaBranchNever,
343: kdbdmaWaitNever,
344: 0,
345: 0 );
346:
347: IOSetDBDMACommandPtr( _ideDMARegs, _ideDMACommandsPhys );
348:
349: return IDER_SUCCESS;
350: }
351:
352: -(ide_return_t) setupDMAList:(vm_offset_t) startAddr client:(vm_task_t) client length:(int)length fRead:(BOOL)fRead
353: {
354: uint count;
355: uint addr;
356: uint physAddr;
357: uint len;
358: uint bytesLeft;
359: uint i;
360: IOReturn rc;
361: uint maxDescriptors;
362: ideDMAList_t *ideDMAList;
363:
364: if ( length == 0 )
365: {
366: return IDER_SUCCESS;
367: }
368:
369: bytesLeft = length;
370: count = PAGE_SIZE - (startAddr & (PAGE_SIZE-1));
371: addr = startAddr;
372:
373: maxDescriptors = MAX_IDE_DESCRIPTORS * 2;
374:
375: ideDMAList = (ideDMAList_t *) _ideDMACommands;
376: for ( i=0; i < maxDescriptors && bytesLeft; i++ )
377: {
378: len = ( count > bytesLeft ) ? bytesLeft : count;
379:
380: rc = IOPhysicalFromVirtual( client, trunc_page(addr), &physAddr );
381: if ( rc != IO_R_SUCCESS )
382: {
383: IOLog("IDE Disk - IOPhysicalFromVirtual rc = %d\n\r", rc);
384: return IDER_MEMFAIL;
385: }
386: physAddr = (physAddr & ~(PAGE_SIZE-1)) | (addr & (PAGE_SIZE-1));
387:
388: ideDMAList[i].start = EndianSwap32( physAddr );
389: ideDMAList[i].length = EndianSwap32( len );
390:
391: bytesLeft -= len;
392: addr += len;
393: count = PAGE_SIZE;
394: }
395:
396: if ( bytesLeft )
397: {
398: IOLog("IDE I/O request too large - Length = %d\n\r", length);
399: return IDER_REJECT;
400: }
401:
402: ideDMAList[i-1].length |= EndianSwap32( 0x80000000 );
403:
404: [[self deviceDescription] configWriteLong:0x74 value: _ideDMACommandsPhys];
405:
406: return IDER_SUCCESS;
407: }
408:
409:
410: /*
411: * This routine makes sure the DMA channel has shutdown at the end of an
412: * I/O request and obtains tha actual byte count transferred.
413: */
414: - (uint) stopDBDMA
415: {
416: uint dmaStatus;
417: uint xferCount;
418:
419: dmaStatus = IOGetDBDMAChannelStatus( _ideDMARegs );
420:
421: if ( dmaStatus & (kdbdmaDead | kdbdmaActive) )
422: {
423: if ( IsPowerStar() )
424: {
425: [self fixOHareDMACorruption_1];
426: }
427: else
428: {
429: IODBDMAReset( _ideDMARegs );
430: }
431: }
432:
433: xferCount = [self getDBDMATransferCount];
434:
435: if ( dmaStatus & (kdbdmaDead | kdbdmaActive) )
436: {
437: if ( IsPowerStar() )
438: {
439: [self fixOHareDMACorruption_2];
440: }
441: }
442: return xferCount;
443: }
444:
445: /*
446: * The OHare DMA controller and its predecessor Grand Central have a nasty habit of
447: * clobbering bytes prior to the data buffer if the buffer is not 16-byte aligned.
448: *
449: * To fix this we check for a non-aligned DMA read operation and save the bytes
450: * prior to the start of the data buffer, and them restore them after the DMA channel
451: * is shutdown.
452: */
453:
454: - (void) fixOHareDMACorruption_1
455: {
456: IOReturn rc;
457: uint i;
458: uint physAddr;
459: uint virtAddr;
460: unsigned char *p;
461: BOOL resetDone = NO;
462: uint dmaOp;
463: unsigned char saveUs[16];
464: uint len;
465:
466: do
467: {
468: dmaOp = IOGetCCOperation(&_ideDMACommands[0]) >> 28;
469: if ( dmaOp != kdbdmaInputMore )
470: {
471: continue;
472: }
473:
474: physAddr = IOGetCCAddress(&_ideDMACommands[0]);
475: if ( !(physAddr & 0x0000000F) )
476: {
477: continue;
478: }
479:
480: rc = IOMapPhysicalIntoIOTask( (vm_offset_t) trunc_page(physAddr),
481: PAGE_SIZE,
482: (vm_offset_t *) &virtAddr );
483: if ( rc != IO_R_SUCCESS )
484: {
485: continue;
486: }
487:
488: p = (unsigned char *) ( (virtAddr & ~(PAGE_SIZE-1)) | (physAddr & 0xFF0) );
489: len = (physAddr & 0x00F);
490:
491: for ( i=0; i < len; i++ )
492: {
493: saveUs[i] = p[i];
494: }
495:
496: IODBDMAReset( _ideDMARegs );
497: resetDone = YES;
498:
499: for ( i=0; i < len; i++ )
500: {
501: p[i] = saveUs[i];
502: }
503:
504: IOUnmapPhysicalFromIOTask( (vm_offset_t) trunc_page(virtAddr),
505: PAGE_SIZE );
506: }
507: while( 0 );
508:
509: if ( resetDone == NO )
510: {
511: IODBDMAReset( _ideDMARegs );
512: }
513: }
514:
515:
516: /*
517: * The OHare II controller has a bug where if there is a pending DMA write operation
518: * that was not accepted by the device, it 'remembers' is and inserts an spurious
519: * DMA write to the device on the next write operation. This results in the data
520: * for the next write operation to be shifted foward by two bytes.
521: *
522: */
523:
524: - (void) fixOHareDMACorruption_2
525: {
526: uint dmaOp;
527:
528: dmaOp = IOGetCCOperation(&_ideDMACommands[0]) >> 28;
529: if ( dmaOp == kdbdmaOutputMore )
530: {
531: IOPanic("Disk(ata): IDE Hardware error - unable to recover\n\r");
532: }
533: }
534:
535: /*
536: * Calculate the actual transfer count by reading back the DMA descriptors.
537: */
538: - (uint) getDBDMATransferCount
539: {
540: uint i;
541: uint ccResult;
542: uint xferCount = 0;
543:
544: for ( i=0; i < MAX_IDE_DESCRIPTORS; i++ )
545: {
546: ccResult = IOGetCCResult( &_ideDMACommands[i] );
547:
548: if ( !(ccResult & kdbdmaStatusRun) )
549: {
550: break;
551: }
552: xferCount += (IOGetCCOperation( &_ideDMACommands[i] ) & kdbdmaReqCountMask) - (ccResult & kdbdmaResCountMask);
553: }
554: return xferCount;
555: }
556:
557: @end
558:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.