|
|
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 (c) 1991, 1992, 1993 NeXT Computer, Inc.
26: *
27: * Abstract superclass for SCSI controllers.
28: *
29: * HISTORY
30: *
31: * 1998-3-11 [email protected] Moved SCSI user to drvSCSIServer project.
32: * 12 December 1997 Martin Minow at Apple
33: * Added IOSCISUser kernel support
34: * 14 June 1995 Doug Mitchell at NeXT
35: * Added SCSI-3 support.
36: * 25 June 1993 David E. Bohman at NeXT
37: * Cleaned up some (made machine independent). Added this header.
38: * ?? ??? ???? Doug Mitchell at NeXT
39: * Created.
40: */
41:
42: #import <driverkit/IOSCSIController.h>
43: #import <machkit/NXLock.h>
44: #import <driverkit/return.h>
45: #import <driverkit/generalFuncs.h>
46: #import <driverkit/interruptMsg.h>
47: #import <driverkit/align.h>
48: #import <driverkit/xpr_mi.h>
49: #import <driverkit/kernelDriver.h>
50:
51: static int scUnitNum = 0;
52:
53: /*
54: * An element of _reserveQ.
55: */
56: typedef struct {
57: unsigned long long target;
58: unsigned long long lun;
59: id owner;
60: id lender;
61: queue_chain_t link;
62: } reserveElt;
63:
64: @interface IOSCSIController(private)
65:
66: - (reserveElt *) searchReserveQ: (unsigned long long) target
67: lun: (unsigned long long) lun;
68:
69: @end
70:
71: @implementation IOSCSIController
72:
73: - initFromDeviceDescription:deviceDescription
74: {
75: unsigned int target, lun;
76: char devName[20];
77: IODMAAlignment dmaAlign;
78:
79: queue_init(&_reserveQ);
80: if([[self class] deviceStyle] == IO_DirectDevice) {
81: /*
82: * Allow a subclass to act like an indirect device by
83: * skipping this stuff.
84: */
85: if ([super initFromDeviceDescription:deviceDescription] == nil)
86: return nil;
87:
88: if ([self startIOThread] != IO_R_SUCCESS) {
89: [self free]; return nil;
90: }
91: } else
92: [self setDeviceDescription:deviceDescription];
93:
94: /*
95: * We keep track of all scsi controllers in the system by number.
96: * Their device names look like 'scXX'. Note that the rest of the
97: * system actually LOOKS FOR sc0 instead of something more basic,
98: * so we're forced into using this scheme.
99: */
100: [self setUnit:scUnitNum];
101: sprintf(devName, "sc%d", scUnitNum++);
102: [self setName:devName];
103: [self setDeviceKind:"sc"];
104:
105: /*
106: * Determine worst case alignment requirement for this controller.
107: * The result will be used to do the alignment in
108: * allocateBufferOfLength.
109: */
110: [self getDMAAlignment:&dmaAlign];
111: _worstCaseAlign = dmaAlign.readStart;
112: if(dmaAlign.writeStart > _worstCaseAlign) {
113: _worstCaseAlign = dmaAlign.writeStart;
114: }
115: if(dmaAlign.readLength > _worstCaseAlign) {
116: _worstCaseAlign = dmaAlign.readLength;
117: }
118: if(dmaAlign.writeLength > _worstCaseAlign) {
119: _worstCaseAlign = dmaAlign.writeLength;
120: }
121: if(_worstCaseAlign == 1) {
122: _worstCaseAlign = 0;
123: }
124: return self;
125: }
126:
127:
128: - free
129: {
130: int size;
131: reserveElt *rsvElt;
132:
133: if(_reserveQ.next != NULL) {
134: /*
135: * Avoid if queue hasn't been init'd....
136: */
137: while(!queue_empty(&_reserveQ)) {
138: rsvElt = (reserveElt *)queue_first(&_reserveQ);
139: queue_remove(&_reserveQ, rsvElt, reserveElt *, link);
140: IOFree(rsvElt, sizeof(*rsvElt));
141: }
142: }
143:
144: /*
145: * If this is the last IOSCSIController to have been initialized,
146: * update the global unit counter.
147: */
148: if([self unit] == (scUnitNum - 1)) {
149: scUnitNum--;
150: }
151:
152: /* XXX what about the SCSIController thread?? */
153: return [super free];
154: }
155:
156: /*
157: * Release a reserved element for the owner
158: * _reserveLock held
159: */
160:
161: - (void) releaseReservationElement:(reserveElt *) rsvElt
162: {
163: id lender;
164:
165: lender = rsvElt->lender;
166: if( lender
167: && [lender respondsTo:@selector(reacquireTarget)]
168: && (IO_R_SUCCESS == [lender reacquireTarget]) ) {
169:
170: rsvElt->lender = nil;
171: rsvElt->owner = lender;
172:
173: } else {
174: queue_remove(&_reserveQ, rsvElt, reserveElt *, link);
175: IOFree(rsvElt, sizeof(*rsvElt));
176: _reserveCount--;
177: }
178: }
179:
180: /*
181: * Attempt to reserve specified target and lun for calling device. Returns
182: * non-zero if device already reserved.
183: *
184: * This is called by a client (e.g., SCSIDisk) in an attempt to mark a
185: * particular target/lun as being "in use" by that client; it's normally
186: * only used during SCSI bus configuration.
187: */
188:
189: - releaseAllUnitsForOwner: owner;
190: {
191: reserveElt *rsvElt, *nxtElt;
192:
193: [_reserveLock lock];
194:
195: rsvElt = (reserveElt *) queue_first(&_reserveQ);
196: while ( !queue_end(&_reserveQ, (queue_t) rsvElt) ) {
197: nxtElt = (reserveElt *) rsvElt->link.next;
198: if (rsvElt->owner == owner) {
199: [self releaseReservationElement:rsvElt];
200: }
201: rsvElt = nxtElt;
202: }
203:
204: [_reserveLock unlock];
205: }
206:
207: - (int) reserveTarget:(u_char)target lun:(u_char)lun forOwner:(id)owner
208: {
209: return [self reserveSCSI3Target:(unsigned long long)target
210: lun:(unsigned long long)lun
211: forOwner:owner];
212: }
213:
214:
215: - (void)releaseTarget:(u_char)target lun:(u_char)lun forOwner:(id)owner
216: {
217: [self releaseSCSI3Target:(unsigned long long)target
218: lun:(unsigned long long)lun
219: forOwner:owner];
220: }
221:
222: - (int)reserveSCSI3Target : (unsigned long long)target
223: lun : (unsigned long long)lun
224: forOwner : owner
225: {
226: int rtn = 0;
227: int targInt = target;
228: reserveElt *rsvElt;
229: id currentOwner;
230:
231: xpr_sdev("reserveSCSI3Target: t %x:%x l %x:%x\n",
232: (unsigned)(target >> 32),
233: (unsigned)target,
234: (unsigned)(lun >> 32),
235: (unsigned)lun, 5);
236: [_reserveLock lock];
237:
238: if(targInt >= [self numberOfTargets]) {
239: rtn = 1;
240: goto out;
241: }
242: rsvElt = [self searchReserveQ:target lun:lun];
243: if(rsvElt) {
244: xpr_sdev("...already reserved\n", 1,2,3,4,5);
245:
246: currentOwner = rsvElt->owner;
247: if( (rsvElt->lender == nil) // only 1 deep stack
248: && [currentOwner respondsTo:@selector(requestReleaseTarget)]
249: && (IO_R_SUCCESS == [currentOwner requestReleaseTarget]) ) {
250:
251: rsvElt->lender = currentOwner;
252: rsvElt->owner = owner;
253:
254: } else
255: rtn = 1;
256:
257: goto out;
258: }
259:
260: /*
261: * Cons up a new element for _reserveQ.
262: */
263: rsvElt = IOMalloc(sizeof(*rsvElt));
264: rsvElt->target = target;
265: rsvElt->lun = lun;
266: rsvElt->owner = owner;
267: rsvElt->lender = nil;
268: queue_enter(&_reserveQ, rsvElt, reserveElt *, link);
269: _reserveCount++;
270: out:
271: [_reserveLock unlock];
272: return(rtn);
273: }
274:
275: - (void)releaseSCSI3Target : (unsigned long long)target
276: lun : (unsigned long long)lun
277: forOwner : owner
278: {
279: int targInt = target;
280: reserveElt *rsvElt;
281:
282: xpr_sdev("releaseSCSI3Target: t %x:%x l %x:%x\n",
283: (unsigned)(target >> 32),
284: (unsigned)target,
285: (unsigned)(lun >> 32),
286: (unsigned)lun, 5);
287: [_reserveLock lock];
288: if(targInt >= [self numberOfTargets]) {
289: IOLog("IOSCSIController releaseTarget: INVALID TARGET\n");
290: goto out;
291: }
292: rsvElt = [self searchReserveQ:target lun:lun];
293: if(rsvElt == NULL) {
294: IOLog("IOSCSIController releaseTarget: NOT RESERVED\n");
295: goto out;
296: }
297: if(rsvElt->owner != owner) {
298: IOLog("IOSCSIController releaseTarget: INVALID OWNER\n");
299: goto out;
300: }
301:
302: [self releaseReservationElement:rsvElt];
303:
304: out:
305: [_reserveLock unlock];
306: }
307:
308:
309: /*
310: * Returns the number of SCSI targets supported. Default is 8, returned here.
311: * Subclasses may override if they support more than 8 targets.
312: */
313: - (int)numberOfTargets
314: {
315: return SCSI_NTARGETS;
316: }
317:
318: - (unsigned int) numReserved
319: {
320: return _reserveCount;
321: }
322:
323: - (sc_status_t) executeRequest : (IOSCSIRequest *)scsiReq
324: buffer : (void *)buffer /* data destination */
325: client : (vm_task_t)client
326: {
327: /*
328: * Subclass must implement this; we should never get here.
329: */
330: return SR_IOST_INVALID;
331: }
332:
333: /*
334: * executeRequest (with an IOMemoryDescriptor) requires buffers aligned to
335: * IO_SCSI_DMA_ALIGNMENT. The client identification is contained in the
336: * IOMemoryDescriptor object
337: */
338: - (sc_status_t) executeRequest : (IOSCSIRequest *) scsiReq
339: ioMemoryDescriptor : (IOMemoryDescriptor *) ioMemoryDescriptor
340: {
341: /*
342: * Subclass must implement this; we should never get here.
343: */
344: return SR_IOST_INVALID;
345: }
346:
347: - (sc_status_t) executeSCSI3Request : (IOSCSI3Request *)scsiReq
348: buffer : (void *)buffer /* data destination */
349: client : (vm_task_t)client
350: {
351: /*
352: * Optional.
353: */
354: return SR_IOST_CMDREJ;
355: }
356:
357: /*
358: * executeRequest (with an IOMemoryDescriptor) requires buffers aligned to
359: * IO_SCSI_DMA_ALIGNMENT. The client identification is contained in the
360: * IOMemoryDescriptor object
361: */
362: - (sc_status_t) executeSCSI3Request : (IOSCSI3Request *) scsiReq
363: ioMemoryDescriptor : (IOMemoryDescriptor *) ioMemoryDescriptor
364: {
365: /*
366: * Optional.
367: */
368: return SR_IOST_CMDREJ;
369: }
370:
371: - (sc_status_t) resetSCSIBus
372: {
373: return SR_IOST_INVALID;
374: }
375:
376: /*
377: * Convert an sc_status_t to an IOReturn.
378: */
379: - (IOReturn)returnFromScStatus:(sc_status_t)sc_status
380: {
381: switch(sc_status) {
382: case SR_IOST_GOOD:
383: return(IO_R_SUCCESS);
384: case SR_IOST_ALIGN:
385: return(IO_R_ALIGN);
386: case SR_IOST_CMDREJ:
387: return(IO_R_INVALID_ARG);
388: case SR_IOST_IPCFAIL:
389: return(IO_R_IPC_FAILURE);
390: case SR_IOST_INT:
391: return(IO_R_INTERNAL);
392: case SR_IOST_MEMF:
393: return(IO_R_VM_FAILURE);
394: case SR_IOST_MEMALL:
395: return(IO_R_RESOURCE);
396: case SR_IOST_DMA:
397: return(IO_R_DMA);
398: case SR_IOST_WP:
399: return(IO_R_NOT_WRITABLE);
400: default:
401: return(IO_R_IO);
402: }
403: }
404:
405:
406: /*
407: * Determine maximum DMA which can be peformed in a single call to
408: * executeRequest:buffer:client:.
409: */
410: - (unsigned)maxTransfer
411: {
412: return 16 * 1024 * 1024; /* XXX */
413: }
414:
415:
416: /*
417: * Return required DMA alignment for current architecture.
418: * May be overridden by subclass.
419: */
420: - (void)getDMAAlignment:(IODMAAlignment *)alignment
421: {
422: alignment->readStart = 1; /* XXX */
423: alignment->writeStart = 1; /* XXX */
424: alignment->readLength = 1; /* XXX */
425: alignment->writeLength = 1; /* XXX */
426: }
427:
428:
429:
430: - (unsigned int) numQueueSamples
431: {
432: return 0;
433: }
434:
435:
436: - (unsigned int) sumQueueLengths
437: {
438: return 0;
439: }
440:
441:
442: - (unsigned int) maxQueueLength
443: {
444: return 0;
445: }
446:
447:
448: - (void)resetStats
449: {
450: }
451:
452:
453: - (IOReturn)getIntValues:(unsigned *)parameterArray
454: forParameter:(IOParameterName)parameterName
455: count:(unsigned int *)count
456: {
457: unsigned maxCount = *count;
458: unsigned *returnedCount = count;
459:
460: unsigned int params[IO_SCSI_CONTROLLER_STAT_ARRAY_SIZE];
461: int i;
462: if(maxCount == 0) {
463: maxCount = IO_MAX_PARAMETER_ARRAY_LENGTH;
464: }
465: if(strcmp(parameterName, IO_SCSI_CONTROLLER_STATS) == 0) {
466: params[IO_SCSI_CONTROLLER_MAX_QUEUE_LENGTH] =
467: [self maxQueueLength];
468: params[IO_SCSI_CONTROLLER_QUEUE_SAMPLES] =
469: [self numQueueSamples];
470: params[IO_SCSI_CONTROLLER_QUEUE_TOTAL] =
471: [self sumQueueLengths];
472:
473: *returnedCount = 0;
474: for(i=0; i<IO_SCSI_CONTROLLER_STAT_ARRAY_SIZE; i++) {
475: if(*returnedCount == maxCount)
476: break;
477: parameterArray[i] = params[i];
478: (*returnedCount)++;
479: }
480: return IO_R_SUCCESS;
481: }
482: else if(strcmp(parameterName, IO_IS_A_SCSI_CONTROLLER) == 0) {
483: /*
484: * No data; just let caller know we're a disk.
485: */
486: *returnedCount = 0;
487: return IO_R_SUCCESS;
488: }
489: else {
490: return [super getIntValues:parameterArray
491: forParameter:parameterName
492: count:count];
493:
494: }
495: }
496:
497:
498: - (IOReturn)setIntValues:(unsigned *)parameterArray
499: forParameter:(IOParameterName)parameterName
500: count:(unsigned int)count
501: {
502: if(strcmp(parameterName, IO_SCSI_CONTROLLER_STATS) == 0) {
503: [self resetStats];
504: return IO_R_SUCCESS;
505: }
506: else
507: return [super setIntValues:parameterArray
508: forParameter:parameterName
509: count : count];
510: }
511:
512: /*
513: * Allocate some well-aligned memory. *actualStart is what has to be
514: * IOFree()'d eventually; *actualLength is the size arg to IOFree. The
515: * return value is the well-aligned pointer. There is room at the end of
516: * the returned pointer's buffer to do a DMA_DO_ALIGN(...,size,
517: * _worstCaseAlign).
518: */
519:
520: - (void *)allocateBufferOfLength: (unsigned)length
521: actualStart : (void **)actualStart
522: actualLength : (unsigned *)actualLength
523: {
524: char *cp;
525: int cnt = length + 2 * _worstCaseAlign;
526:
527: cp = IOMalloc(cnt);
528: *actualStart = cp;
529: *actualLength = cnt;
530: if(_worstCaseAlign > 1) {
531: return(IOAlign(void *, cp, _worstCaseAlign));
532: }
533: else {
534: return cp;
535: }
536: }
537:
538: - property_IODeviceClass:(char *)classes length:(unsigned int *)maxLen
539: {
540: strcpy( classes, IOClassSCSIController);
541: return( self);
542: }
543:
544: - property_IODeviceType:(char *)classes length:(unsigned int *)maxLen
545: {
546: if( [[self class] deviceStyle] == IO_DirectDevice)
547: strcat( classes, " "IOTypeSCSI);
548: return( self);
549: }
550:
551: @end
552:
553: @implementation IOSCSIController(private)
554:
555: /*
556: * Locate reserveElt for specified target and LUN. _reserveLock must be
557: * held on entry.
558: */
559: - (reserveElt *)searchReserveQ : (unsigned long long)target
560: lun : (unsigned long long)lun
561: {
562: reserveElt *rsvElt;
563:
564: rsvElt = (reserveElt *)queue_first(&_reserveQ);
565: while(!queue_end(&_reserveQ, (queue_t)rsvElt)) {
566: if((rsvElt->target == target) && (rsvElt->lun == lun)) {
567: return rsvElt;
568: }
569: rsvElt = (reserveElt *)rsvElt->link.next;
570: }
571: return NULL;
572: }
573:
574: @end
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.