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