|
|
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: /*
26: * Copyright 1997-1998 by Apple Computer, Inc., All rights reserved.
27: * Copyright 1994-1997 NeXT Software, Inc., All rights reserved.
28: *
29: * ATADiskInternal.m - internal IDE/ATA disk methods.
30: *
31: * HISTORY
32: *
33: * 04-Mar-1996 Rakesh Dubey at NeXT
34: * Modified so that no memory is allocated at run-time.
35: *
36: * 07-Jul-1994 Rakesh Dubey at NeXT
37: * Created from original driver written by David Somayajulu.
38: */
39:
40: #import <driverkit/return.h>
41: #import <driverkit/driverTypes.h>
42: #import "ATADiskInternal.h"
43: #import "ATADiskKernel.h"
44: #import <driverkit/kernelDiskMethods.h>
45: #import <driverkit/generalFuncs.h>
46: #import <machkit/NXLock.h>
47: #import <driverkit/align.h>
48: #import <sys/systm.h>
49:
50: IOReturn iderToIo(ide_return_t);
51:
52: //#define DEBUG
53:
54: @implementation ATADisk(Internal)
55:
56: /*
57: * Print information about the disk and fill up the ideDriveName field.
58: */
59: -(void)printInfo:(ideIdentifyInfo_t *)ideIdentifyInfo unit:(unsigned int)unit
60: {
61: int i;
62: char name[50];
63: char firmware[9];
64:
65: /*
66: * Print drive name with firmware revision number after doing byte swaps.
67: */
68: for (i = 0; i < 20; i++) {
69: name[2*i] = ideIdentifyInfo->modelNumber[2*i+1];
70: name[2*i+1] = ideIdentifyInfo->modelNumber[2*i];
71: }
72: name[40] = '\0';
73:
74: for (i = 0; i < 4; i++) {
75: firmware[2*i] = ideIdentifyInfo->firmwareRevision[2*i+1];
76: firmware[2*i+1] = ideIdentifyInfo->firmwareRevision[2*i];
77: }
78: firmware[8] = '\0';
79:
80: for (i = 38; i >= 0; i--) {
81: if (name[i] != ' ')
82: break;
83: }
84: strcpy(name+i+2, firmware);
85:
86:
87: IOLog("%s: %s\n", [self name], name);
88:
89: /*
90: * The drive name is limited to 32 characters and we don't want firmware
91: * version in there.
92: */
93: name[i+1] = '\0'; name[31] = '\0';
94: strcpy(_ideDriveName, name);
95:
96: /*
97: * Other diagnostic information. All of this can also be obtained via
98: * /usr/etc/idemodes
99: */
100: #if 0
101: IOLog("%s: PIO timing cycle: %d ns (mode %d).\n", [self name],
102: ideIdentifyInfo->pioDataTransferCyleTimingMode &
103: IDE_PIO_TIMING_MODE_MASK,
104: [_cntrlr getTransferModeFromCycleTime:ideIdentifyInfo
105: transferType:IDE_TRANSFER_PIO]);
106:
107: if (ideIdentifyInfo->capabilities & IDE_CAP_DMA_SUPPORTED) {
108: IOLog("%s: DMA timing cycle: %d ns (mode %d).\n", [self name],
109: ideIdentifyInfo->dmaDataTransferCyleTimingMode &
110: IDE_DMA_TIMING_MODE_MASK,
111: [_cntrlr getTransferModeFromCycleTime:ideIdentifyInfo
112: transferType:IDE_TRANSFER_SW_DMA]);
113: }
114: if (ideIdentifyInfo->capabilities & IDE_CAP_LBA_SUPPORTED) {
115: IOLog("%s: LBA supported.\n", [self name]);
116: }
117: if (ideIdentifyInfo->capabilities & IDE_CAP_IORDY_SUPPORTED) {
118: IOLog("%s: IORDY supported.\n", [self name]);
119: }
120:
121: if (ideIdentifyInfo->bufferType != 0) {
122: IOLog("%s: buffer type %d of %d sectors.\n", [self name],
123: ideIdentifyInfo->bufferType, ideIdentifyInfo->bufferSize);
124: }
125: #endif
126: }
127:
128: /*
129: * Device-specific initialization. We just do enough here to do some I/O and
130: * to find out if the requested drive is present. This function is "reusable"
131: * for a given instance of ATADisk; initResources must have been called
132: * exactly once prior to any use of this method. Returns YES if drive is
133: * present, else NO.
134: */
135: - (BOOL)ideDiskInit:(unsigned int)diskUnit target:(unsigned int)unit
136: {
137: char dev_name[10];
138: unsigned total_sectors;
139: ideIdentifyInfo_t *ideIdentifyInfo;
140: #ifdef NO_ATA_RUNTIME_MEMORY_ALLOCATION
141: int i;
142: ideBuf_t *ideBuf;
143: #endif NO_ATA_RUNTIME_MEMORY_ALLOCATION
144:
145:
146: queue_init(&_ioQueueDisk);
147: queue_init(&_ioQueueNodisk);
148:
149:
150: #ifdef NO_ATA_RUNTIME_MEMORY_ALLOCATION
151:
152: /* Set up a queue of ideBufs */
153: queue_init(&_ideBufQueue);
154: _ideBufLock = [NXLock new];
155: [_ideBufLock lock];
156:
157:
158: for (i = 0; i < MAX_NUM_ATABUF; i++) {
159: ideBuf = &_ideBufPool[i];
160: ideBuf->waitLock = [NXConditionLock alloc];
161: [ideBuf->waitLock initWith:NO];
162: queue_enter(&_ideBufQueue, ideBuf, ideBuf_t *, bufLink);
163: }
164: [_ideBufLock unlock];
165:
166: #if 0 // XXX
167: if (_ide_debug) {
168: IOLog("NO_ATA_RUNTIME_MEMORY_ALLOCATION\n");
169: }
170: #endif
171:
172: #endif NO_ATA_RUNTIME_MEMORY_ALLOCATION
173:
174: _driveNum = unit;
175:
176: /* Skip ATAPI devices. */
177: if ([_cntrlr isAtapiDevice:unit] == YES) {
178: return NO;
179: }
180:
181: _ideInfo = *[_cntrlr getIdeDriveInfo:unit];
182: if (_ideInfo.type == 0) {
183: //IOLog("ATADisk: Bogus info for disk %d target %d.\n", diskUnit, unit);
184: return NO;
185: }
186:
187: sprintf(dev_name, "hd%d", diskUnit);
188: [self setUnit:diskUnit];
189: [self setName:dev_name];
190:
191: ideIdentifyInfo = [_cntrlr getIdeIdentifyInfo:unit];
192: [self printInfo:ideIdentifyInfo unit:unit];
193:
194: /*
195: * Cache optimal data transfer command.
196: */
197:
198: if ([_cntrlr getMultiSectorValue:unit] > 0)
199: {
200: _ideReadCommandPIO = IDE_READ_MULTIPLE;
201: _ideWriteCommandPIO = IDE_WRITE_MULTIPLE;
202: }
203: else
204: {
205: _ideReadCommandPIO = IDE_READ;
206: _ideWriteCommandPIO = IDE_WRITE;
207: }
208:
209: if ( [_cntrlr isDmaSupported:unit] )
210: {
211: IOLog("%s: using DMA transfers.\n", [self name]);
212: _ideReadCommand = IDE_READ_DMA;
213: _ideWriteCommand = IDE_WRITE_DMA;
214: }
215: else
216: {
217: IOLog("%s: using PIO transfers.\n", [self name]);
218: _ideReadCommand = _ideReadCommandPIO;
219: _ideWriteCommand = _ideWriteCommandPIO;
220: }
221:
222: _ideControllerType = [_cntrlr getControllerType];
223:
224: if ([self initIdeDrive] != IO_R_SUCCESS) {
225: return NO;
226: }
227:
228: total_sectors = _ideInfo.total_sectors;
229:
230: [self setRemovable:NO];
231: [self setBlockSize:_ideInfo.bytes_per_sector];
232: [self setDiskSize:total_sectors];
233: [self setFormattedInternal:YES];
234: [self setLastReadyState: IO_Ready];
235:
236: if (_ideDriveName[0] == '\0') {
237: sprintf(_ideDriveName, "IDE Drive Type %d", _ideInfo.type);
238: }
239: [self setDriveName:_ideDriveName];
240:
241: [super init];
242:
243: return YES;
244: }
245:
246: /*
247: * One-time only initialization. We have only one thread per disk since ATA
248: * disks do not support command queueing.
249: */
250: #ifdef DEBUG
251: void *ideThreadPtr;
252: #endif DEBUG
253:
254: - initResources : controller
255: {
256: _cntrlr = controller;
257: _ioQLock = [NXConditionLock alloc];
258: [_ioQLock initWith:NO_WORK_AVAILABLE];
259: #ifdef DEBUG
260: ideThreadPtr = IOForkThread((IOThreadFunc)ideThread, self);
261: #else DEBUG
262: IOForkThread((IOThreadFunc)ideThread, self);
263: #endif DEBUG
264: return self;
265: }
266:
267: /*
268: * Free up local resources.
269: */
270: - free
271: {
272: /*
273: * First kill the I/O thread, then free alloc'd instance variables.
274: */
275: ideBuf_t *ideBuf;
276: int i;
277:
278: ideBuf = [self allocIdeBuf:NULL];
279: ideBuf->command = IDEC_THREAD_ABORT;
280: ideBuf->buf = NULL;
281: ideBuf->needsDisk = 0;
282: ideBuf->oneWay = 0;
283: [self enqueueIdeBuf:ideBuf];
284:
285: [self freeIdeBuf:ideBuf];
286: [_ioQLock free];
287:
288: #ifdef NO_ATA_RUNTIME_MEMORY_ALLOCATION
289: if (_ideBufLock)
290: [_ideBufLock free];
291:
292: for (i = 0; i < MAX_NUM_ATABUF; i++) {
293: if (_ideBufPool[i].waitLock)
294: [_ideBufPool[i].waitLock free];
295: }
296: #endif NO_ATA_RUNTIME_MEMORY_ALLOCATION
297:
298: return ([super free]);
299: }
300:
301: /*
302: * Allocate and free IdeBuf_t's.
303: */
304:
305: #ifdef NO_ATA_RUNTIME_MEMORY_ALLOCATION
306: - (ideBuf_t *) allocIdeBuf:(void *)pending
307: {
308: ideBuf_t *ideBuf;
309: id waitLock;
310:
311: while (1) {
312: [_ideBufLock lock];
313: if (!queue_empty(&_ideBufQueue))
314: break;
315: [_ideBufLock unlock];
316: IOSleep(10); // the system is overloaded
317: }
318:
319: ASSERT(queue_empty(&_ideBufQueue) != 0);
320: ideBuf = (ideBuf_t *) queue_first(&_ideBufQueue);
321: ASSERT(ideBuf != 0);
322: queue_remove(&_ideBufQueue, ideBuf, ideBuf_t *, bufLink);
323:
324: waitLock = ideBuf->waitLock;
325: bzero(ideBuf, sizeof(ideBuf_t));
326: ideBuf->waitLock = waitLock;
327: [ideBuf->waitLock initWith:NO];
328:
329: if (pending != NULL)
330: ideBuf->pending = pending;
331:
332: [_ideBufLock unlock];
333: return (ideBuf);
334: }
335:
336: - (void)freeIdeBuf:(ideBuf_t *) ideBuf
337: {
338: [_ideBufLock lock];
339: queue_enter(&_ideBufQueue, ideBuf, ideBuf_t *, bufLink);
340: ASSERT(queue_empty(&_ideBufQueue) != 0);
341: [_ideBufLock unlock];
342: }
343:
344: #else NO_ATA_RUNTIME_MEMORY_ALLOCATION
345:
346: - (ideBuf_t *) allocIdeBuf:(void *)pending
347: {
348: ideBuf_t *ideBuf = IOMalloc(sizeof(ideBuf_t));
349:
350: bzero(ideBuf, sizeof(ideBuf_t));
351: if (pending == NULL) {
352: ideBuf->waitLock = [NXConditionLock alloc];
353: [ideBuf->waitLock initWith:NO];
354: } else
355: ideBuf->pending = pending;
356: return (ideBuf);
357: }
358:
359: - (void)freeIdeBuf:(ideBuf_t *) ideBuf
360: {
361: if (ideBuf->waitLock) {
362: [ideBuf->waitLock free];
363: }
364: IOFree(ideBuf, sizeof(ideBuf_t));
365: }
366: #endif NO_ATA_RUNTIME_MEMORY_ALLOCATION
367:
368: - (IOReturn) ideXfrIoReq:(ideIoReq_t *)ideIoReq
369: {
370: ideBuf_t *ideBuf;
371: IOReturn rtn;
372:
373: ideBuf = [self allocIdeBuf:NULL];
374: ideBuf->command = IDEC_IOREQ;
375: ideBuf->ideIoReq = ideIoReq;
376: ideBuf->block = 0;
377: ideBuf->blockCnt = 0;
378: ideBuf->buf = 0;
379: ideBuf->client = 0; /* it picked up from ideIoReq */
380: ideBuf->needsDisk = 1;
381: ideBuf->bytesXfr = 0;
382: ideBuf->oneWay = 0;
383: rtn = [self enqueueIdeBuf:ideBuf];
384: [self freeIdeBuf:ideBuf];
385:
386: return (rtn);
387: }
388:
389: - (IOReturn) initIdeDrive
390: {
391: IOReturn rtn;
392: ideBuf_t *ideBuf;
393:
394: ideBuf = [self allocIdeBuf:NULL];
395: ideBuf->command = IDEC_INIT;
396: ideBuf->block = 0;
397: ideBuf->blockCnt = 0;
398: ideBuf->buf = 0;
399: ideBuf->client = 0;
400: ideBuf->needsDisk = 1;
401: ideBuf->bytesXfr = 0;
402: ideBuf->oneWay = 0;
403: rtn = [self enqueueIdeBuf:ideBuf];
404: [self freeIdeBuf:ideBuf];
405:
406: return(rtn);
407: }
408:
409: /*
410: * Common read/write routine.
411: */
412: - (IOReturn) deviceRwCommon:(IdeCmd_t) command
413: block:(u_int) deviceBlock
414: length:(u_int) length
415: buffer:(void *)buffer
416: client:(vm_task_t) client
417: pending:(void *)pending
418: actualLength:(u_int *) actualLength
419: {
420: ideBuf_t *ideBuf;
421: IOReturn rtn;
422: u_int blocksReq;
423: u_int block_size;
424: u_int dev_size;
425:
426: rtn = [self isDiskReady:NO];
427:
428: switch (rtn) {
429: case IO_R_SUCCESS:
430: break;
431: case IO_R_NO_DISK:
432: return (rtn);
433: default:
434: IOLog("%s deviceRwCommon: bogus return from isDiskReady (%s)\n",
435: [self name], [self stringFromReturn:rtn]);
436: return (rtn);
437: }
438:
439: block_size = [self blockSize];
440: dev_size = [self diskSize];
441:
442: if (length % block_size) {
443: return (IO_R_INVALID);
444: }
445: blocksReq = length / block_size;
446: if ((deviceBlock + blocksReq) > dev_size) {
447: if (deviceBlock >= dev_size) {
448: return (IO_R_INVALID_ARG);
449: }
450: blocksReq = dev_size - deviceBlock;
451: }
452: ideBuf = [self allocIdeBuf:pending];
453: ideBuf->command = command;
454: ideBuf->block = deviceBlock;
455: ideBuf->blockCnt = blocksReq;
456: ideBuf->buf = buffer;
457: ideBuf->client = client;
458: ideBuf->needsDisk = 1;
459: ideBuf->bytesXfr = 0;
460: ideBuf->oneWay = 0;
461:
462: rtn = [self enqueueIdeBuf:ideBuf];
463:
464: if (pending == NULL) {
465: /*
466: * Sync I/O.
467: */
468: *actualLength = ideBuf->bytesXfr;
469: [self freeIdeBuf:ideBuf];
470: }
471: return (rtn);
472: }
473:
474: /*
475: * -- Enqueue an IdeBuf_t on ioQueue<Disk,Nodisk>
476: * -- wake up the I/O thread
477: * -- wait for I/O complete (if ideBuf->pending == NULL)
478: *
479: * All I/O goes thru here; this is the last method called by exported methods
480: * before the I/O thread takes over.
481: */
482: - (IOReturn) enqueueIdeBuf:(ideBuf_t *) ideBuf
483: {
484: queue_head_t *q;
485:
486: ideBuf->status = IO_R_INVALID;
487: [_ioQLock lock];
488: if (ideBuf->needsDisk)
489: q = &_ioQueueDisk;
490: else
491: q = &_ioQueueNodisk;
492: queue_enter(q, ideBuf, ideBuf_t *, link);
493: [_ioQLock unlockWith:WORK_AVAILABLE];
494:
495: if (ideBuf->pending != NULL)
496: return (IO_R_SUCCESS);
497:
498: /*
499: * Wait for I/O complete if not an async command.
500: */
501:
502: if (ideBuf->oneWay) {
503: return IO_R_SUCCESS;
504: }
505: [ideBuf->waitLock lockWhen:YES];
506: [ideBuf->waitLock unlock];
507:
508: return (ideBuf->status);
509: }
510:
511:
512: /*
513: * Either wake up the thread which is waiting on the ideCmdBuf, or send an
514: * ioComplete back to client. ideCmdBuf->status must be valid.
515: */
516: - (void)ideIoComplete:(ideBuf_t *) ideBuf
517: {
518: if (ideBuf->pending) {
519: [self completeTransfer:ideBuf->pending
520: withStatus:ideBuf->status
521: actualLength:ideBuf->bytesXfr];
522: [self freeIdeBuf:ideBuf];
523: } else {
524: /*
525: * Sync I/O. Just wake up the waiting thread.
526: */
527: [ideBuf->waitLock lock];
528: [ideBuf->waitLock unlockWith:YES];
529: }
530:
531: }
532:
533: /*
534: * Main command dispatch method.
535: */
536: - (void)ideCmdDispatch:(ideBuf_t *)ideBuf
537: {
538: IOReturn rtn = IO_R_SUCCESS;
539: ideBuf_t *abortBuf;
540:
541: switch (ideBuf->command) {
542:
543: case IDEC_IOREQ:
544: [_cntrlr ideExecuteCmd:ideBuf->ideIoReq ToDrive:_driveNum];
545:
546: break;
547:
548: case IDEC_READ:
549: case IDEC_WRITE:
550: rtn = [self ideRwCommon:ideBuf];
551:
552: break;
553:
554: case IDEC_ABORT:
555:
556: /*
557: * Each I/O pending in the needsDisk queue must be aborted.
558: */
559: [_ioQLock lock];
560: while (!queue_empty(&_ioQueueDisk)) {
561: abortBuf = (ideBuf_t *) queue_first(&_ioQueueDisk);
562: queue_remove(&_ioQueueDisk,
563: abortBuf,
564: ideBuf_t *,
565: link);
566: [_ioQLock unlock];
567: abortBuf->status = IO_R_NO_DISK;
568: if (abortBuf->ideIoReq)
569: abortBuf->ideIoReq->status = IDER_VOLUNAVAIL;
570: [self ideIoComplete:abortBuf];
571: [_ioQLock lock];
572: }
573: [_ioQLock unlock];
574:
575: break;
576:
577: case IDEC_THREAD_ABORT:
578:
579: /*
580: * First give I/O complete before we die.
581: */
582: ideBuf->status = IO_R_SUCCESS;
583: [self ideIoComplete:ideBuf];
584: IOExitThread();
585:
586: case IDEC_INIT:
587: #if 0
588: /* Called once during initialization. */
589: if ([_cntrlr initIdeDriveLowLevel] == IDER_SUCCESS)
590: rtn = IO_R_SUCCESS;
591: else
592: rtn = IO_R_IO;
593: #endif 0
594: rtn = IO_R_SUCCESS;
595: break;
596:
597: default:
598: IOLog("%s: Bogus ideBuf->command 0x%0x in ideCmdDispatch\n",
599: [self name], ideBuf->command);
600: IOPanic("ideThread");
601: }
602:
603: /*
604: * I/O complete the command if appropriate.
605: */
606: if (ideBuf->oneWay) {
607:
608: [self freeIdeBuf:ideBuf];
609:
610: return;
611: }
612: ideBuf->status = rtn;
613:
614: [self ideIoComplete:ideBuf];
615: return;
616: }
617:
618: /*
619: * Common r/w routine. The following ideBuf fields are required:
620: * block
621: * blockCnt
622: * buf
623: * client
624: * pending
625: *
626: * block and blockCnt are assumed to be already adjusted for overflow.
627: */
628:
629: - (IOReturn) ideRwCommon:(ideBuf_t *)ideBuf
630: {
631: int currentBlock = ideBuf->block; /* start block, current
632: * segment */
633: int currentBlockCnt; /* block count, current segment */
634: int blocksToGo = ideBuf->blockCnt;
635: unsigned ioCommand;
636: char *currentBuf = ideBuf->buf;
637: ideIoReq_t ideIoReq;
638: IOReturn rtn;
639: unsigned int block_size = _ideInfo.bytes_per_sector;
640: BOOL readFlag = (ideBuf->command == IDEC_READ) ? YES : NO;
641: int blocksMoved;
642: ns_time_t start_time;
643:
644:
645: IOGetTimestamp(&start_time);
646:
647: if ( (_ideControllerType == kControllerTypeCmd646X) && ((u_int)currentBuf & 1) )
648: {
649: ioCommand = readFlag ? _ideReadCommandPIO : _ideWriteCommandPIO;
650: }
651: else
652: {
653: ioCommand = readFlag ? _ideReadCommand : _ideWriteCommand;
654: }
655:
656: while (blocksToGo) {
657:
658: /*
659: * Set up controller command block for current segment.
660: */
661: currentBlockCnt = ((blocksToGo > MAX_BLOCKS_PER_XFER) ?
662: MAX_BLOCKS_PER_XFER : blocksToGo);
663:
664: ideIoReq.cmd = ioCommand;
665: ideIoReq.addr = currentBuf;
666: ideIoReq.blkcnt = currentBlockCnt;
667: ideIoReq.block = currentBlock;
668:
669: /*
670: * Note we're compiling MACH_USER_API, hence the cast...
671: */
672: ideIoReq.map = (struct vm_map *) ideBuf->client;
673:
674: rtn = [_cntrlr ideExecuteCmd:&ideIoReq ToDrive:_driveNum];
675:
676: blocksMoved = ideIoReq.blocks_xfered;
677: blocksToGo -= blocksMoved;
678: currentBlock += blocksMoved;
679: currentBuf += ideIoReq.blocks_xfered * block_size;
680:
681: /*
682: * Handle errors.
683: */
684:
685: if (rtn) {
686: /*
687: * This is a colossal error, which should never happen...
688: */
689: ideIoReq.status = IDER_REJECT;
690: }
691: switch (ideIoReq.status) {
692: case IDER_SUCCESS:
693: break;
694: case IDER_TIMEOUT:
695: case IDER_MEMALLOC:
696: case IDER_MEMFAIL:
697: case IDER_REJECT:
698: case IDER_BADDRV:
699: case IDER_CMD_ERROR:
700: case IDER_VOLUNAVAIL:
701: case IDER_SPURIOUS:
702: goto done;
703: break;
704: default:
705:
706: /*
707: * Non-retriable errors.
708: */
709: [self logRwErr:"FATAL" block:currentBlock status:ideIoReq.status
710: readFlag:readFlag];
711: goto done;
712: break;
713:
714: } /* switch status */
715: } /* while blocksToGo */
716: done:
717:
718: /*
719: * Finished. Update client's status and log statistics.
720: */
721: ideBuf->bytesXfr = (ideBuf->blockCnt - blocksToGo) * block_size;
722: rtn = ideBuf->status = iderToIo(ideIoReq.status);
723: if (ideIoReq.status != IO_R_SUCCESS) {
724:
725: if (readFlag) {
726: [self incrementReadErrors];
727: } else {
728: [self incrementWriteErrors];
729: }
730:
731: } else {
732: ns_time_t end_time;
733:
734: /* no "latency" measurement... */
735: ns_time_t delta;
736:
737: IOGetTimestamp(&end_time);
738: delta = end_time - start_time;
739: if (readFlag) {
740:
741: [self addToBytesRead:ideBuf->bytesXfr
742: totalTime:delta
743: latentTime:0];
744: } else {
745: [self addToBytesWritten:ideBuf->bytesXfr
746: totalTime:delta
747: latentTime:0];
748: }
749: }
750:
751: return (rtn);
752: }
753:
754: - (void)logRwErr : (const char *)errType // e.g., "RECALIBRATING"
755: block : (int)block
756: status : (ide_return_t)status
757: readFlag : (BOOL)readFlag
758: {
759:
760: IOLog("%s: Sector %d cmd = %s; %s: %s\n",
761: [self name], block, readFlag ? "Read" : "Write",
762: IOFindNameForValue(status, iderValues), errType);
763:
764: }
765:
766: /*
767: * Unlock ioQLock, updating condition variable as appropriate.
768: */
769: - (void)unlockIoQLock
770: {
771: int queue_state;
772: IODiskReadyState lastReady = [self lastReadyState];
773:
774: /*
775: * There's still work to do when:
776: * -- ioQueueNodisk non-empty, or
777: * -- ioQueueDisk non-empty and we have a disk.
778: */
779:
780: if ((!queue_empty(&_ioQueueNodisk)) ||
781: ((!queue_empty(&_ioQueueDisk)) && (lastReady != IO_NoDisk))) {
782: queue_state = WORK_AVAILABLE;
783: } else
784: queue_state = NO_WORK_AVAILABLE;
785: [_ioQLock unlockWith:queue_state];
786: }
787:
788:
789: /*
790: * I/O thread. Each one of these sits around waiting for work to do on
791: * ioQueue; when something appears, the thread grabs it and disptahes it.
792: */
793:
794: volatile void ideThread(ATADisk *idisk)
795: {
796: ideBuf_t *ideBuf;
797: queue_head_t *q;
798:
799: while (1) {
800:
801: /*
802: * Wait for some work to do.
803: */
804: [idisk->_ioQLock lockWhen:WORK_AVAILABLE];
805:
806: /*
807: * Service all requests which do not require a disk.
808: */
809: q = &idisk->_ioQueueNodisk;
810: while (!queue_empty(q)) {
811: ideBuf = (ideBuf_t *) queue_first(q);
812: queue_remove(q, ideBuf, ideBuf_t *, link);
813: [idisk->_ioQLock unlock];
814: ASSERT(ideBuf->needsDisk == 0);
815: [idisk ideCmdDispatch:ideBuf];
816: [idisk->_ioQLock lock];
817: }
818:
819: /*
820: * Now service all requests which require a disk, as long as we have
821: * one.
822: */
823:
824: q = &idisk->_ioQueueDisk;
825: ASSERT([idisk lastReadyState] == IO_Ready);
826: while ((!queue_empty(q)) &&
827: ([idisk lastReadyState] == IO_Ready)) {
828: ideBuf = (ideBuf_t *) queue_first(q);
829: queue_remove(q, ideBuf, ideBuf_t *, link);
830: [idisk->_ioQLock unlock];
831: ASSERT(ideBuf->needsDisk == 1);
832: [idisk ideCmdDispatch:ideBuf];
833: [idisk->_ioQLock lock];
834: }
835:
836: [idisk unlockIoQLock];
837: }
838:
839: /* NOT REACHED */
840: }
841:
842: IOReturn iderToIo(ide_return_t ider)
843: {
844: switch (ider) {
845: case IDER_SUCCESS:
846: return (IO_R_SUCCESS);
847: case IDER_TIMEOUT:
848: case IDER_CNTRL_REJECT:
849: case IDER_CMD_ERROR:
850: case IDER_SPURIOUS:
851: return (IO_R_IO);
852: case IDER_MEMALLOC:
853: return (IO_R_NO_MEMORY);
854: case IDER_MEMFAIL:
855: return (IO_R_VM_FAILURE);
856: case IDER_REJECT:
857: return (IO_R_UNSUPPORTED);
858: case IDER_BADDRV:
859: return (IO_R_NO_DEVICE);
860: case IDER_VOLUNAVAIL:
861: return (IO_R_NO_DISK);
862: default:
863: return (IO_R_INTERNAL);
864: }
865: }
866:
867: @end
868:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.