|
|
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: * SCSIDiskPrivate.m - Implementation of Private methods for SCSIDisk class.
27: *
28: * HISTORY
29: *
30: * 30-Jul-98 Dan Markarian at Apple. See Radar 2260508, 2258860. If the
31: * SCSIDisk driver attempts to probe a non-zero LUN and a
32: * target exists on LUN 0 that is actively doing (tagged) I/O,
33: * the target may abort all commands with an overlapped command
34: * error, causing the original command to fail without completion.
35: * Suggested work-arounds (for MacOS X Server, release 1): probe
36: * only LUN 0. If a target is discovered, reserve all LUNs for
37: * that target. This code must be revisited for IOKit.
38: *
39: *
40: * 11-Feb-91 Doug Mitchell at NeXT
41: * Created.
42: */
43:
44: #define MACH_USER_API 1
45: #undef KERNEL_PRIVATE
46:
47: #import <sys/types.h>
48: #import <driverkit/SCSIDiskPrivate.h>
49: #import <driverkit/SCSIDiskTypes.h>
50: #import <driverkit/SCSIDiskThread.h>
51: #import <driverkit/SCSIDisk.h>
52: #import <driverkit/IODiskPartition.h>
53: #import <driverkit/scsiTypes.h>
54: #import <bsd/dev/scsireg.h>
55: #import <driverkit/xpr_mi.h>
56: #import <driverkit/return.h>
57: #import <driverkit/align.h>
58: #import <driverkit/generalFuncs.h>
59: #import <kernserv/prototypes.h>
60: #import <mach/mach_interface.h>
61: #import <machkit/NXLock.h>
62:
63: static int moveString(char *inp, char *outp, int inlength, int outlength);
64:
65: @implementation SCSIDisk(Private)
66:
67: /*
68: * One-time only initialization.
69: */
70: - initResources
71: {
72: /*
73: * Radar 2005639: Initialize the instance with the
74: * compiled-in number of threads.
75: */
76: #if defined(i386) || defined(hppa)
77: return ([self initResourcesWithThreadCount : NUM_SD_THREADS_MAX]);
78: #else
79: return ([self initResourcesWithThreadCount : NUM_SD_THREADS_MIN]);
80: #endif
81: }
82:
83: - initResourcesWithThreadCount
84: : (int) threadCount
85: {
86: int threadNum;
87:
88: queue_init(&_ioQueueDisk);
89: queue_init(&_ioQueueNodisk);
90: _ioQLock = [NXConditionLock alloc];
91: [_ioQLock initWith:NO_WORK_AVAILABLE];
92:
93: /*
94: * This gets re-init'd per updateReadyState by IODiskPartitionProbe:.
95: */
96: [self setLastReadyState:IO_NotReady];
97: _ejectLock = [NXConditionLock alloc];
98: [_ejectLock initWith:0];
99: _numDiskIos = 0;
100: _ejectPending = NO;
101: _isReserved = 0;
102: _isRegistered = 0;
103:
104:
105: /*
106: * Start up some I/O threads to perform the actual work of this device.
107: * FIXME - there should only be one thread if target does not
108: * implement command queueing, and more (at least two, max TBD)
109: * if target does implement command queueing.
110: */
111: _numThreads = 0;
112: /*
113: * Radar 2005639: use the requested number of threads.
114: */
115: for(threadNum=0; threadNum < threadCount; threadNum++)
116: {
117: _thread[threadNum] = IOForkThread((IOThreadFunc)sdIoThread,
118: self);
119: _numThreads++;
120: }
121: return self;
122: }
123:
124: /*
125: * Device-specific initialization. We just do enough here to do some
126: * I/O and to find out if the requested target/lun is a SCSI disk device.
127: * This function is "reusable" for a given instance of SCSIDisk; initResources
128: * must have been called exactly once prior to any use of this method.
129: */
130:
131: #define DRIVE_TYPE_LENGTH 80
132:
133: - (sdInitReturn_t)SCSIDiskInit :(int)iunit /* IODevice unit # */
134: targetId : (u_char)Target
135: lun : (u_char)Lun
136: controller : controllerId
137: {
138: inquiry_reply_t inquiryData;
139: sc_status_t rtn;
140: char driveType[DRIVE_TYPE_LENGTH]; /* name from Inquiry */
141: char *outp;
142: char deviceName[30];
143: char location[IO_STRING_LENGTH];
144:
145: xpr_sd("SCSIDiskInit: iunit %d target %d lun %d\n",
146: iunit, Target, Lun, 4,5);
147:
148: /*
149: * init common instance variables.
150: */
151: _controller = controllerId;
152: _target = Target;
153: _lun = Lun;
154: [self setUnit:iunit];
155: sprintf(deviceName, "sd%d", iunit);
156: [self setName:deviceName];
157:
158: /*
159: * Try an Inquiry command.
160: */
161: bzero(&inquiryData, sizeof(inquiry_reply_t));
162: rtn = [self sdInquiry:&inquiryData];
163: switch(rtn) {
164: case SR_IOST_GOOD:
165: break;
166: case SR_IOST_SELTO:
167: return(SDR_SELECTTO);
168: default:
169: return(SDR_ERROR);
170: }
171:
172: /*
173: * Is it a disk?
174: */
175: if(inquiryData.ir_qual != DEVQUAL_OK) {
176: return(SDR_NOTADISK);
177: }
178: switch(inquiryData.ir_devicetype) {
179: case DEVTYPE_DISK:
180: case DEVTYPE_WORM:
181: case DEVTYPE_OPTICAL:
182: case DEVTYPE_CDROM:
183: break;
184: default:
185: return(SDR_NOTADISK);
186: }
187:
188: /*
189: * The top 3 bits (ir_qual) have to be 0, so throw 'em out.
190: */
191: _inquiryDeviceType = inquiryData.ir_devicetype;
192: if(inquiryData.ir_removable)
193: [self setRemovable:1];
194:
195: /*
196: * Compress multiple blanks out of the vendor id and product ID.
197: */
198: outp = driveType;
199: outp += moveString((char *)&inquiryData.ir_vendorid,
200: outp,
201: 8,
202: &driveType[DRIVE_TYPE_LENGTH] - outp);
203: if(*(outp - 1) != ' ')
204: *outp++ = ' ';
205: outp += moveString((char *)&inquiryData.ir_productid,
206: outp,
207: 16,
208: &driveType[DRIVE_TYPE_LENGTH] - outp);
209: if(*(outp - 1) != ' ')
210: *outp++ = ' ';
211: outp += moveString((char *)&inquiryData.ir_revision,
212: outp,
213: 4,
214: &driveType[DRIVE_TYPE_LENGTH] - outp);
215: *outp = '\0';
216: [self setDriveName:driveType];
217: sprintf(location,"Target %d LUN %d at %s", _target, _lun,
218: [controllerId name]);
219: [self setLocation:location];
220: IOLog("%s: %s\n", deviceName, driveType);
221:
222: /*
223: * Do a Test Unit Ready to clear a possible Unit Attention condition.
224: * We don't care about the result.
225: */
226: [self updateReadyState];
227:
228: /*
229: * Start up motor. We'll ignore errors on this one too.
230: */
231: [self scsiStartStop:SS_START inhibitRetry:YES];
232:
233: /*
234: * Let's find out some more info. An error on the
235: * updatePhysicalParameters could mean no disk present; that's OK...
236: */
237: [self setFormattedInternal:0]; // until we do a successful r/w
238: rtn = [self updatePhysicalParameters];
239: if(rtn) {
240: xpr_sd("SCSIDiskInit: updatePhysicalParameters failed; "
241: "continuing\n",
242: 1,2,3,4,5);
243: }
244:
245: /*
246: * log device name. DiskObject will log block_size and capacity.
247: */
248:
249: bzero(driveType, DRIVE_TYPE_LENGTH);
250:
251: /*
252: * Compress multiple blanks out of the vendor id and product ID.
253: */
254: outp = driveType;
255: outp += moveString((char *)&inquiryData.ir_vendorid,
256: outp,
257: 8,
258: &driveType[DRIVE_TYPE_LENGTH] - outp);
259: if(*(outp - 1) != ' ')
260: *outp++ = ' ';
261: outp += moveString((char *)&inquiryData.ir_productid,
262: outp,
263: 16,
264: &driveType[DRIVE_TYPE_LENGTH] - outp);
265: if(*(outp - 1) != ' ')
266: *outp++ = ' ';
267: outp += moveString((char *)&inquiryData.ir_revision,
268: outp,
269: 32,
270: &driveType[DRIVE_TYPE_LENGTH] - outp);
271: *outp = '\0';
272: [self setDriveName:driveType];
273: sprintf(location,"Target %d LUN %d at %s", _target, _lun,
274: [controllerId name]);
275: [self setLocation:location];
276: [super init];
277: return(SDR_GOOD);
278: }
279:
280: /*
281: * Copy inp to outp for up to inlength input characters or outlength output
282: * characters. Compress multiple spaces and eliminate nulls. Returns number
283: * of characters copied to outp.
284: */
285: static int moveString(char *inp, char *outp, int inlength, int outlength)
286: {
287: int lastCharSpace = 0;
288: char *outpStart = outp;
289:
290: while(inlength && outlength) {
291: switch(*inp) {
292: case '\0':
293: inp++;
294: inlength--;
295: continue;
296: case ' ':
297: if(lastCharSpace) {
298: inp++;
299: inlength--;
300: continue;
301: }
302: lastCharSpace = 1;
303: goto copyit;
304: default:
305: lastCharSpace = 0;
306: copyit:
307: *outp++ = *inp++;
308: inlength--;
309: outlength--;
310: break;
311: }
312: }
313: return(outp - outpStart);
314: }
315:
316: /*
317: * Free up local resources.
318: */
319: - free
320: {
321: int threadNum;
322: sdBuf_t *sdBuf;
323:
324: xpr_sd("SCSIDisk free\n", 1,2,3,4,5);
325:
326: /*
327: * Send a "thread abort" command to each thread.
328: */
329: sdBuf = [self allocSdBuf:NULL];
330: sdBuf->command = SDOP_ABORT_THREAD;
331: sdBuf->needsDisk = 0;
332: for(threadNum=0; threadNum<_numThreads; threadNum++) {
333: [self enqueueSdBuf:sdBuf];
334: }
335: [self freeSdBuf:sdBuf];
336:
337: /*
338: * Release our target/lun reservation if we have one.
339: */
340: if(_isReserved) {
341: #if 1 // Radar Fix #2260508
342: /*
343: * LUN 0 will be unreserved. Unreserve
344: * all the non-zero LUNs first.
345: */
346: [self releaseNonZeroLunsOnTarget:_target];
347: #endif // Radar Fix #2260508
348: [_controller releaseTarget:_target
349: lun:_lun
350: forOwner:self];
351: }
352: [_ioQLock free];
353: return([super free]);
354: }
355:
356: - (IOReturn) reacquireTarget
357: {
358: IOReturn ret = IO_R_NOT_OPEN;
359:
360: if(NO == _isReserved) {
361: ret = IO_R_SUCCESS;
362: _isReserved = YES;
363: if( [self isRemovable])
364: [self setLastReadyState:IO_NotReady]; // cause a volCheck probe
365: else if( IO_Ready == [self updateReadyState]) {
366: id descr;
367: // duplicate the volCheck probe of IODiskPartition
368: [self updatePhysicalParameters];
369: [self diskBecameReady];
370: descr = [IODeviceDescription new];
371: [descr setDirectDevice:self];
372: if( NO == [IODiskPartition probe:descr])
373: [descr free];
374: }
375: } else
376: IOLog("SCSIDisk unexpected reacquireTarget\n");
377:
378: return( ret);
379: }
380:
381: - (IOReturn) requestReleaseTarget
382: {
383: IOReturn ret = IO_R_NOT_OPEN;
384: id diskPart;
385:
386: if(_isReserved) {
387: if( _allowLoans) {
388: diskPart = [self nextLogicalDisk]; // a partition always exists
389:
390: ret = [diskPart requestRelease];
391: if( ret)
392: return( ret);
393:
394: [self synchronizeCache];
395: [self setLastReadyState:IO_Ready]; // stop volCheck activity
396: _isReserved = NO;
397: ret = IO_R_SUCCESS;
398: }
399: } else
400: IOLog("SCSIDisk unexpected requestReleaseTarget\n");
401:
402: return( ret);
403: }
404:
405: - (IOReturn)getCharValues : (unsigned char *)parameterArray
406: forParameter : (IOParameterName)parameterName
407: count : (unsigned *)count // in/out
408: {
409:
410: if( 0 == strncmp("IOSCSIDiskAllowLoans", parameterName, strlen("IOSCSIDiskAllowLoans")))
411: _allowLoans = 1;
412: else if( 0 == strncmp("IOSCSIDiskDisallowLoans", parameterName, strlen("IOSCSIDiskDisallowLoans")))
413: _allowLoans = 0;
414:
415: else return( [super getCharValues:parameterArray
416: forParameter:parameterName
417: count:count]);
418:
419: return( IO_R_SUCCESS);
420: }
421:
422: /*
423: * Internal I/O routines.
424: */
425:
426: /*
427: * Inquiry. inquiryReply does not have to be well aligned.
428: * Retries and error logging disabled.
429: */
430: - (sc_status_t)sdInquiry : (inquiry_reply_t *)inquiryReply
431: {
432: IOSCSIRequest scsiReq;
433: cdb_6_t *cdbp = &scsiReq.cdb.cdb_c6;
434: sdBuf_t *sdBuf;
435: inquiry_reply_t *alignedReply;
436: void *freep;
437: int freecnt;
438: sc_status_t rtn;
439: IODMAAlignment dmaAlign;
440:
441: xpr_sd("sd%d sdInquiry\n", [self unit], 2,3,4,5);
442:
443: /*
444: * Get some well-aligned memory.
445: */
446: alignedReply = [_controller allocateBufferOfLength:
447: sizeof(inquiry_reply_t)
448: actualStart:&freep
449: actualLength:&freecnt];
450: bzero(alignedReply, sizeof(inquiry_reply_t));
451: bzero(&scsiReq, sizeof(IOSCSIRequest));
452: scsiReq.target = _target;
453: scsiReq.lun = _lun;
454: scsiReq.read = YES;
455:
456: /*
457: * Get appropriate alignment from controller.
458: */
459: [_controller getDMAAlignment:&dmaAlign];
460: if(dmaAlign.readLength > 1) {
461: scsiReq.maxTransfer = IOAlign(int, sizeof(inquiry_reply_t),
462: dmaAlign.readLength);
463: }
464: else {
465: scsiReq.maxTransfer = sizeof(inquiry_reply_t);
466: }
467: scsiReq.timeoutLength = SD_TIMEOUT_SIMPLE;
468: scsiReq.disconnect = 1;
469:
470: sdBuf = [self allocSdBuf:NULL];
471: sdBuf->command = SDOP_CDB_READ;
472: sdBuf->scsiReq = &scsiReq;
473: sdBuf->buf = alignedReply;
474: sdBuf->client = IOVmTaskSelf();
475: cdbp->c6_opcode = C6OP_INQUIRY;
476: cdbp->c6_lun = _lun;
477: cdbp->c6_len = sizeof(inquiry_reply_t);
478: sdBuf->needsDisk = 0;
479: sdBuf->retryDisable = 1;
480:
481: [self enqueueSdBuf:sdBuf];
482:
483: if(scsiReq.driverStatus == SR_IOST_GOOD) {
484: unsigned required = (char *)(&alignedReply->ir_zero3) -
485: (char *)(alignedReply);
486: if(scsiReq.bytesTransferred < required) {
487: IOLog("%s: bad DMA Transfer count (%d) on Inquiry\n",
488: [self name], scsiReq.bytesTransferred);
489: rtn = SR_IOST_HW;
490: }
491: else {
492: /*
493: * Copy data back to caller's struct. Zero the
494: * portion of alignedReply which did not get valid
495: * data; the last flush out of the DMA pipe could
496: * have written trash to it (and our caller
497: * expects NULL data).
498: */
499: unsigned zeroSize;
500:
501: zeroSize = sizeof(*alignedReply) -
502: scsiReq.bytesTransferred;
503: if(zeroSize) {
504: bzero((char *)alignedReply +
505: scsiReq.bytesTransferred,
506: zeroSize);
507: }
508: *inquiryReply = *alignedReply;
509: rtn = scsiReq.driverStatus;
510: }
511: }
512: else {
513: rtn = scsiReq.driverStatus;
514: }
515: IOFree(freep, freecnt);
516: xpr_sd("sdInquiry: returning %s\n",
517: IOFindNameForValue(rtn, IOScStatusStrings),
518: 2,3,4,5);
519: return rtn;
520: }
521:
522: /*
523: * Read Capacity. capacityReply does not have to be well aligned. Fails
524: * if disk not ready.
525: */
526: - (sc_status_t)sdReadCapacity : (capacity_reply_t *)capacityReply
527: {
528: IOSCSIRequest scsiReq;
529: cdb_10_t *cdbp = &scsiReq.cdb.cdb_c10;
530: sdBuf_t *sdBuf;
531: capacity_reply_t *alignedReply;
532: void *freep;
533: int freecnt;
534: sc_status_t rtn;
535: IODMAAlignment dmaAlign;
536:
537: xpr_sd("sd%d sdReadCapacity\n", [self unit], 2,3,4,5);
538:
539: /*
540: * Get some well-aligned memory.
541: */
542: alignedReply = [_controller allocateBufferOfLength:
543: sizeof(capacity_reply_t)
544: actualStart:&freep
545: actualLength:&freecnt];
546:
547: bzero(&scsiReq, sizeof(IOSCSIRequest));
548: scsiReq.target = _target;
549: scsiReq.lun = _lun;
550: scsiReq.read = YES;
551:
552: /*
553: * Get appropriate alignment from controller.
554: */
555: [_controller getDMAAlignment:&dmaAlign];
556: if(dmaAlign.readLength > 1) {
557: scsiReq.maxTransfer = IOAlign(int, sizeof(capacity_reply_t),
558: dmaAlign.readLength);
559: }
560: else {
561: scsiReq.maxTransfer = sizeof(capacity_reply_t);
562: }
563: scsiReq.timeoutLength = SD_TIMEOUT_SIMPLE;
564: scsiReq.disconnect = 1;
565:
566: sdBuf = [self allocSdBuf:NULL];
567: sdBuf->command = SDOP_CDB_READ;
568: sdBuf->scsiReq = &scsiReq;
569: sdBuf->buf = alignedReply;
570: sdBuf->client = IOVmTaskSelf();
571: cdbp->c10_opcode = C10OP_READCAPACITY;
572: cdbp->c10_lun = _lun;
573: sdBuf->needsDisk = 0;
574:
575: [self enqueueSdBuf:sdBuf];
576:
577: if(scsiReq.driverStatus == SR_IOST_GOOD) {
578: #if !i386
579: if(scsiReq.bytesTransferred != sizeof(capacity_reply_t)) {
580: IOLog("%s: bad DMA Transfer count (%d) on Read"
581: " Capacity\n",
582: [self name], scsiReq.bytesTransferred);
583: rtn = SR_IOST_HW;
584: }
585: else {
586: #else
587: {
588: #endif
589: /*
590: * Copy data back to caller's struct.
591: */
592: *capacityReply = *alignedReply;
593: rtn = scsiReq.driverStatus;
594: }
595: }
596: else {
597: rtn = scsiReq.driverStatus;
598: }
599: IOFree(freep, freecnt);
600: xpr_sd("sdReadCapacity: returning %s\n",
601: IOFindNameForValue(rtn, IOScStatusStrings),
602: 2,3,4,5);
603: return rtn;
604: }
605:
606:
607: /*
608: * Mode Sense.
609: */
610: - (sc_status_t)sdModeSense : (mode_sel_data_t *)modeSenseReply
611: {
612: IOSCSIRequest scsiReq;
613: cdb_6_t *cdbp = &scsiReq.cdb.cdb_c6;
614: sdBuf_t *sdBuf;
615: mode_sel_data_t *alignedReply;
616: void *freep;
617: int freecnt;
618: sc_status_t rtn;
619: IODMAAlignment dmaAlign;
620:
621: xpr_sd("sd%d sdModeSense\n", [self unit], 2,3,4,5);
622:
623: /*
624: * Get some well-aligned memory.
625: */
626: alignedReply = [_controller allocateBufferOfLength:
627: sizeof(mode_sel_data_t)
628: actualStart:&freep
629: actualLength:&freecnt];
630:
631: bzero(&scsiReq, sizeof(IOSCSIRequest));
632: scsiReq.target = _target;
633: scsiReq.lun = _lun;
634: scsiReq.read = YES;
635:
636: /*
637: * Get appropriate alignment from controller.
638: */
639: [_controller getDMAAlignment:&dmaAlign];
640: if(dmaAlign.readLength > 1) {
641: scsiReq.maxTransfer = IOAlign(int, sizeof(mode_sel_data_t),
642: dmaAlign.readLength);
643: }
644: else {
645: scsiReq.maxTransfer = sizeof(mode_sel_data_t);
646: }
647: scsiReq.timeoutLength = SD_TIMEOUT_SIMPLE;
648: scsiReq.disconnect = 1;
649:
650: sdBuf = [self allocSdBuf:NULL];
651: sdBuf->command = SDOP_CDB_READ;
652: sdBuf->scsiReq = &scsiReq;
653: sdBuf->buf = alignedReply;
654: sdBuf->client = IOVmTaskSelf();
655: cdbp->c6_opcode = C6OP_MODESENSE;
656: cdbp->c6_lun = _lun;
657: cdbp->c6_len = sizeof(mode_sel_data_t);
658: sdBuf->needsDisk = 1;
659:
660: [self enqueueSdBuf:sdBuf];
661:
662: if(scsiReq.driverStatus == SR_IOST_GOOD) {
663:
664: /*
665: * Copy data back to caller's struct.
666: */
667: *modeSenseReply = *alignedReply;
668: rtn = scsiReq.driverStatus;
669: }
670: else {
671: rtn = scsiReq.driverStatus;
672: }
673:
674: IOFree(freep, freecnt);
675:
676: xpr_sd("sdModeSense: returning %s\n",
677: IOFindNameForValue(rtn, IOScStatusStrings),
678: 2,3,4,5);
679: return rtn;
680: }
681:
682: /*
683: * Read data; retries and error reporting disabled. Assumes disk is present.
684: */
685: - (IOReturn)sdRawRead : (int)block
686: blockCnt:(int)blockCnt
687: buffer:(void *)buffer
688: {
689: sdBuf_t *sdBuf;
690: IOReturn rtn;
691:
692: xpr_sd("sdRawRead block %d cnt %d\n", block, blockCnt, 3,4,5);
693: sdBuf = [self allocSdBuf:NULL];
694: sdBuf->command = SDOP_READ;
695: sdBuf->block = block;
696: sdBuf->blockCnt = blockCnt;
697: sdBuf->buf = buffer;
698: sdBuf->client = IOVmTaskSelf();
699: sdBuf->needsDisk = 1;
700: sdBuf->retryDisable = 1;
701: rtn = [self enqueueSdBuf:sdBuf];
702: [self freeSdBuf:sdBuf];
703: xpr_sd("sdRawRead: returning %s\n", [self stringFromReturn:rtn],
704: 2,3,4,5);
705: return(rtn);
706: }
707:
708: /*
709: * Start, stop, eject.
710: */
711: - (IOReturn)scsiStartStop : (startStop_t)cmd
712: inhibitRetry : (BOOL)inhibitRetry
713: {
714: IOSCSIRequest scsiReq;
715: sdBuf_t *sdBuf;
716: cdb_6_t *cdbp = &scsiReq.cdb.cdb_c6;
717: IOReturn rtn;
718:
719: xpr_sd("%s: scsiStartStop: cmd 0x%x\n", [self name], cmd,3,4,5);
720:
721: bzero(&scsiReq, sizeof(IOSCSIRequest));
722: scsiReq.target = _target;
723: scsiReq.lun = _lun;
724: scsiReq.timeoutLength = SD_TIMEOUT_EJECT;
725: scsiReq.disconnect = 1;
726:
727: sdBuf = [self allocSdBuf:NULL];
728: sdBuf->scsiReq = &scsiReq;
729: sdBuf->retryDisable = inhibitRetry ? 1 : 0;
730: sdBuf->needsDisk = 1;
731:
732: cdbp->c6_opcode = C6OP_STARTSTOP;
733: cdbp->c6_lun = _lun;
734:
735: switch(cmd) {
736: case SS_EJECT:
737: cdbp->c6_len = C6S_SS_EJECT;
738: sdBuf->command = SDOP_EJECT;
739: break;
740: case SS_STOP:
741: cdbp->c6_len = C6S_SS_STOP;
742: sdBuf->command = SDOP_CDB_WRITE;
743: break;
744: case SS_START:
745: cdbp->c6_len = C6S_SS_START;
746: sdBuf->command = SDOP_CDB_WRITE;
747: break;
748: }
749:
750: rtn = [self enqueueSdBuf:sdBuf];
751: xpr_sd("%s scsiStartStop: returning %s\n", [self name],
752: [self stringFromReturn:rtn], 3,4,5);
753: [self freeSdBuf:sdBuf];
754: return(rtn);
755: }
756:
757: /*
758: * Common read/write routine.
759: */
760: - (IOReturn) deviceRwCommon : (sdOp_t)command
761: block: (u_int) deviceBlock
762: length : (u_int)length
763: buffer : (void *)buffer
764: client : (vm_task_t)client
765: pending : (void *)pending
766: actualLength : (u_int *)actualLength
767: {
768: sdBuf_t *sdBuf;
769: IOReturn rtn;
770: u_int blocksReq;
771: u_int block_size;
772: u_int dev_size;
773:
774: /*
775: * Note we have to 'fault in' a possible non-present disk in
776: * order to get its physical parameters...
777: */
778: rtn = [self isDiskReady:YES];
779: switch(rtn) {
780: case IO_R_SUCCESS:
781: break;
782: case IO_R_NO_DISK:
783: xpr_sd("%s deviceRwCommon: disk not present\n",
784: [self name], 2,3,4,5);
785: return(rtn);
786: default:
787: IOLog("%s deviceRwCommon: bogus return from isDiskReady "
788: "(%s)\n",
789: [self name], [self stringFromReturn:rtn]);
790: return(rtn);
791: }
792:
793: if(![self isFormatted])
794: return(IO_R_UNFORMATTED);
795: block_size = [self blockSize];
796: dev_size = [self diskSize];
797:
798: /*
799: * Verify access and legal parameters.
800: */
801: if(length % block_size) {
802: xpr_sd("deviceRwCommon: unaligned length\n", 1,2,3,4,5);
803: return(IO_R_INVALID);
804: }
805: blocksReq = length / block_size;
806: if((deviceBlock + blocksReq) > dev_size) {
807: if(deviceBlock >= dev_size) {
808: xpr_sd("deviceRwCommon: invalid "
809: "deviceBlock/byte count\n", 1,2,3,4,5);
810: return(IO_R_INVALID_ARG);
811: }
812: /*
813: * Truncate.
814: */
815: blocksReq = dev_size - deviceBlock;
816: xpr_sd("deviceRwCommon: truncating to %d blocks\n", blocksReq,
817: 2,3,4,5);
818: }
819: sdBuf = [self allocSdBuf:pending];
820: sdBuf->command = command;
821: sdBuf->block = deviceBlock;
822: sdBuf->blockCnt = blocksReq;
823: sdBuf->buf = buffer;
824: sdBuf->client = client;
825: sdBuf->needsDisk = 1;
826: rtn = [self enqueueSdBuf:sdBuf];
827: if(pending == NULL) {
828: /*
829: * Sync I/O.
830: */
831: *actualLength = sdBuf->bytesXfr;
832: [self freeSdBuf:sdBuf];
833: }
834: return(rtn);
835: }
836:
837: /*
838: * -- Enqueue an sdBuf on _ioQueue<Disk,Nodisk>
839: * -- wake up one of the I/O threads
840: * -- wait for I/O complete (if sdBuf->pending == NULL)
841: */
842: - (IOReturn)enqueueSdBuf:(sdBuf_t *)sdBuf
843: {
844: queue_head_t *q;
845:
846: #ifdef DDM_DEBUG
847: if(sdBuf->pending) {
848: xpr_sd("enqueueSdBuf: sdBuf 0x%x, ASYNC\n", sdBuf, 2,3,4,5);
849: }
850: else {
851: xpr_sd("enqueueSdBuf: sdBuf 0x%x, SYNC\n", sdBuf, 2,3,4,5);
852: }
853: #endif DDM_DEBUG
854:
855: sdBuf->status = IO_R_INVALID;
856: [_ioQLock lock];
857: /*
858: * TBD - sort by disk block eventually.
859: */
860: if(sdBuf->needsDisk)
861: q = &_ioQueueDisk;
862: else
863: q = &_ioQueueNodisk;
864: queue_enter(q, sdBuf, sdBuf_t *, link);
865: [_ioQLock unlockWith:WORK_AVAILABLE];
866: if(sdBuf->pending != NULL)
867: return(IO_R_SUCCESS);
868:
869: /*
870: * wait for I/O complete.
871: */
872: [sdBuf->waitLock lockWhen:YES];
873: [sdBuf->waitLock unlockWith:NO]; // for easy reuse
874: xpr_sd("enqueueSdBuf: I/O Complete sdBuf 0x%x status %s\n",
875: sdBuf, [self stringFromReturn:sdBuf->status], 3,4,5);
876: return(sdBuf->status);
877: }
878:
879: /*
880: * Allocate and free sdBuf_t's.
881: *
882: * TBD - we might keep around a queue of free sdBuf_t's.
883: */
884: - (sdBuf_t *)allocSdBuf : (void *)pending
885: {
886: sdBuf_t *sdBuf = IOMalloc(sizeof(sdBuf_t));
887:
888: bzero(sdBuf, sizeof(sdBuf_t));
889: if(pending == NULL) {
890: sdBuf->waitLock = [NXConditionLock alloc];
891: [sdBuf->waitLock initWith:NO];
892: }
893: else
894: sdBuf->pending = pending;
895: return(sdBuf);
896: }
897:
898: - (void)freeSdBuf : (sdBuf_t *)sdBuf
899: {
900: if(!sdBuf->pending) {
901: [sdBuf->waitLock free];
902: }
903: IOFree(sdBuf, sizeof(sdBuf_t));
904: }
905:
906: #if 1 // Radar Fix #2260508
907: - (void) reserveNonZeroLunsOnTarget : (int) target
908: {
909: //
910: // Reserves all non-zero LUNs for the specified target. If a given
911: // LUN is already reserved by someone else, reserveTarget is smart
912: // enough to leave it alone and reject our reservation request (no
913: // errors are logged).
914: //
915: // Assumptions:
916: // o _controller instance variable is already set
917: //
918:
919: unsigned char tempLun;
920:
921: for (tempLun = 1; tempLun < SCSI_NLUNS; tempLun++)
922: {
923: [_controller reserveTarget:target lun:tempLun forOwner:self];
924: }
925: }
926:
927: - (void) releaseNonZeroLunsOnTarget : (int) target
928: {
929: //
930: // Unreserves all non-zero LUNs for the specified target. If a given
931: // LUN has been reserved by someone other than us, the releaseTarget
932: // method is smart enough to leave the LUN reserved (however, an error
933: // will be logged).
934: //
935: // Assumptions:
936: // o _controller instance variable is already set
937: //
938:
939: unsigned char tempLun;
940:
941: // Release the luns in reverse order to avoid a problem when another
942: // client is simultaneously trying to acquire the luns. (This is,
943: // of course, impossible, but it can't hurt to be suspicious.)
944:
945: for (tempLun = SCSI_NLUNS - 1; tempLun >= 1; tempLun--)
946: {
947: [_controller releaseTarget:target lun:tempLun forOwner:self];
948: }
949: }
950: #endif // Radar Fix #2260508
951:
952: @end
953:
954:
955:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.