|
|
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: /* Copyright (c) 1991 NeXT Computer, Inc. All rights reserved.
25: *
26: * IODisk.m - implementation of generic disk object.
27: *
28: * HISTORY
29: * 31-Jan-91 Doug Mitchell at NeXT
30: * Created.
31: */
32:
33: #import <bsd/sys/types.h>
34: #import <driverkit/return.h>
35: #import <mach/kern_return.h>
36: #import <driverkit/IODisk.h>
37: #import <driverkit/Device_ddm.h>
38: #ifdef KERNEL
39: #import <kernserv/prototypes.h>
40: #import <mach/mach_interface.h>
41: #else KERNEL
42: #import <mach/mach.h>
43: #import <bsd/libc.h>
44: #endif KERNEL
45: #import <driverkit/IOLogicalDisk.h>
46: #import <driverkit/IODiskPartition.h>
47: #import <driverkit/volCheck.h>
48: #import <machkit/NXLock.h>
49: #import <driverkit/generalFuncs.h>
50: #import <bsd/sys/errno.h>
51: #import <driverkit/IODeviceDescription.h>
52:
53: #ifdef ppc //bknight - 12/16/97 - Radar #2004660
54: #define GROK_APPLE 1
55: #endif //bknight - 12/16/97 - Radar #2004660
56:
57: /*
58: * For stringFromReturn:.
59: */
60: static IONamedValue diskIoReturnValues[] = {
61: {IO_R_NO_LABEL, "No Label" },
62: {IO_R_UNFORMATTED, "Disk Not Formatted" },
63: {IO_R_NO_DISK, "Disk Not Present" },
64: {IO_R_NO_BLOCK_ZERO, "Can\'t Read Block 0" },
65: {IO_R_NO_NEXT_PART, "No NeXT partition" },
66: {0, NULL }
67: };
68:
69: #ifdef DDM_DEBUG
70: /*
71: * For xpr's.
72: */
73: IONamedValue readyStateValues[] = {
74: {IO_Ready, "Ready" },
75: {IO_NotReady, "Not Ready" },
76: {IO_NoDisk, "No Disk" },
77: {IO_Ejecting, "Ejecting" },
78: {0, NULL }
79: };
80: #endif DDM_DEBUG
81:
82: @implementation IODisk
83:
84: /*
85: * Public methods.
86: */
87:
88: /*
89: * Public methods to get and set disk parameters. May be overridden by
90: * subclass.
91: */
92:
93: - (unsigned)diskSize
94: {
95: return(_diskSize);
96: }
97:
98: - (unsigned)blockSize
99: {
100: return(_blockSize);
101: }
102:
103: - (IOReturn)setFormatted : (BOOL)formattedFlag
104: {
105:
106: /*
107: * This is illegal if any attached logicalDisks are open.
108: * In the Unix world, this is normally only done on the raw
109: * device, an IODiskPartition, which overrides this method.
110: */
111: #ifdef KERNEL
112: IOPanic("setFormatted: on IODisk");
113: #else KERNEL
114: id targ = (id)self;
115:
116: xpr_disk("DiskObject %s: setFormatted flag = %d\n",
117: [self name], formattedFlag, 3,4,5);
118:
119: if(_nextLogicalDisk && [_nextLogicalDisk isOpen]) {
120: xpr_err("%s: setFormatted with logicalDisk open\n",
121: [self name], 2,3,4,5);
122: return(IO_R_BUSY);
123: }
124: if(formattedFlag) {
125: /*
126: * Update our internal device parameters.
127: * FIXME - maybe check for respondsTo:.
128: */
129: [targ updatePhysicalParameters];
130: _formatted = 1;
131: }
132: else
133: _formatted = 0;
134: /*
135: * Let any attached logical disks know about this, using the internal
136: * version of setFormatted to avoid having our setFormattedInternal:
137: * being called back..
138: */
139: if(_nextLogicalDisk)
140: [_nextLogicalDisk setFormattedInternal:formattedFlag];
141: #endif KERNEL
142: return(IO_R_SUCCESS);
143: }
144:
145: - (BOOL)isFormatted
146: {
147: return(_formatted);
148: }
149:
150: - (BOOL)isRemovable
151: {
152: return(_removable);
153: }
154:
155: - (const char *)driveName
156: {
157: return(_driveName);
158: }
159:
160: - (BOOL)isPhysical
161: {
162: return(_isPhysical);
163: }
164:
165: - (BOOL)isWriteProtected
166: {
167: return(_writeProtected);
168: }
169:
170: /*
171: * Eject current disk.
172: */
173: - (IOReturn) eject
174: {
175:
176: #ifdef KERNEL
177: IOPanic("IODisk eject in kernel illegal\n");
178: return(IO_R_UNSUPPORTED);
179: #else KERNEL
180:
181: id targ = (id)self;
182:
183: if(!_removable)
184: return(IO_R_UNSUPPORTED);
185: xpr_disk("DiskObject %s eject:\n", [self name], 2,3,4,5);
186:
187: /*
188: * We can't allow this if any logical disks are attached.
189: * Normally in the Unix world, eject is invoked on an IODiskPartition,
190: * which overrides this method and ends up calling physDev's
191: * ejectPhysical. If we're here, that means we must be a
192: * physical device.
193: */
194: if(_nextLogicalDisk) {
195: xpr_disk("DiskObject eject: Logical Disk(s)"
196: " Attached\n", 1,2,3,4,5);
197: IOLog("%s: Eject attempt with attached logical disks",
198: [self name]);
199: return(IO_R_OPEN);
200: }
201:
202: /*
203: * We know nothing about this disk...
204: */
205: _formatted = 0;
206:
207: /*
208: * Can't send this method to self, it's in IOPhysicalDiskMethods
209: * protocol.
210: * FIXME - probably should check for respondsTo:.
211: */
212: return([targ ejectPhysical]);
213: #endif KERNEL
214: }
215:
216: /*
217: * Get/set parameters used only by subclasses.
218: */
219: - (void)setDiskSize : (unsigned)size
220: {
221: _diskSize = size;
222: }
223:
224: - (void)setBlockSize : (unsigned)size
225: {
226: _blockSize = size;
227: }
228:
229: - (void)setIsPhysical : (BOOL)isPhysFlag
230: {
231: _isPhysical = isPhysFlag ? YES : NO;
232: }
233:
234: - nextLogicalDisk
235: {
236: return(_nextLogicalDisk);
237: }
238:
239: - (void) setRemovable : (BOOL)removableFlag
240: {
241: _removable = removableFlag ? YES : NO;
242: return;
243: }
244:
245: - (void)setDriveName : (const char *)name
246: {
247: int len;
248:
249: len = strlen((char *)name);
250: if(len >= MAXDNMLEN)
251: len = MAXDNMLEN - 1;
252: strncpy(_driveName, name, len);
253: _driveName[MAXDNMLEN - 1] = '\0';
254: }
255:
256: - (IODiskReadyState)lastReadyState
257: {
258: return(_lastReadyState);
259: }
260:
261: - (void)setLastReadyState : (IODiskReadyState)readyState
262: {
263: _lastReadyState = readyState;
264: }
265:
266: - (void)setWriteProtected : (BOOL)writeProtectedFlag
267: {
268: _writeProtected = writeProtectedFlag ? YES : NO;
269: }
270:
271:
272: /*
273: * internal setFormatted - avoids logical disk interaction.
274: */
275: - (void)setFormattedInternal:(BOOL)formattedFlag
276: {
277: xpr_disk("DiskObject %s: setFormattedInternal flag = %d\n",
278: [self name], formattedFlag, 3,4,5);
279: _formatted = formattedFlag ? YES : NO;
280: }
281:
282: /*
283: * Statistics support.
284: */
285: - (void)addToBytesRead : (unsigned)bytesRead
286: totalTime : (ns_time_t)totalTime
287: latentTime : (ns_time_t)latentTime
288: {
289: unsigned long long ms_ll;
290:
291: _readOps++;
292: _bytesRead += bytesRead;
293: ms_ll = totalTime / (1000 * 1000);
294: _readTotalTime += ms_ll;
295: ms_ll = latentTime / (1000 * 1000);
296: _readLatentTime += ms_ll;
297: }
298:
299: - (void)addToBytesWritten : (unsigned)bytesWritten
300: totalTime : (ns_time_t)totalTime
301: latentTime : (ns_time_t)latentTime
302: {
303: unsigned long long ms_ll;
304:
305: _writeOps++;
306: _bytesWritten += bytesWritten;
307: ms_ll = totalTime / (1000 * 1000);
308: _writeTotalTime += ms_ll;
309: ms_ll = latentTime / (1000 * 1000);
310: _writeLatentTime += ms_ll;
311: }
312:
313: - (void)incrementReadRetries
314: {
315: _readRetries++;
316: }
317:
318: - (void)incrementReadErrors
319: {
320: _readErrors++;
321: }
322:
323: - (void)incrementWriteRetries
324: {
325: _writeRetries++;
326: }
327:
328: - (void)incrementWriteErrors
329: {
330: _writeErrors++;
331: }
332:
333: - (void)incrementOtherRetries
334: {
335: _otherRetries++;
336: }
337:
338: - (void)incrementOtherErrors
339: {
340: _otherErrors++;
341: }
342:
343:
344: /*
345: * For gathering cumulative statistics.
346: */
347: - (IOReturn)getIntValues : (unsigned *)parameterArray
348: forParameter : (IOParameterName)parameterName
349: count : (unsigned *)count; // in/out
350: {
351: unsigned int paramArray[IO_DISK_STAT_ARRAY_SIZE];
352: int i;
353: int maxCount = *count;
354:
355: if(maxCount == 0) {
356: maxCount = IO_MAX_PARAMETER_ARRAY_LENGTH;
357: }
358: if(strcmp(parameterName, IO_DISK_STATS) == 0) {
359: paramArray[IO_Reads] = _readOps;
360: paramArray[IO_BytesRead] = _bytesRead;
361: paramArray[IO_TotalReadTime] = _readTotalTime;
362: paramArray[IO_LatentReadTime] = _readLatentTime;
363: paramArray[IO_ReadRetries] = _readRetries;
364: paramArray[IO_ReadErrors] = _readErrors;
365: paramArray[IO_Writes] = _writeOps;
366: paramArray[IO_BytesWritten] = _bytesWritten;
367: paramArray[IO_TotalWriteTime] = _writeTotalTime;
368: paramArray[IO_LatentWriteTime] = _writeLatentTime;
369: paramArray[IO_WriteRetries] = _writeRetries;
370: paramArray[IO_WriteErrors] = _writeErrors;
371: paramArray[IO_OtherRetries] = _otherRetries;
372: paramArray[IO_OtherErrors] = _otherErrors;
373:
374: *count = 0;
375: for(i=0; i<IO_DISK_STAT_ARRAY_SIZE; i++) {
376: if(*count == maxCount)
377: break;
378: parameterArray[i] = paramArray[i];
379: (*count)++;
380: }
381: return IO_R_SUCCESS;
382: }
383: else if(strcmp(parameterName, IO_IS_A_DISK) == 0) {
384: /*
385: * No data; just let caller know we're a disk.
386: */
387: *count = 0;
388: return IO_R_SUCCESS;
389: }
390: else if(strcmp(parameterName, IO_IS_A_PHYSICAL_DISK) == 0) {
391: *count = 1;
392: parameterArray[0] = _isPhysical ? 1 : 0;
393: return IO_R_SUCCESS;
394: }
395: else {
396: return [super getIntValues : parameterArray
397: forParameter : parameterName
398: count : count];
399:
400: }
401: }
402:
403: /*
404: * Register a connection with LogicalDisk. If we already have a logicalDisk,
405: * this is a nop - subclasses might override this method to perform
406: * other operations in that case.
407: */
408: - (void) setLogicalDisk : diskId
409: {
410: xpr_disk("setLogicalDisk: log %s self %s oldLog %s\n",
411: (diskId ? [diskId name] : "nil"),
412: [self name],
413: (_nextLogicalDisk ? [_nextLogicalDisk name] : "nil"), 4,5);
414: #ifdef GROK_APPLE //bknight - 12/16/97 - Radar #2004660
415: /*
416: * bknight - 12/16/97 - This was changed in order to prevent a
417: * space leak caused by IODiskPartition instances for HFS partitions
418: * on disks that get ejected. It changes the meaning of this call
419: * to be either "set to nil" or "insert at the end of the list beginning
420: * at", depending on the value of the argument. With this change,
421: * it becomes important that the _nextLogicalDisk field gets set to nil
422: * before being used - including being used by this routine, which means
423: * that it must be set to nil before setting it to a non-nil value.
424: * Otherwise, there would be a use-before-definition bug. Anyhow, it
425: * it appears that all the callers do a setLogicalDisk:nil before
426: * ever calling it with a non-nil argument, so this is safe.
427: * However, if new call sites are added, this needs to be taken into
428: * account, or we need to split it into two methods each having the
429: * appropriate functionality: either "set the field" or "add to the list".
430: */
431: if( ! diskId ) {
432: _nextLogicalDisk = diskId;
433: }
434: else if ( ! _nextLogicalDisk && self != diskId ) {
435: _nextLogicalDisk = diskId;
436: }
437: else if ( _nextLogicalDisk ) {
438: [_nextLogicalDisk setLogicalDisk: diskId];
439: }
440: #else GROK_APPLE //bknight - 12/16/97 - Radar #2004660
441: if(_nextLogicalDisk == nil) {
442: _nextLogicalDisk = diskId;
443: }
444: #endif GROK_APPLE //bknight - 12/16/97 - Radar #2004660
445:
446: }
447:
448: /*
449: * Invoked by instance of subclass upon completion of device initialization.
450: * The code here is only executed for physical disks.
451: *
452: * All device parameters (_diskSize, _blockSize, _formatted, _removable,
453: * _lastReadyState) must be valid at this time.
454: */
455: #define ALWAYS_VCREGISTER 1
456:
457: - registerDevice
458: {
459: id targ = (id)self; // IODisk doesn't implement updateReadyState
460: id ret;
461:
462: xpr_disk("DiskObject registerDisk\n", 1,2,3,4,5);
463: if(!_isPhysical) {
464: ret = [super registerDevice];
465: goto out;
466: }
467:
468: /*
469: * Do some trivial initialization.
470: */
471:
472: _nextLogicalDisk = nil;
473: _LogicalDiskLock = [NXLock new];
474:
475: _readOps = 0;
476: _bytesRead = 0;
477: _readTotalTime = 0;
478: _readLatentTime = 0;
479: _readRetries = 0;
480: _readErrors = 0;
481: _writeOps = 0;
482: _bytesWritten = 0;
483: _writeTotalTime = 0;
484: _writeLatentTime = 0;
485: _writeRetries = 0;
486: _writeErrors = 0;
487: _otherRetries = 0;
488: _otherErrors = 0;
489:
490: /*
491: * For physical disks, this will cause probes of IODiskPartition.
492: */
493: ret = [super registerDevice];
494:
495: /*
496: * sign up for disk insertion/ready detect notification.
497: */
498: if(ret != nil && (
499: ALWAYS_VCREGISTER ||
500: _removable ||
501: ([targ updateReadyState] != IO_Ready))) {
502: /*
503: * Make sure the disk conforms to the appropriate protocol.
504: */
505: if(! [[self class]
506: conformsTo:@protocol(IOPhysicalDiskMethods)] ) {
507: IOLog("Warning: %s, class %s, does not conform to "
508: "IOPhysicalDiskMethods\n",
509: [self name], [[self class] name]);
510: goto out;
511: }
512: #ifdef KERNEL
513: volCheckRegister(self,
514: _devAndIdInfo->blockDev,
515: _devAndIdInfo->rawDev);
516: #else KERNEL
517: volCheckRegister(self, 0, 0);
518: #endif KERNEL
519: }
520:
521: out:
522: return ret;
523: }
524:
525: /*
526: * Lock/Unlock device for LogicalDisk-specific methods. Invoked only by
527: * LogicalDisks which are attached to this device.
528: */
529: - (void)lockLogicalDisks
530: {
531: [_LogicalDiskLock lock];
532: }
533:
534: - (void)unlockLogicalDisks
535: {
536: [_LogicalDiskLock unlock];
537: }
538:
539: /*
540: * Convert an IOReturn to text. Overrides superclass's method of same name
541: * to allow for additional IOReturn's defined in IODisk.h.
542: */
543: - (const char *)stringFromReturn : (IOReturn)rtn
544: {
545: IONamedValue *valArray = diskIoReturnValues;
546:
547: for( ; valArray->name; valArray++) {
548: if(valArray->value == rtn)
549: return(valArray->name);
550: }
551: /*
552: * Not found here. Pass up to superclass.
553: */
554: return([super stringFromReturn:rtn]);
555: }
556:
557: /*
558: * Convert an IOReturn to an errno.
559: */
560: - (int)errnoFromReturn : (IOReturn)rtn
561: {
562: switch(rtn) {
563: case IO_R_NO_DISK:
564: return(ENXIO);
565: case IO_R_NO_LABEL:
566: return(ENXIO); // ???
567: case IO_R_UNFORMATTED:
568: return(EINVAL);
569: default:
570: /*
571: * Not found here. Pass up to superclass.
572: */
573: return([super errnoFromReturn:rtn]);
574:
575: }
576: }
577:
578: /*
579: * volCheck module support.
580: */
581:
582: static inline int
583: diskTypeToPR(IODiskType diskType)
584: {
585: switch(diskType) {
586: case IO_SCSI:
587: return PR_DRIVE_SCSI;
588: case IO_Floppy:
589: return PR_DRIVE_FLOPPY;
590: case IO_Other:
591: return -1;
592: }
593: }
594:
595: /*
596: * Request a "please insert disk" panel.
597: */
598: - (void)requestInsertionPanelForDiskType : (IODiskType)diskType
599: {
600: volCheckRequest(self, diskTypeToPR(diskType));
601: }
602:
603: /*
604: * Notify volCheck thread that specified device is in a "disk ejecting" state.
605: */
606: - (void)diskIsEjecting : (IODiskType)diskType
607: {
608: volCheckEjecting(self, diskTypeToPR(diskType));
609:
610: }
611:
612: /*
613: * Notify volCheck that disk has gone not ready. Typically called on
614: * gross error detection.
615: */
616: - (void)diskNotReady
617: {
618: volCheckNotReady(self);
619: }
620:
621: /*
622: * To be optionally overridden by subclass. IODisk version returns NO.
623: * If subclass's version returns NO, and the drive is a removable media
624: * drive, the drive will not be polled once per second while ready state
625: * is IO_NotReady or IO_NoDisk; instead; polling will only occur when
626: * an DKIOCCHECKINSERT ioctl is executed on the vol driver.
627: */
628: - (BOOL)needsManualPolling
629: {
630: return NO;
631: }
632:
633: - property_IODeviceType:(char *)types length:(unsigned int *)maxLen
634: {
635: if( [self isRemovable])
636: strcat( types, " "IOTypeRemovableDisk);
637: if( [self isWriteProtected])
638: strcat( types, " "IOTypeWriteProtectedDisk);
639:
640: return( self);
641: }
642:
643: - property_IODeviceClass:(char *)classes length:(unsigned int *)maxLen
644: {
645: strcpy( classes, IOClassBlock);
646: if( [self isPhysical])
647: strcat( classes, " "IOClassDisk);
648: return( self);
649: }
650:
651: @end
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.