|
|
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) 1992 NeXT Computer, Inc. All rights reserved.
25: *
26: * SCSIGeneric.m - Generic SCSI Driver.
27: *
28: * HISTORY
29: * 14-Jun-95 Doug Mitchell at NeXT
30: * Added SCSI-3 support.
31: * 19-Aug-92 Doug Mitchell at NeXT
32: * Created.
33: */
34:
35: #import <driverkit/SCSIGeneric.h>
36: #import <driverkit/SCSIGenericPrivate.h>
37: #import <driverkit/scsiTypes.h>
38: #import <driverkit/return.h>
39: #import <driverkit/generalFuncs.h>
40: #import <driverkit/kernelDriver.h>
41: #import <machkit/NXLock.h>
42: #import <driverkit/xpr_mi.h>
43: #import <driverkit/align.h>
44:
45: /*
46: * Private method declarations.
47: */
48: @interface SCSIGeneric(Private)
49:
50: - (sc_status_t)getSense : (esense_reply_t *)sense;
51: - (void)clearReservation;
52:
53: @end
54:
55: /*
56: * Public method implementation.
57: */
58: @implementation SCSIGeneric
59:
60: + (IODeviceStyle)deviceStyle
61: {
62: return IO_IndirectDevice;
63: }
64:
65: /*
66: * The protocol we need as an indirect device.
67: */
68: static Protocol *protocols[] = {
69: @protocol(IOSCSIControllerExported),
70: nil
71: };
72:
73: + (Protocol **)requiredProtocols
74: {
75: return protocols;
76: }
77:
78:
79: - registerLoudly
80: {
81: return( nil);
82: }
83:
84: + (BOOL)probe : deviceDescription
85: {
86: id sgId;
87: int i;
88: id controller = [deviceDescription directDevice];
89:
90: /*
91: * We only bother attaching to controller 0 at probe time.
92: * Clients can specify other controllers later via
93: * -setController:.
94: */
95: if([controller unit] != 0) {
96: return NO;
97: }
98: for(i=0; i<NUM_SG_DEV; i++) {
99: sgId = [self alloc];
100: sgIdMap[i] = sgId;
101: [sgId sgInit:i controller:controller];
102: }
103: return YES;
104: }
105:
106: /*
107: * One-time only init. Returns non-zero on error.
108: */
109: - (int)sgInit : (unsigned)unitNum
110: controller : controller
111: {
112: char name[20];
113:
114: _controller = controller;
115: _controllerNum = 0;
116: _autoSense = 0;
117: _isReserved = 0;
118: _targLunValid = 0;
119: _openLock = [NXLock new];
120: _owner = nil;
121: sprintf(name, "sg%d", unitNum);
122: [self setName:name];
123: [self setDeviceKind:"SCSIGeneric"];
124: [self setLocation:[controller name]];
125: [self setUnit:unitNum];
126: [self registerDevice];
127: return 0;
128: }
129:
130: - (unsigned char)target
131: {
132: return (unsigned char)_target;
133: }
134:
135: - (unsigned char)lun
136: {
137: return (unsigned char)_lun;
138: }
139:
140: - (unsigned long long)SCSI3_target
141: {
142: return _target;
143: }
144:
145: - (unsigned long long)SCSI3_lun
146: {
147: return _lun;
148: }
149:
150: /*
151: * Acquire and release, to allow exclusive access to this device.
152: *
153: * -acquire returns non-zero if device in use, else reserves device for
154: * exclusive use by 'caller'.
155: * -release returns non-zero if device not currently in use by 'caller'.
156: */
157: - (int)acquire : caller
158: {
159: int rtn;
160:
161: xpr_sdev("SCSIGeneric acquire\n", 1,2,3,4,5);
162: [_openLock lock];
163: if(_owner) {
164: rtn = 1;
165: }
166: else {
167: _autoSense = 0;
168: _owner = caller;
169: rtn = 0;
170: }
171: [_openLock unlock];
172: return rtn;
173: }
174:
175: - (int)release : caller
176: {
177: int rtn;
178:
179: xpr_sdev("SCSIGeneric release\n", 1,2,3,4,5);
180: [_openLock lock];
181: if(caller != _owner) {
182: IOLog("%s: bogus close call\n", [self name]);
183: rtn = 1;
184: }
185: else {
186: /*
187: * Clear possible pending reservation.
188: */
189: [self clearReservation];
190: _owner = nil;
191: }
192: [_openLock unlock];
193: }
194:
195: /*
196: * ioctl equivalents.
197: */
198:
199: /*
200: * Set target and lun. If isRoot is true, this will succeed even if specified
201: * target/lun are currently reserved. otherwise, returns IO_R_BUSY if
202: * desired target/lun already reserved.
203: */
204: - (IOReturn)setTarget : (unsigned char)target
205: lun:(unsigned char)lun
206: isRoot:(BOOL)isRoot
207: {
208: xpr_sdev("SCSIGeneric setTarget t %d l %d\n", target, lun, 3,4,5);
209: if((target >= [_controller numberOfTargets]) || (lun > SCSI_NLUNS)) {
210: return IO_R_INVALID_ARG;
211: }
212:
213: [self clearReservation];
214: if([_controller reserveSCSI3Target:(unsigned long long)target
215: lun:(unsigned long long)lun
216: forOwner:self]) {
217: if(!isRoot) {
218: return IO_R_BUSY;
219: }
220: /*
221: * else: playing dangerously, but we'll do it...
222: */
223: }
224: else {
225: _isReserved = 1;
226: }
227: _target = target;
228: _lun = lun;
229: _targLunValid = 1;
230: return IO_R_SUCCESS;
231: }
232:
233: - (IOReturn)setSCSI3Target : (unsigned long long)target
234: lun:(unsigned long long)lun
235: isRoot:(BOOL)isRoot
236: {
237: xpr_sdev("setSCSI3Target: t %x:%x l %x:%x\n",
238: (unsigned)(target >> 32),
239: (unsigned)target,
240: (unsigned)(lun >> 32),
241: (unsigned)lun, 5);
242: if((target >= [_controller numberOfTargets]) || (lun > SCSI_NLUNS)) {
243: return IO_R_INVALID_ARG;
244: }
245:
246: [self clearReservation];
247: if([_controller reserveSCSI3Target:target
248: lun:lun
249: forOwner:self]) {
250: if(!isRoot) {
251: return IO_R_BUSY;
252: }
253: /*
254: * else: playing dangerously, but we'll do it...
255: */
256: }
257: else {
258: _isReserved = 1;
259: }
260: _target = target;
261: _lun = lun;
262: _targLunValid = 1;
263: return IO_R_SUCCESS;
264: }
265:
266:
267: /*
268: * Select controller number. Clears pending reservation if controllerNum
269: * is changing.
270: */
271: - (IOReturn)setController : (unsigned)controllerNum
272: {
273: char contrStr[10];
274: IOReturn drtn;
275: id newController;
276:
277: if(controllerNum == _controllerNum) {
278: return IO_R_SUCCESS;
279: }
280: [self clearReservation];
281:
282: /*
283: * Look up new controller.
284: */
285: sprintf(contrStr, "sc%d", controllerNum);
286: drtn = IOGetObjectForDeviceName(contrStr, &newController);
287: if(drtn) {
288: return IO_R_NO_DEVICE;
289: }
290: _controllerNum = controllerNum;
291: _controller = newController;
292: _targLunValid = 0;
293: return IO_R_SUCCESS;
294: }
295:
296: /*
297: * Enable/disable 'autosense' mechanism.
298: */
299: - (IOReturn)enableAutoSense
300: {
301: _autoSense = 1;
302: return IO_R_SUCCESS;
303: }
304:
305: - (IOReturn)disableAutoSense
306: {
307: _autoSense = 0;
308: return IO_R_SUCCESS;
309: }
310:
311: - (int)autoSense
312: {
313: return _autoSense;
314: }
315:
316:
317: /*
318: * Execute CDB. Buffer must be well aligned.
319: * *sense will contain sense data if autoSense is enabled and command
320: * resulted in Check status.
321: */
322: - (sc_status_t)executeRequest : (IOSCSIRequest *)scsiReq
323: buffer:(void *)buffer /* data destination */
324: client:(vm_task_t)client
325: senseBuf:(esense_reply_t *)senseBuf
326: {
327: sc_status_t rtn;
328:
329: xpr_sdev("sg executeRequest; op %s\n",
330: IOFindNameForValue(scsiReq->cdb.cdb_opcode,
331: IOSCSIOpcodeStrings),2,3,4,5);
332: if(!_targLunValid ||
333: ((unsigned long long)scsiReq->target != _target) ||
334: ((unsigned long long)scsiReq->lun != _lun)) {
335: rtn = SR_IOST_CMDREJ;
336: goto out;
337: }
338: rtn = [_controller executeRequest:scsiReq
339: buffer:buffer
340: client:client];
341:
342: /*
343: * The only thing we deal with is Check Status, for which we'll do
344: * a Request Sense if autoSense is enabled.
345: */
346: if(rtn == SR_IOST_CHKSV) {
347: /*
348: * Host adaptor already got us sense data.
349: */
350: *senseBuf = scsiReq->senseData;
351: }
352: else if((rtn == SR_IOST_CHKSNV) && _autoSense) {
353: rtn = [self getSense:senseBuf];
354: if(rtn == SR_IOST_GOOD) {
355: rtn = SR_IOST_CHKSV;
356: }
357: else {
358: IOLog("%s: Request Sense on target %d lun %d "
359: "failed (%s)\n",
360: [self name], (unsigned)_target, (unsigned)_lun,
361: IOFindNameForValue(rtn, IOScStatusStrings));
362: rtn = SR_IOST_CHKSNV;
363: }
364: }
365: out:
366: xpr_sdev("sg executeRequest: returning %s\n",
367: IOFindNameForValue(rtn, IOScStatusStrings), 2,3,4,5);
368: return rtn;
369: }
370:
371: /*
372: * Execute CDB, SCSI-3 style. Buffer must be well aligned.
373: * *sense will contain sense data if autoSense is enabled and command
374: * resulted in Check status.
375: */
376: - (sc_status_t)executeSCSI3Request : (IOSCSI3Request *)scsiReq
377: buffer : (void *)buffer /* data destination */
378: client : (vm_task_t)client
379: senseBuf : (esense_reply_t *)senseBuf
380: {
381: sc_status_t rtn;
382:
383: xpr_sdev("sg executeSCSI3Request; op %s\n",
384: IOFindNameForValue(scsiReq->cdb.cdb_opcode,
385: IOSCSIOpcodeStrings),2,3,4,5);
386: if(!_targLunValid ||
387: (scsiReq->target != _target) ||
388: (scsiReq->lun != _lun)) {
389: rtn = SR_IOST_CMDREJ;
390: goto out;
391: }
392: rtn = [_controller executeSCSI3Request:scsiReq
393: buffer:buffer
394: client:client];
395:
396: /*
397: * The only thing we deal with is Check Status, for which we'll do
398: * a Request Sense if autoSense is enabled.
399: */
400: if(rtn == SR_IOST_CHKSV) {
401: /*
402: * Host adaptor already got us sense data.
403: */
404: *senseBuf = scsiReq->senseData;
405: }
406: else if((rtn == SR_IOST_CHKSNV) && _autoSense) {
407: rtn = [self getSense:senseBuf];
408: if(rtn == SR_IOST_GOOD) {
409: rtn = SR_IOST_CHKSV;
410: }
411: else {
412: IOLog("%s: Request Sense on target %d lun %d "
413: "failed (%s)\n",
414: [self name], (unsigned)_target, (unsigned)_lun,
415: IOFindNameForValue(rtn, IOScStatusStrings));
416: rtn = SR_IOST_CHKSNV;
417: }
418: }
419: out:
420: xpr_sdev("sg executeSCSI3Request: returning %s\n",
421: IOFindNameForValue(rtn, IOScStatusStrings), 2,3,4,5);
422: return rtn;
423: }
424:
425: /*
426: * Reset SCSI bus. We can't authorize this; caller should ensure that
427: * client is root!
428: */
429: - (sc_status_t) resetSCSIBus;
430: {
431: return [_controller resetSCSIBus];
432: }
433:
434: - controller
435: {
436: return _controller;
437: }
438:
439: @end /* of SCSIGeneric */
440:
441: /*
442: * Private methods.
443: */
444: @implementation SCSIGeneric(Private)
445:
446: /*
447: * Get sense data from current target and lun. senseBuf does not have
448: * to be well aligned.
449: */
450: - (sc_status_t)getSense : (esense_reply_t *)senseBuf
451: {
452: IOSCSIRequest scsiReq;
453: cdb_6_t *cdbp = &scsiReq.cdb.cdb_c6;
454: esense_reply_t *alignedBuf;
455: void *freePtr;
456: int freeCnt;
457: sc_status_t rtn;
458: IODMAAlignment dmaAlign;
459:
460: alignedBuf = [_controller allocateBufferOfLength:
461: sizeof(esense_reply_t)
462: actualStart:&freePtr
463: actualLength:&freeCnt];
464: bzero(&scsiReq, sizeof(IOSCSIRequest));
465: [_controller getDMAAlignment:&dmaAlign];
466:
467: scsiReq.target = _target;
468: scsiReq.lun = _lun;
469: scsiReq.read = YES;
470: if(dmaAlign.readLength > 1) {
471: scsiReq.maxTransfer = IOAlign(int, sizeof(esense_reply_t),
472: dmaAlign.readLength);
473: } else {
474: scsiReq.maxTransfer = sizeof(esense_reply_t);
475: }
476: scsiReq.timeoutLength = 10;
477: scsiReq.disconnect = 0;
478: cdbp->c6_opcode = C6OP_REQSENSE;
479: cdbp->c6_lun = _lun;
480: cdbp->c6_len = sizeof(esense_reply_t);
481:
482: rtn = [_controller executeRequest:&scsiReq
483: buffer:alignedBuf
484: client:IOVmTaskSelf()];
485: if(rtn == SR_IOST_GOOD) {
486: *senseBuf = *alignedBuf;
487: }
488: IOFree(freePtr, freeCnt);
489: return rtn;
490: }
491:
492: /*
493: * Clear possible pending reservation, whichever style was last used.
494: */
495: - (void)clearReservation
496: {
497: if(_isReserved) {
498: if(_targLunValid) {
499: [_controller releaseSCSI3Target:_target
500: lun:_lun
501: forOwner:self];
502: _targLunValid = 0;
503: }
504: else {
505: IOLog("%s: clearReservation, no valid target\n",
506: [self name]);
507: }
508: _isReserved = 0;
509: }
510:
511: /*
512: * Note _targLunValid could have been true on entry even if
513: * _isReserved was false - that's the case where root set a target
514: * and LUN which was already reserved.
515: */
516: _targLunValid = 0;
517: }
518:
519:
520: @end /* of SCSIGeneric(Private) */
521:
522:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.