|
|
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: /* unixDisk.m 1.0 01/31/91 (c) 1991 NeXT
25: *
26: * unixDisk.m - Implementation for unix Disk superclass. Provides IODevice
27: * interface for current "/dev" disks.
28: *
29: * HISTORY
30: * 31-Jan-91 Doug Mitchell at NeXT
31: * Created.
32: */
33:
34: #import <bsd/sys/types.h>
35: #import <mach/mach.h>
36: #import <mach/vm_param.h>
37: #import <mach/mach_error.h>
38: #import <bsd/libc.h>
39: #import <bsd/sys/file.h>
40: #import <driverkit/return.h>
41: #import <driverkit/IODisk.h>
42: #import "unixDisk.h"
43: #import "unixDiskPrivate.h"
44: #import "unixThread.h"
45: #import <errno.h>
46: #import "unixDiskUxpr.h"
47: #import <bsd/dev/disk.h>
48: #import <machkit/NXLock.h>
49: #import <driverkit/generalFuncs.h>
50: #import <remote/NXConnection.h>
51: #import <objc/error.h>
52:
53: #define FAKE_LIVE_PARTITION 1
54: #define NUM_API_THREADS 2
55:
56: @implementation unixDisk
57:
58: +initialize
59: {
60: [super registerClass:self];
61: return self;
62: }
63:
64: /*
65: * Common initialization. Device-specific parameters (dev_size, block_size)
66: * must have been initialized before we're called by subclass's *init:
67: * routines.
68: */
69: - unixInit:(int)numThreads
70: {
71: int thread_num;
72: struct drive_info drive_info;
73:
74: xpr_ud("unixInit: numThreads %d\n", numThreads, 2,3,4,5);
75:
76: /*
77: * Set up our instance's IOQueue.
78: */
79: IOQueue.qlock = [NXConditionLock alloc];
80: [IOQueue.qlock initWith:NO_WORK_AVAILABLE];
81: queue_init(&IOQueue.q_disk);
82: queue_init(&IOQueue.q_nodisk);
83: IOQueue.device = self;
84: IOQueue.ejectLock = [NXConditionLock alloc];
85: [IOQueue.ejectLock initWith:0];
86: IOQueue.numDiskIos = 0;
87: IOQueue.ejectPending = FALSE;
88:
89: /*
90: * Log drive name.
91: */
92: if(ioctl(unix_fd[0], DKIOCINFO, &drive_info)) {
93: xpr_err("%s: unixInit: DKIOCINFO error\n", [self name],
94: 2,3,4,5);
95: }
96: else {
97: IOLog("%s: %s\n", [self name], drive_info.di_name);
98: }
99:
100: /*
101: * Start up some I/O threads to perform the actual work of this device.
102: */
103: for(thread_num=0; thread_num<numThreads; thread_num++) {
104: IOForkThread((IOThreadFunc)unix_thread, &IOQueue);
105: }
106:
107: /*
108: * Init other instance variables.
109: */
110: [self setLastReadyState:IO_Ready];
111: [self setIsPhysical:YES];
112: [super init];
113: return self;
114: }
115:
116: /*
117: * Overrides IODisk method of same name; we do this to start up
118: * NXConnections for IODiskPartition partitions attached to this physDevice.
119: */
120: - (void) setLogicalDisk : diskId
121: {
122: if([self registerPartition:diskId] == nil) {
123: return;
124: }
125: [super setLogicalDisk : diskId];
126: }
127:
128: /*
129: * Set up an NXConnection for ourself and start up threads to handle
130: * incoming I/O requests.
131: * Called both from main(), for physical disk, and from setLogicalDisk:
132: * for IODiskPartition instances.
133: */
134: - registerPartition: partId
135: {
136: id roserver;
137: int threadNum;
138: id rtn = self;
139:
140: NX_DURING {
141: roserver = [NXConnection registerRoot:partId
142: withName:[partId name]];
143: } NX_HANDLER {
144: IOLog("registerRoot raised %d\n",
145: NXLocalHandler.code);
146: rtn = nil;
147: } NX_ENDHANDLER
148:
149: if(rtn == nil) {
150: return rtn;
151: }
152: if(roserver == nil) {
153: IOLog("registerRoot returned nil\n");
154: return nil;
155: }
156:
157: /*
158: * Start up "API threads".
159: */
160: for(threadNum=0; threadNum<NUM_API_THREADS; threadNum++) {
161: NX_DURING {
162: [roserver runInNewThread];
163: } NX_HANDLER {
164: IOLog("runInNewThread raised %d\n",
165: NXLocalHandler.code);
166: rtn = nil;
167: } NX_ENDHANDLER;
168: if(rtn == nil) {
169: break;
170: }
171: }
172: return rtn;
173: }
174:
175: /*
176: * IODiskDeviceReadingAndWriting protocol implementation. The main task of
177: * these methods is:
178: *
179: * -- verify valid input parameters (can we skip this?)
180: * -- set up and enqueue an IOBuf for servicing by the I/O thread.
181: * -- Wait for I/O complete if synchronous request.
182: */
183:
184: - (IOReturn) readAt : (u_int)offset
185: length : (u_int)length
186: buffer : (unsigned char *)buffer
187: actualLength : (u_int *)actualLength
188: {
189: IOReturn mrtn;
190: IOBuf_t *IOBuf;
191:
192: xpr_ud("unixDisk read: unit %d offset 0x%x "
193: "length 0x%x\n", [self unit], offset, length, 4,5);
194:
195: mrtn = [self readCommon : offset
196: length : length
197: buffer : buffer
198: actualLength : actualLength /* returned */
199: pending : 0
200: caller : nil
201: IOBufRtn : &IOBuf];
202:
203: /*
204: * Wait for I/O complete.
205: */
206: if(!mrtn) {
207: [IOBuf->wait_lock lockWhen:TRUE];
208: [IOBuf->wait_lock unlock];
209: mrtn = IOBuf->status;
210: [self freeIOBuf:IOBuf];
211: }
212: xpr_ud("unixDisk read: returning %d\n", mrtn, 2,3,4,5);
213: return(mrtn);
214: }
215:
216: - (IOReturn) readAsyncAt : (u_int)offset
217: length : (u_int)length
218: buffer : (unsigned char *)buffer
219: pending : (void *)pending
220: {
221: return IO_R_UNSUPPORTED;
222: }
223:
224: - (IOReturn) writeAt : (u_int)offset
225: length : (u_int)length
226: buffer : (unsigned char *)buffer
227: actualLength : (u_int *)actualLength
228: {
229: IOReturn mrtn;
230: IOBuf_t *IOBuf;
231:
232: xpr_ud("unixDisk write: unit %d offset 0x%x "
233: "length 0x%x\n", [self unit], offset, length, 4,5);
234:
235: mrtn = [self writeCommon : offset
236: length : length
237: buffer : buffer
238: actualLength : actualLength /* returned */
239: pending : 0
240: caller : nil
241: IOBufRtn : &IOBuf];
242:
243: /*
244: * Wait for I/O complete.
245: */
246: if(!mrtn) {
247: [IOBuf->wait_lock lockWhen:TRUE];
248: mrtn = IOBuf->status;
249: [self freeIOBuf:IOBuf];
250: }
251: xpr_ud("unixDisk write: returning %d\n", mrtn, 2,3,4,5);
252: return(mrtn);
253: }
254:
255: - (IOReturn) writeAsyncAt : (u_int)offset
256: length : (u_int)length
257: buffer : (unsigned char *)buffer
258: pending : (void *)pending
259: {
260: return IO_R_UNSUPPORTED;
261: }
262:
263: - (IODiskReadyState)updateReadyState
264: {
265: IOBuf_t *IOBuf;
266: IODiskReadyState readyState;
267:
268: xpr_ud("unixDisk updateReadyState: top\n", 1,2,3,4,5);
269:
270: /*
271: * Queue up an IOBuf.
272: */
273: IOBuf = [self allocIOBuf];
274: IOBuf->command = @selector(deviceCheckReady:threadNum:);
275: IOBuf->offset = 0;
276: IOBuf->bytesReq = 0;
277: IOBuf->buf = &readyState;
278: IOBuf->bytesXfr = NULL;
279: IOBuf->status = IO_R_INVALID; /* must be filled in by
280: * I/O thread */
281: IOBuf->pending = 0;
282: IOBuf->device = self;
283: IOBuf->dirRead = 1;
284: IOBuf->wait_lock = [NXConditionLock alloc];
285: [IOBuf->wait_lock initWith:FALSE];
286: [self enqueueIoBuf:IOBuf needs_disk:FALSE];
287:
288: /*
289: * Wait for I/O complete.
290: */
291: [IOBuf->wait_lock lockWhen:TRUE];
292: readyState = *(IODiskReadyState *)IOBuf->buf;
293: [self freeIOBuf:IOBuf];
294:
295: xpr_ud("unixDisk updateReadyState: DONE; state = %s\n",
296: IOFindNameForValue(readyState, readyStateValues), 2,3,4,5);
297: return(readyState);
298: }
299:
300: /*
301: * IOPhysicalDiskMethods protocol methods.
302: */
303: /*
304: * Device-specific eject. Called by DiskObject's eject:.
305: */
306: - (IOReturn) ejectPhysical
307: {
308: IOReturn mrtn;
309: IOBuf_t *IOBuf;
310:
311: xpr_ud("unixDisk ejectPhysical: top\n", 1,2,3,4,5);
312:
313: /*
314: * Queue up an IOBuf.
315: */
316: IOBuf = [self allocIOBuf];
317: IOBuf->command = @selector(deviceEject:threadNum:);
318: IOBuf->offset = 0;
319: IOBuf->bytesReq = 0;
320: IOBuf->buf = NULL;
321: IOBuf->bytesXfr = NULL;
322: IOBuf->status = IO_R_INVALID; /* must be filled in by
323: * I/O thread */
324: IOBuf->pending = 0;
325: IOBuf->device = self;
326: IOBuf->dirRead = 1;
327: IOBuf->wait_lock = [NXConditionLock alloc];
328: [IOBuf->wait_lock initWith:FALSE];
329: [self enqueueIoBuf:IOBuf needs_disk:TRUE];
330:
331: /*
332: * Wait for I/O complete.
333: */
334: [IOBuf->wait_lock lockWhen:TRUE];
335: mrtn = IOBuf->status;
336: [self freeIOBuf:IOBuf];
337:
338: xpr_ud("unixDisk eject: DONE; status = %d\n", mrtn, 2,3,4,5);
339: return(mrtn);
340: }
341:
342: /*
343: * Removable media support.
344: */
345:
346: /*
347: * Called by volCheck thread when WS has told us that a requested disk is
348: * not present. Pending I/Os which require a disk to be present must be
349: * aborted.
350: */
351: - (void)abortRequest
352: {
353: IOReturn mrtn;
354: IOBuf_t *IOBuf;
355:
356: xpr_ud("unixDisk abortRequest: top\n", 1,2,3,4,5);
357:
358: /*
359: * Queue up an IOBuf.
360: */
361: IOBuf = [self allocIOBuf];
362: IOBuf->command = @selector(unixDeviceAbort:);
363: IOBuf->offset = 0;
364: IOBuf->bytesReq = 0;
365: IOBuf->buf = NULL;
366: IOBuf->bytesXfr = NULL;
367: IOBuf->status = IO_R_INVALID; /* must be filled in by
368: * I/O thread */
369: IOBuf->pending = 0;
370: IOBuf->device = self;
371: IOBuf->dirRead = 1;
372: IOBuf->wait_lock = [NXConditionLock alloc];
373: [IOBuf->wait_lock initWith:FALSE];
374: [self enqueueIoBuf:IOBuf needs_disk:FALSE];
375:
376: /*
377: * Wait for I/O complete.
378: */
379: [IOBuf->wait_lock lockWhen:TRUE];
380: mrtn = IOBuf->status;
381: [self freeIOBuf:IOBuf];
382:
383: xpr_ud("unixDisk abortRequest: DONE; status = %d\n", mrtn, 2,3,4,5);
384: return;
385: }
386:
387: /*
388: * Called by the volCheck thread when a transition to "ready" is detected.
389: * Pending I/Os which require a disk may proceed.
390: *
391: * All we have to do is wake up the I/O threads.
392: */
393: - (void)diskBecameReady
394: {
395: [self ioThreadWakeup];
396: }
397:
398: /*
399: * Inquire if disk is present; if not, and 'prompt' is TRUE, ask for it.
400: * Returns IO_R_NO_DISK if:
401: * prompt TRUE, disk not present, and user cancels request for disk.
402: * prompt FALSE, disk not present.
403: * Else returns IO_R_SUCCESS.
404: */
405: - (IOReturn)isDiskReady : (BOOL)prompt
406: {
407: IOReturn mrtn;
408: IOBuf_t *IOBuf;
409:
410: xpr_ud("%s: diskBecameReady\n", [self name], 2,3,4,5);
411: if([self lastReadyState] == IO_Ready) {
412: /*
413: * This one's easy...
414: */
415: return(IO_R_SUCCESS);
416: }
417: if(prompt == NO) {
418: return(IO_R_NO_DISK);
419: }
420:
421: /*
422: * Queue up an IOBuf.
423: */
424: IOBuf = [self allocIOBuf];
425: IOBuf->command = @selector(deviceProbe:);
426: IOBuf->offset = 0;
427: IOBuf->bytesReq = 0;
428: IOBuf->buf = NULL;
429: IOBuf->bytesXfr = NULL;
430: IOBuf->status = IO_R_INVALID; /* must be filled in by
431: * I/O thread */
432: IOBuf->pending = 0;
433: IOBuf->device = self;
434: IOBuf->dirRead = 1;
435: IOBuf->wait_lock = [NXConditionLock alloc];
436: [IOBuf->wait_lock initWith:FALSE];
437: [self enqueueIoBuf:IOBuf needs_disk:TRUE];
438:
439: /*
440: * Wait for I/O complete.
441: */
442: [IOBuf->wait_lock lockWhen:TRUE];
443: mrtn = IOBuf->status;
444: [self freeIOBuf:IOBuf];
445:
446: xpr_ud("unixDisk isDiskReady: DONE; status = %d\n", mrtn, 2,3,4,5);
447: return(mrtn);
448: }
449:
450: /*
451: * This must be implemented by subclass.
452: */
453: - (IOReturn)updatePhysicalParameters
454: {
455: IOLog("unixDisk updatePhysicalParameters: NOT IMPLEMENTED\n");
456: return IO_R_UNSUPPORTED;
457: }
458:
459: /*
460: * unixDisk-specific Get/set methods.
461: */
462: - (int)diskType
463: {
464: return(_diskType);
465: }
466:
467: - (void)setDiskType : (int)type
468: {
469: _diskType = type;
470: }
471:
472: /*
473: * Distributed Objects R/W protocol.
474: */
475: - (IOReturn) readAt : (unsigned)offset // in blocks
476: length : (unsigned)length // in bytes
477: data : (out IOData **)data
478: actualLength : (out unsigned *)actualLength
479: {
480: IOReturn rtn;
481: IOData *ldata = [[IOData alloc] initWithSize:length];
482:
483: /*
484: * FIXME - when freeFlag is set to YES (which is what we really
485: * want), this method crashes with the following error messages
486: * when run with the DiskTest app:
487: *
488: * finishEncoding: send error -101:invalid memory
489: * uncaught exception : 11001
490: * objc: FREED(id): message free sent to freed object=0x9c01c
491: *
492: * When run with the test programs in ../tests, everything works
493: * OK...
494: *
495: * When we set freeFlag to NO, everything works, but the IOStub
496: * server leaks memory.
497: */
498: [ldata setFreeFlag:NO];
499: rtn = [self readAt:offset
500: length:length
501: buffer:[ldata data]
502: actualLength:actualLength];
503: if(*actualLength) {
504: *data = ldata;
505: }
506:
507: return rtn;
508: }
509:
510: - (IOData *)rreadAt : (unsigned)offset
511: length : (unsigned)length
512: rtn : (out IOReturn *)rtn
513: actualLength : (out unsigned *)actualLength
514: {
515: IOReturn lrtn;
516: IOData *ldata = [[IOData alloc] initWithSize:length];
517:
518: [ldata setFreeFlag:YES];
519: lrtn = [self readAt:offset
520: length:length
521: buffer:[ldata data]
522: actualLength:actualLength];
523: *rtn = lrtn;
524: return ldata;
525: }
526:
527:
528: - (IOReturn) readAsyncAt : (unsigned)offset
529: length : (unsigned)length
530: ioKey : (unsigned)ioKey
531: caller : (id)caller
532: {
533: /*
534: * TBD
535: */
536: return IO_R_UNSUPPORTED;
537: }
538:
539:
540: - (IOReturn) writeAt : (unsigned)offset // in blocks
541: length : (unsigned)length // in bytes
542: data : (out IOData *)data
543: actualLength : (out unsigned *)actualLength
544: {
545: IOReturn rtn;
546:
547: if([data size] < length) {
548: IOLog("%s writeAt: insufficient memory in IOData\n",
549: [self name]);
550: }
551: rtn = [self writeAt:offset
552: length:length
553: buffer:[data data]
554: actualLength:actualLength];
555: [data free];
556: return rtn;
557: }
558:
559: - (IOReturn)writeAsyncAt : (unsigned)offset // in blocks
560: length : (unsigned)length // in bytes
561: data : (in IOData *)data
562: ioKey : (unsigned)ioKey
563: caller : (id)caller
564: {
565: return IO_R_UNSUPPORTED;
566: }
567:
568: @end
569:
570: IOReturn errno_to_mio(int Errno) {
571:
572: IOReturn mrtn;
573:
574: switch(Errno) {
575: case 0:
576: mrtn = IO_R_SUCCESS;
577: break;
578: case EIO:
579: mrtn = IO_R_IO;
580: break;
581: case EPERM:
582: case EACCES:
583: mrtn = IO_R_PRIVILEGE;
584: break;
585: default:
586: mrtn = IO_R_IO;
587: break;
588: }
589: return(mrtn);
590: }
591:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.