|
|
1.1 root 1: /*
2: * SCSITape.m -- implementation of scsi tape driver routines
3: *
4: * HISTORY
5: * 31-Mar-93 Phillip Dibner at NeXT
6: * Created.
7: *
8: */
9:
10:
11: #import <sys/errno.h>
12: #import <sys/types.h>
13: #import <sys/time.h>
14: #import <sys/conf.h>
15: #import <sys/uio.h>
16: #import <sys/mtio.h>
17: #import <bsd/dev/scsireg.h>
18:
19: #import <driverkit/scsiTypes.h>
20: #import <driverkit/align.h>
21: #import <driverkit/kernelDriver.h>
22: #import <driverkit/scsiTypes.h>
23: #import <driverkit/return.h>
24: #import <machkit/NXLock.h>
25: #import <kernserv/prototypes.h>
26: #import <kernserv/kern_server_types.h>
27: #import "SCSITape.h"
28: #import "SCSITapeTypes.h"
29:
30: #define DRIVE_TYPE_LENGTH 80
31:
32: #define USE_EBD 1 /* use "even byte disconnect" rather than
33: * "no disconnect during data xfer" for exabyte
34: */
35:
36: extern int st_devsw_init();
37:
38: static int moveString(); /* rmv nulls & blanks from inquiry strings */
39: void assign_cdb_c6s_len(); /* store length data in little-endian cdb_6s */
40: void assign_msbd_numblocks(); /* store nblks in little-endian modesel bd */
41: void assign_msbd_blocklength(); /* store blklen in little-endian modesel bd */
42: int cdb_c6s_len_value(); /* byte swap to read length data in cdb */
43: int er_info_value (); /* byte swapping for sense reply info data */
44:
45: id stIdMap [NST];
46:
47: @implementation SCSITape
48:
49: + (IODeviceStyle)deviceStyle
50: {
51: return IO_IndirectDevice;
52: }
53:
54: /*
55: * The protocol we need as an indirect device.
56: */
57: static Protocol *protocols[] = {
58: @protocol(IOSCSIControllerExported),
59: nil
60: };
61:
62: + (Protocol **)requiredProtocols
63: {
64: return protocols;
65: }
66:
67: static unsigned int tapeUnit = 0;
68:
69: + (BOOL) probe: deviceDescription
70: {
71: SCSITape *tapeId = nil;
72: unsigned char stTarget, stLun;
73: id controllerId =
74: [deviceDescription directDevice];
75: stInitReturn_t irtn = STR_ERROR;
76: BOOL brtn = NO;
77: int major;
78:
79: /* asm volatile("int3"); */ // Early break to debugger
80:
81: if ((major = st_devsw_init()) < 0) {
82: return NO;
83: }
84:
85: for (stTarget=0; stTarget<SCSI_NTARGETS; stTarget++) {
86: for(stLun=0; stLun<SCSI_NLUNS; stLun++) {
87:
88: #ifdef DEBUG
89: IOLog ("SCSITape probe: target %d lun %d\n", stTarget, stLun);
90: #endif DEBUG
91:
92: if(tapeId == nil) {
93: /*
94: * Create an instance, do some basic
95: * initialization. Set up a default
96: * device name for error reporting during
97: * initialization.
98: */
99: tapeId = [SCSITape alloc];
100: }
101:
102: if ([controllerId reserveTarget:stTarget
103: lun:stLun
104: forOwner:tapeId]) {
105: /*
106: * Someone already has this one.
107: */
108: continue;
109: }
110: else {
111: [tapeId setReservedTargetLun: YES];
112: }
113:
114: #ifdef DEBUG
115: IOLog ("SCSITape probe: about to init\n");
116: #endif DEBUG
117:
118: irtn = [tapeId initSCSITape:(int)tapeUnit
119: target: stTarget
120: lun: stLun
121: controller: controllerId
122: majorDeviceNumber: major];
123:
124: #ifdef DEBUG
125: IOLog ("SCSITape probe: irtn is %d\n", irtn);
126: #endif DEBUG
127:
128: switch (irtn) {
129: case STR_GOOD:
130: /*
131: * Init'd OK - still must register device.
132: */
133: [tapeId registerDevice];
134: stIdMap [tapeUnit] = tapeId;
135: tapeId = nil;
136: tapeUnit++;
137: if (tapeUnit >= NST) goto done;
138: brtn = YES;
139: break;
140:
141: default:
142: [controllerId releaseTarget: stTarget
143: lun: stLun
144: forOwner: tapeId];
145: [tapeId setReservedTargetLun: NO];
146: if(irtn == STR_SELECTTO) {
147: /*
148: * Skip the rest of the luns on
149: * this target.
150: */
151: goto nextTarget;
152: }
153: /*
154: * else try next lun.
155: */
156: } /* switch (irtn) */
157: } /* for lun */
158:
159: nextTarget:
160:
161: continue;
162: } /* for target */
163:
164: done:
165: /*
166: * Free up leftover owner and id. At this point, tapeId does NOT have
167: * a target/lun reserved.
168: */
169: if(tapeId) {
170: [tapeId free];
171: }
172:
173: return brtn;
174: }
175:
176:
177: - (stInitReturn_t) initSCSITape:(int)iunit /* IODevice unit # */
178: target: (u_char) stTarget
179: lun: (u_char) stLun
180: controller: controllerId
181: majorDeviceNumber: (int) major
182: {
183: inquiry_reply_t inquiryData;
184: sc_status_t rtn;
185: char driveType[DRIVE_TYPE_LENGTH]; /* name from Inquiry */
186: char *outp;
187: char deviceName[30];
188: char location[IO_STRING_LENGTH];
189:
190:
191: /*
192: * Initialize common instance variables.
193: */
194: _controller = controllerId;
195: _target = stTarget;
196: _lun = stLun;
197: sprintf(deviceName, "st%d", iunit);
198: [self setName: deviceName];
199: [self setDeviceKind:"SCSITape"];
200: [self setLocation:[_controller name]];
201: [self setUnit: iunit];
202:
203: #ifdef DEBUG
204: IOLog
205: ("InitSCSITape: target %d lun %d unit %d deviceName %s location %s\n",
206: stTarget, stLun, iunit, deviceName, [_controller name]);
207: #endif DEBUG
208:
209: /*
210: * Resources for commands during initialization.
211: */
212: _senseDataPtr = IOMalloc (sizeof (struct esense_reply));
213: _senseDataValid = NO;
214:
215: /*
216: * Other instance variables
217: */
218: _didWrite = NO;
219: _suppressIllegalLength = NO;
220: _isInitialized = NO;
221: _devLock = nil; // Until we know we're a tape
222:
223: /*
224: * Test Unit Ready to clear possible Unit Attention. Success is
225: * not important.
226: */
227: [self stTestReady];
228:
229: /*
230: * Try an Inquiry command.
231: */
232: bzero(&inquiryData, sizeof(inquiry_reply_t));
233: rtn = [self stInquiry:&inquiryData];
234:
235: #ifdef DEBUG
236: IOLog ("InitSCSITape inquiry returned %d\n", rtn);
237: #endif DEBUG
238:
239: switch(rtn) {
240: case SR_IOST_GOOD:
241: break;
242: case SR_IOST_SELTO:
243: return STR_SELECTTO;
244: default:
245: return STR_ERROR;
246: }
247:
248: /*
249: * Is it a tape?
250: */
251: if(inquiryData.ir_qual != DEVQUAL_OK ||
252: inquiryData.ir_devicetype != DEVTYPE_TAPE) {
253:
254: #ifdef DEBUG
255: IOLog ("InitSCSITape: not a tape\n");
256: #endif DEBUG
257:
258: return(STR_NOTATAPE);
259: }
260:
261: /*
262: * Set up resources for exclusive open.
263: */
264: _devLock = [[NXLock alloc] init];
265: _devAcquired = NO;
266:
267: /*
268: * Compress multiple blanks out of the vendor id and product ID.
269: */
270: bzero (driveType, DRIVE_TYPE_LENGTH);
271: outp = driveType;
272: outp += moveString((char *)&inquiryData.ir_vendorid,
273: outp,
274: 8,
275: &driveType[DRIVE_TYPE_LENGTH] - outp);
276: if(*(outp - 1) != ' ')
277: *outp++ = ' ';
278: outp += moveString((char *)&inquiryData.ir_productid,
279: outp,
280: 16,
281: &driveType[DRIVE_TYPE_LENGTH] - outp);
282: if(*(outp - 1) != ' ')
283: *outp++ = ' ';
284: outp += moveString((char *)&inquiryData.ir_revision,
285: outp,
286: 4,
287: &driveType[DRIVE_TYPE_LENGTH] - outp);
288: *outp = '\0';
289:
290: sprintf(location, "Target %d LUN %d at %s", _target, _lun,
291: [controllerId name]);
292: [self setLocation: location];
293: IOLog("%s: %s\n", deviceName, driveType);
294:
295:
296: /*
297: * Do another Test Unit Ready to clear a possible Unit Attention
298: * condition. We don't care about the result.
299: */
300: [self stTestReady];
301:
302: /*
303: * Init to variable blk size.
304: */
305: [self setBlockSize: 0];
306:
307: /*
308: * Store the major number in our instance.
309: */
310: _majorDevNum = major;
311:
312: [super init];
313: _isInitialized = YES;
314: return(STR_GOOD);
315: } /* - initSCSITape: */
316:
317:
318: - free
319: {
320: if (_senseDataPtr)
321: IOFree (_senseDataPtr, sizeof (struct esense_reply));
322: if (_devLock)
323: [_devLock free];
324: if (_reservedTargetLun)
325: [_controller releaseTarget: _target lun: _lun forOwner: _controller];
326: return [super free];
327: }
328:
329:
330: - (IOReturn) getIntValues: (unsigned int *)values
331: forParameter: (IOParameterName) parameter
332: count: (unsigned int *) count
333: {
334: int maxCount = *count;
335:
336: if(maxCount == 0) {
337: maxCount = IO_MAX_PARAMETER_ARRAY_LENGTH;
338: }
339:
340: if(strcmp(parameter, "IOMajorDevice") == 0) {
341: values [0] = [self majorDevNum];
342: *count = 1;
343: return IO_R_SUCCESS;
344: }
345:
346: if (strcmp(parameter, "Unit") == 0) {
347: values [0] = [self unit];
348: *count = 1;
349: return IO_R_SUCCESS;
350:
351: }
352:
353: return [super getIntValues:values
354: forParameter:parameter
355: count:&maxCount];
356: }
357:
358:
359:
360: /*
361: * Gets and sets for instance variables.
362: */
363:
364: - (int) target /* Set only during initialization */
365: {
366: return (int) _target;
367: }
368:
369: - (int) lun /* Set only during initialization */
370: {
371: return (int) _lun;
372: }
373:
374: - controller /* Set only during initialization */
375: {
376: return _controller;
377: }
378:
379: - (BOOL) isInitialized /* Object has been initialized */
380: {
381: return _isInitialized;
382: }
383:
384: - (BOOL) didWrite /* Last command was a write */
385: {
386: return _didWrite;
387: }
388:
389: - (BOOL) isFixedBlock
390: {
391: if (_blockSize) { /* Zero blocksize means variable block size */
392: return YES;
393: } else {
394: return NO;
395: }
396: }
397:
398: - (BOOL) senseDataValid
399: {
400: return _senseDataValid;
401: }
402:
403: - forceSenseDataInvalid /* for MTIOCGET and friends */
404: {
405: _senseDataValid = NO;
406: return self;
407: }
408:
409: - (struct esense_reply *) senseDataPtr
410: {
411: return _senseDataPtr;
412: }
413:
414: - (int) blockSize /* Set only via setBlockSize SCSI operation */
415: {
416: return _blockSize;
417: }
418:
419: - (BOOL) suppressIllegalLength
420: {
421: return _suppressIllegalLength;
422: }
423:
424: - setSuppressIllegalLength: (BOOL) condition
425: {
426: _suppressIllegalLength = condition;
427: return self;
428: }
429:
430: - (BOOL) ignoreCheckCondition
431: {
432: return _ignoreCheckCondition;
433: }
434:
435: - setIgnoreCheckCondition: (BOOL) condition
436: {
437: _ignoreCheckCondition = condition;
438: return self;
439: }
440:
441: - (int) majorDevNum
442: {
443: return _majorDevNum;
444: }
445:
446: - setReservedTargetLun: (BOOL) condition
447: {
448: _reservedTargetLun = condition;
449: return self;
450: }
451:
452: - (BOOL) reservedTargetLun
453: {
454: return _reservedTargetLun;
455: }
456:
457: - (IOReturn) acquireDevice
458: {
459: IOReturn ret = IO_R_INVALID;
460:
461: [_devLock lock];
462: if (_devAcquired == YES) {
463: ret = IO_R_BUSY;
464: } else {
465: _devAcquired = YES;
466: ret = IO_R_SUCCESS;
467: }
468: [_devLock unlock];
469: return ret;
470: }
471:
472: - (IOReturn) releaseDevice
473: {
474: [_devLock lock];
475: _devAcquired = NO;
476: [_devLock unlock];
477: return IO_R_SUCCESS;
478: }
479:
480:
481: /*
482: * General SCSI commands
483: */
484: - (sc_status_t) stInquiry: (inquiry_reply_t *) inquiryReply
485: {
486: IOSCSIRequest scsiReq;
487: cdb_6_t *cdbp = &scsiReq.cdb.cdb_c6;
488: inquiry_reply_t *alignedReply;
489: void *freePtr;
490: int freeCnt;
491: sc_status_t rtn;
492: IODMAAlignment dmaAlign;
493:
494:
495: /*
496: * Get some well-aligned memory.
497: */
498: alignedReply = [_controller
499: allocateBufferOfLength: sizeof(inquiry_reply_t)
500: actualStart:&freePtr
501: actualLength:&freeCnt];
502: bzero(alignedReply, sizeof(inquiry_reply_t));
503: bzero(&scsiReq, sizeof(IOSCSIRequest));
504: scsiReq.target = _target;
505: scsiReq.lun = _lun;
506: scsiReq.read = YES;
507:
508: /*
509: * Get appropriate alignment from controller.
510: */
511: [_controller getDMAAlignment:&dmaAlign];
512: if(dmaAlign.readLength > 1) {
513: scsiReq.maxTransfer = IOAlign(int, sizeof(inquiry_reply_t),
514: dmaAlign.readLength);
515: }
516: else {
517: scsiReq.maxTransfer = sizeof(inquiry_reply_t);
518: }
519:
520: scsiReq.timeoutLength = ST_IOTO_NORM;
521: scsiReq.disconnect = 1;
522:
523: cdbp->c6_opcode = C6OP_INQUIRY;
524: cdbp->c6_lun = _lun;
525: cdbp->c6_len = sizeof(inquiry_reply_t);
526:
527: [self executeRequest: &scsiReq
528: buffer: alignedReply
529: client: IOVmTaskSelf()
530: senseBuf: _senseDataPtr];
531:
532: if(scsiReq.driverStatus == SR_IOST_GOOD) {
533: unsigned required = (char *)(&alignedReply->ir_zero3[0]) -
534: (char *)(alignedReply);
535: if(scsiReq.bytesTransferred < required) {
536: IOLog("%s: bad DMA Transfer count (%d) on Inquiry\n",
537: [self name], scsiReq.bytesTransferred);
538: rtn = SR_IOST_HW;
539: }
540: else {
541: /*
542: * Copy data back to caller's struct. Zero the
543: * portion of alignedReply which did not get valid
544: * data; the last flush out of the DMA pipe could
545: * have written trash to it (and our caller
546: * expects NULL data).
547: */
548: unsigned zeroSize;
549:
550: zeroSize = sizeof(*alignedReply) - scsiReq.bytesTransferred;
551: if(zeroSize) {
552: bzero((char *)alignedReply + scsiReq.bytesTransferred,
553: zeroSize);
554: }
555: *inquiryReply = *alignedReply;
556: rtn = scsiReq.driverStatus;
557: }
558: }
559: else {
560: rtn = scsiReq.driverStatus;
561: }
562:
563: IOFree(freePtr, freeCnt);
564: return rtn;
565: } /* - stInquiry: */
566:
567:
568:
569: - (BOOL) stTestReady
570: {
571: IOSCSIRequest scsiReq;
572: cdb_6_t *cdbp = &scsiReq.cdb.cdb_c6;
573: BOOL rtn;
574:
575: bzero(&scsiReq, sizeof(IOSCSIRequest));
576: scsiReq.target = _target;
577: scsiReq.lun = _lun;
578: scsiReq.timeoutLength = ST_IOTO_NORM;
579: scsiReq.disconnect = 1;
580:
581: cdbp->c6_opcode = C6OP_TESTRDY;
582: cdbp->c6_lun = _lun;
583:
584: [self executeRequest: &scsiReq
585: buffer: (void *) NULL
586: client: IOVmTaskSelf()
587: senseBuf: _senseDataPtr];
588:
589: /*
590: * XXX Do we need to distinguish not ready from no tape?
591: */
592: switch(scsiReq.driverStatus) {
593: case SR_IOST_GOOD:
594: rtn = YES;
595: break;
596: default:
597: rtn = NO;
598: break;
599: }
600:
601: return rtn;
602: } /* - stTestReady: */
603:
604:
605:
606: - (sc_status_t) stCloseFile
607: {
608: IOSCSIRequest scsiReq;
609: cdb_6s_t *cdbp = &scsiReq.cdb.cdb_c6s;
610:
611: bzero(&scsiReq, sizeof(IOSCSIRequest));
612: scsiReq.target = _target;
613: scsiReq.lun = _lun;
614: scsiReq.timeoutLength = ST_IOTO_NORM;
615: scsiReq.disconnect = 1;
616: cdbp->c6s_opcode = C6OP_WRTFM;
617: assign_cdb_c6s_len (cdbp, 1); /* one file mark */
618:
619: return [self executeRequest: &scsiReq
620: buffer: NULL
621: client: IOVmTaskSelf()
622: senseBuf: _senseDataPtr];
623: } /* - stCloseFile */
624:
625:
626: - (sc_status_t) stRewind
627: {
628: IOSCSIRequest scsiReq;
629: cdb_6s_t *cdbp = &scsiReq.cdb.cdb_c6s;
630:
631: bzero(&scsiReq, sizeof(IOSCSIRequest));
632: scsiReq.target = _target;
633: scsiReq.lun = _lun;
634: scsiReq.timeoutLength = ST_IOTO_RWD;
635: scsiReq.disconnect = 1;
636: cdbp->c6s_opcode = C6OP_REWIND;
637:
638: return [self executeRequest: &scsiReq
639: buffer: NULL
640: client: IOVmTaskSelf()
641: senseBuf: _senseDataPtr];
642: } /* - stRewind */
643:
644:
645: /*
646: * Get sense data. senseBuf does not have to be well aligned.
647: */
648: - (sc_status_t) requestSense: (esense_reply_t *)senseBuf
649: {
650: IOSCSIRequest scsiReq;
651: cdb_6_t *cdbp = &scsiReq.cdb.cdb_c6;
652: esense_reply_t *alignedBuf;
653: void *freePtr;
654: int freeCnt;
655: sc_status_t rtn;
656: IODMAAlignment dmaAlign;
657:
658: alignedBuf = [_controller allocateBufferOfLength: sizeof(esense_reply_t)
659: actualStart: &freePtr
660: actualLength: &freeCnt];
661: bzero(&scsiReq, sizeof(IOSCSIRequest));
662: [_controller getDMAAlignment:&dmaAlign];
663:
664: scsiReq.target = _target;
665: scsiReq.lun = _lun;
666: scsiReq.read = YES;
667:
668: if(dmaAlign.readLength > 1) {
669: scsiReq.maxTransfer = IOAlign(int, sizeof(esense_reply_t),
670: dmaAlign.readLength);
671:
672: } else {
673: scsiReq.maxTransfer = sizeof(esense_reply_t);
674: }
675:
676: scsiReq.timeoutLength = ST_IOTO_NORM; // XXX Should be ST_IOTO_SENSE??
677: scsiReq.disconnect = 0;
678: cdbp->c6_opcode = C6OP_REQSENSE;
679: cdbp->c6_lun = _lun;
680: cdbp->c6_len = sizeof(esense_reply_t);
681:
682: rtn = [_controller executeRequest:&scsiReq
683: buffer:alignedBuf
684: client:IOVmTaskSelf()];
685: if(rtn == SR_IOST_GOOD) {
686: *senseBuf = *alignedBuf;
687: _senseDataValid = YES;
688: }
689: IOFree(freePtr, freeCnt);
690: return rtn;
691: } /* - requestSense: */
692:
693:
694:
695:
696: - (sc_status_t) stModeSelect: (struct modesel_parms *) modeSelectParmsPtr
697: {
698: IOSCSIRequest scsiReq;
699: cdb_6_t *cdbp = &scsiReq.cdb.cdb_c6;
700: int count = modeSelectParmsPtr->msp_bcount;
701: struct mode_sel_data *alignedBuf;
702: void *freePtr;
703: int freeCnt;
704: sc_status_t rtn;
705: IODMAAlignment dmaAlign;
706:
707: alignedBuf = [_controller
708: allocateBufferOfLength: count
709: actualStart: &freePtr
710: actualLength: &freeCnt];
711:
712:
713: bzero(&scsiReq, sizeof(IOSCSIRequest));
714:
715: scsiReq.target = _target;
716: scsiReq.lun = _lun;
717: scsiReq.read = NO;
718:
719: [_controller getDMAAlignment:&dmaAlign];
720: if(dmaAlign.readLength > 1) {
721: scsiReq.maxTransfer = IOAlign(int, count,
722: dmaAlign.readLength);
723:
724: } else {
725: scsiReq.maxTransfer = count;
726: }
727:
728: scsiReq.timeoutLength = ST_IOTO_NORM;
729: scsiReq.disconnect = 1;
730: cdbp->c6_opcode = C6OP_MODESELECT;
731: cdbp->c6_lun = _lun;
732: cdbp->c6_len = count;
733:
734: bcopy (&modeSelectParmsPtr->msp_data, alignedBuf, count);
735:
736: rtn = [self executeRequest:&scsiReq
737: buffer:alignedBuf
738: client:IOVmTaskSelf()
739: senseBuf: _senseDataPtr];
740:
741: IOFree(freePtr, freeCnt);
742: return rtn;
743: } /* - stModeSelect: */
744:
745:
746:
747:
748: - (sc_status_t) stModeSense: (struct modesel_parms *) modeSenseParmsPtr
749: {
750: IOSCSIRequest scsiReq;
751: cdb_6_t *cdbp = &scsiReq.cdb.cdb_c6;
752: int count = modeSenseParmsPtr->msp_bcount;
753: struct mode_sel_data *alignedBuf;
754: void *freePtr;
755: int freeCnt;
756: sc_status_t rtn;
757: IODMAAlignment dmaAlign;
758:
759: alignedBuf = [_controller
760: allocateBufferOfLength: count
761: actualStart: &freePtr
762: actualLength: &freeCnt];
763:
764:
765: bzero(&scsiReq, sizeof(IOSCSIRequest));
766:
767: scsiReq.target = _target;
768: scsiReq.lun = _lun;
769: scsiReq.read = YES;
770:
771: [_controller getDMAAlignment:&dmaAlign];
772: if(dmaAlign.readLength > 1) {
773: scsiReq.maxTransfer = IOAlign(int, count,
774: dmaAlign.readLength);
775:
776: } else {
777: scsiReq.maxTransfer = count;
778: }
779:
780: scsiReq.timeoutLength = ST_IOTO_NORM;
781: scsiReq.disconnect = 1;
782: cdbp->c6_opcode = C6OP_MODESENSE;
783: cdbp->c6_lun = _lun;
784: cdbp->c6_len = count;
785:
786: rtn = [self executeRequest:&scsiReq
787: buffer:alignedBuf
788: client:IOVmTaskSelf()
789: senseBuf: _senseDataPtr];
790:
791: if(rtn == SR_IOST_GOOD) {
792: bcopy (alignedBuf, &modeSenseParmsPtr->msp_data, count);
793: }
794:
795: IOFree(freePtr, freeCnt);
796: return rtn;
797: } /* - stModeSense: */
798:
799:
800:
801: - (sc_status_t) executeMTOperation: (struct mtop *) mtopp
802: {
803: IOSCSIRequest scsiReq;
804: cdb_6s_t *cdbp = &scsiReq.cdb.cdb_c6s;
805: int count;
806: sc_status_t rtn;
807:
808: bzero(&scsiReq, sizeof(IOSCSIRequest));
809: scsiReq.target = _target;
810: scsiReq.lun = _lun;
811: scsiReq.timeoutLength = ST_IOTO_NORM; /* Some ops override this */
812: scsiReq.disconnect = 1; // XXX - maybe not for all ops.
813:
814: /*
815: * none of these operations performs DMA. For each, just fill in
816: * the cdb, and pass it to the controller.
817: */
818:
819: /* build a CDB */
820:
821: switch(mtopp->mt_op) {
822: case MTWEOF: /* write file marks */
823: cdbp->c6s_opcode = C6OP_WRTFM;
824: goto setcount_f;
825:
826: case MTFSF: /* space file marks forward */
827: cdbp->c6s_opcode = C6OP_SPACE;
828: cdbp->c6s_opt = C6OPT_SPACE_FM;
829: scsiReq.timeoutLength = mtopp->mt_count * ST_IOTO_SPFM;
830: goto setcount_f;
831:
832: case MTBSF: /* space file marks backward */
833: cdbp->c6s_opcode = C6OP_SPACE;
834: cdbp->c6s_opt = C6OPT_SPACE_FM;
835: scsiReq.timeoutLength = mtopp->mt_count * ST_IOTO_SPFM;
836: goto setcount_b;
837:
838: case MTFSR: /* space records forward */
839: cdbp->c6s_opcode = C6OP_SPACE;
840: cdbp->c6s_opt = C6OPT_SPACE_LB;
841: scsiReq.timeoutLength = ST_IOTO_SPR;
842: setcount_f:
843: assign_cdb_c6s_len (cdbp, mtopp->mt_count);
844: break;
845:
846: case MTBSR: /* space records backward */
847: cdbp->c6s_opcode = C6OP_SPACE;
848: cdbp->c6s_opt = C6OPT_SPACE_LB;
849: scsiReq.timeoutLength = ST_IOTO_SPR;
850: setcount_b:
851: count = 0 - mtopp->mt_count;
852: assign_cdb_c6s_len (cdbp, count);
853: break;
854:
855: case MTREW: /* rewind */
856: cdbp->c6s_opcode = C6OP_REWIND;
857: scsiReq.timeoutLength = ST_IOTO_RWD;
858: break;
859:
860: case MTOFFL: /* set offline */
861: cdbp->c6s_opcode = C6OP_STARTSTOP;
862: /* note load bit is 0 */
863: scsiReq.timeoutLength = ST_IOTO_RWD;
864: break;
865:
866: case MTNOP: /* nop / get status */
867: case MTCACHE: /* enable cache */
868: case MTNOCACHE: /* disable cache */
869: case MTRETEN:
870: case MTERASE:
871: default:
872: rtn = SR_IOST_CMDREJ; /* FIXME: unsupported? */
873: goto out;
874: }
875:
876: rtn = [self executeRequest: &scsiReq
877: buffer: NULL
878: client: IOVmTaskSelf()
879: senseBuf: _senseDataPtr];
880: out:
881: return rtn;
882: } /* - executeMTOperation: */
883:
884:
885:
886: /*
887: * Set block size for SCSI tape device.
888: *
889: * blocksize == 0 --> variable
890: * blocksize != 0 --> fixed @ blocksize
891: *
892: * First, execute mode sense, then mode select with block length
893: * set to 0 (variable) or blocksize (fixed)
894: */
895: - (IOReturn) setBlockSize: (int) blockSize
896: {
897: int rtn;
898: struct modesel_parms *mspp;
899: struct mode_sel_hdr *mshp;
900:
901: mspp = IOMalloc (sizeof(struct modesel_parms));
902: mspp->msp_bcount = sizeof(struct mode_sel_hdr) +
903: sizeof(struct mode_sel_bd);
904:
905: if((rtn = [self stModeSense: mspp]) != SR_IOST_GOOD) {
906: IOFree (mspp, sizeof (struct modesel_parms));
907: return [_controller returnFromScStatus: rtn];
908: }
909:
910: mshp = &mspp->msp_data.msd_header;
911: mshp->msh_sd_length_0 = 0;
912: mshp-> msh_med_type = 0;
913: mshp-> msh_wp = 0;
914: mshp-> msh_bd_length = sizeof(struct mode_sel_bd);
915: assign_msbd_blocklength
916: (&mspp->msp_data.msd_blockdescript, blockSize);
917: assign_msbd_numblocks
918: (&mspp->msp_data.msd_blockdescript, 0);
919:
920: if((rtn = [self stModeSelect: mspp]) != SR_IOST_GOOD) {
921: IOFree (mspp, sizeof (struct modesel_parms));
922: return [_controller returnFromScStatus: rtn];
923: }
924:
925: _blockSize = blockSize;
926:
927: IOFree (mspp, sizeof (struct modesel_parms));
928: return IO_R_SUCCESS;
929: } /* - setBlockSize: */
930:
931:
932:
933:
934: /*
935: * Execute CDB. Buffer must be well aligned. If command results
936: * in Check Status, return the sense data in *senseBuf.
937: */
938: - (sc_status_t) executeRequest: (IOSCSIRequest *)scsiReq
939: buffer:(void *) buffer /* data destination */
940: client:(vm_task_t) client
941: senseBuf:(esense_reply_t *) senseBuf
942: {
943: sc_status_t rtn;
944:
945: _senseDataValid = NO;
946:
947: #ifdef DEBUG
948: IOLog("Entered SCSI Tape executeRequest: op %s, maxTransfer %d, len %d\n",
949: IOFindNameForValue(scsiReq->cdb.cdb_opcode,
950: IOSCSIOpcodeStrings),
951: scsiReq->maxTransfer,
952: (scsiReq->cdb.cdb_c6s.c6s_len2 << 16) |
953: (scsiReq->cdb.cdb_c6s.c6s_len1 << 8) |
954: (scsiReq->cdb.cdb_c6s.c6s_len0));
955: #endif DEBUG
956:
957: rtn = [_controller executeRequest:scsiReq
958: buffer:buffer
959: client:client];
960:
961: #ifdef DEBUG
962: IOLog ("Length %d on return from executeRequest\n", scsiReq->bytesTransferred);
963: #endif DEBUG
964:
965: /*
966: * Log error returns.
967: */
968: if (rtn != SR_IOST_GOOD) {
969: /*
970: * If result is Check Condition, do a Request Sense, unless suppressed.
971: */
972: if(rtn == SR_IOST_CHKSV) {
973: /*
974: * Host Adaptor already got us sense data. Give sense data
975: * to user and save it.
976: */
977: *senseBuf = *_senseDataPtr = scsiReq->senseData;
978: _senseDataValid = YES;
979: }
980: if (((rtn == SR_IOST_CHKSNV) || (rtn == SR_IOST_CHKSV)) &&
981: !_ignoreCheckCondition) {
982: if(rtn == SR_IOST_CHKSV) {
983: rtn = SR_IOST_GOOD;
984: }
985: else {
986: rtn = [self requestSense: senseBuf];
987: }
988: if(rtn == SR_IOST_GOOD) {
989: /*
990: * If the error is a filemark, and we are reading,
991: * then return no error. Otherwise, return
992: * check sense, with valid sense data.
993: */
994: if ((scsiReq->cdb.cdb_c6.c6_opcode == C6OP_READ) &&
995: (senseBuf->er_filemark)) {
996:
997: /*
998: * Check for correct reporting of bytes transferred.
999: * (This works around a DPT firmware bug.)
1000: */
1001: int transferLength =
1002: cdb_c6s_len_value (&scsiReq->cdb.cdb_c6s) -
1003: er_info_value (senseBuf);
1004:
1005: if ([self isFixedBlock]) {
1006: transferLength = transferLength * _blockSize;
1007: }
1008:
1009: if (scsiReq->bytesTransferred != transferLength) {
1010: #ifdef DEBUG
1011: IOLog ("%s: Incorrect byte count reported - "
1012: "corrected to %d\n", [self name], transferLength);
1013: #endif DEBUG
1014: scsiReq->bytesTransferred = transferLength;
1015: }
1016:
1017: rtn = SR_IOST_GOOD;
1018: scsiReq->driverStatus = SR_IOST_GOOD;
1019:
1020: #ifdef DEBUG
1021: IOLog ("execReq sense: er_filemark %d, er_badlen %d, er_sensekey %d, er_addsensecode %d, er_qualifier %d, er_info %d\n",
1022: senseBuf->er_filemark, senseBuf->er_badlen, senseBuf->er_sensekey,
1023: senseBuf->er_addsensecode, senseBuf->er_qualifier,
1024: er_info_value (senseBuf));
1025: #endif DEBUG
1026:
1027: }
1028: else {
1029: rtn = SR_IOST_CHKSV;
1030: }
1031: }
1032: else {
1033: if (_isInitialized) {
1034: IOLog("%s: Request Sense on target %d lun %d "
1035: "failed (%s)\n",
1036: [self name], _target, _lun,
1037: IOFindNameForValue(rtn, IOScStatusStrings));
1038: }
1039: rtn = SR_IOST_CHKSNV;
1040: }
1041: }
1042:
1043: /*
1044: * Log error messages, except the spate of timeouts and
1045: * device not ready messages during initialization.
1046: */
1047: if (_isInitialized &&
1048: (rtn != SR_IOST_GOOD) &&
1049: !_ignoreCheckCondition) {
1050:
1051: IOLog("%s, target %d, lun %d: op %s returned %s\n",
1052: [self name], _target, _lun,
1053: IOFindNameForValue(scsiReq->cdb.cdb_opcode,
1054: IOSCSIOpcodeStrings),
1055: IOFindNameForValue(rtn, IOScStatusStrings));
1056:
1057: if (rtn == SR_IOST_CHKSV) {
1058: IOLog (" Sense key = 0x%x Sense Code = 0x%x\n",
1059: senseBuf->er_sensekey, senseBuf->er_addsensecode);
1060: }
1061: }
1062:
1063: _didWrite = NO;
1064: }
1065:
1066: else {
1067: /* Remember good writes for device close */
1068: if (scsiReq->cdb.cdb_opcode == C6OP_WRITE) {
1069: _didWrite = YES;
1070: } else {
1071: _didWrite = NO;
1072: }
1073: }
1074:
1075: return rtn;
1076: } /* executeRequest: */
1077:
1078: @end
1079:
1080: /*
1081: * Supporting functions.
1082: */
1083:
1084: /*
1085: * moveString is taken directly from SCSIDiskPrivate.m.
1086: * It's used by -initSCSITape:
1087: *
1088: * Copy inp to outp for up to inlength input characters or outlength output
1089: * characters. Compress multiple spaces and eliminate nulls. Returns number
1090: * of characters copied to outp.
1091: */
1092: static int
1093: moveString(char *inp, char *outp, int inlength, int outlength)
1094: {
1095: int lastCharSpace = 0;
1096: char *outpStart = outp;
1097:
1098: while(inlength && outlength) {
1099: switch(*inp) {
1100: case '\0':
1101: inp++;
1102: inlength--;
1103: continue;
1104: case ' ':
1105: if(lastCharSpace) {
1106: inp++;
1107: inlength--;
1108: continue;
1109: }
1110: lastCharSpace = 1;
1111: goto copyit;
1112: default:
1113: lastCharSpace = 0;
1114: copyit:
1115: *outp++ = *inp++;
1116: inlength--;
1117: outlength--;
1118: break;
1119: }
1120: }
1121: return(outp - outpStart);
1122: }
1123:
1124:
1125:
1126: void
1127: assign_cdb_c6s_len (struct cdb_6s *cdbp, int length)
1128: {
1129: #if __BIG_ENDIAN__
1130: #if __NATURAL_ALIGNMENT__
1131: cdbp->c6s_len[0] = (length >> 16) & 0xff;
1132: cdbp->c6s_len[1] = (length >> 8) & 0xff;
1133: cdbp->c6s_len[2] = length & 0xff;
1134:
1135: #else __NATURAL_ALIGNMENT__
1136:
1137: cdbp->c6s_len = length;
1138:
1139: #endif __NATURAL_ALIGNMENT__
1140:
1141:
1142: #elif __LITTLE_ENDIAN__
1143:
1144: cdbp->c6s_len0 = (u_char) length & 0xff;
1145: cdbp->c6s_len1 = (u_char) (length >> 8) & 0xff;
1146: cdbp->c6s_len2 = (u_char) (length >> 16) & 0xff;
1147:
1148: #endif
1149:
1150: return;
1151: }
1152:
1153: void
1154: assign_msbd_numblocks (struct mode_sel_bd *msbdp, int numblocks)
1155: {
1156: #if __BIG_ENDIAN__
1157: msbdp->msbd_numblocks = numblocks;
1158: #elif __LITTLE_ENDIAN__
1159: msbdp->msbd_numblocks0 = (u_char) numblocks & 0xff;
1160: msbdp->msbd_numblocks1 = (u_char) (numblocks >> 8) & 0xff;
1161: msbdp->msbd_numblocks2 = (u_char) (numblocks >> 16) & 0xff;
1162: #endif
1163: return;
1164: }
1165:
1166: void
1167: assign_msbd_blocklength (struct mode_sel_bd *msbdp, int length)
1168: {
1169: #if __BIG_ENDIAN__
1170: msbdp->msbd_blocklength = length;
1171: #elif __LITTLE_ENDIAN__
1172: msbdp->msbd_blocklength0 = (u_char) length & 0xff;
1173: msbdp->msbd_blocklength1 = (u_char) (length >> 8) & 0xff;
1174: msbdp->msbd_blocklength2 = (u_char) (length >> 16) & 0xff;
1175: #endif
1176: return;
1177: }
1178:
1179: int
1180: cdb_c6s_len_value (struct cdb_6s *cdbp)
1181: {
1182: #if __BIG_ENDIAN__
1183: return (cdbp->c6s_len);
1184: #elif __LITTLE_ENDIAN__
1185: return (cdbp->c6s_len0 | (cdbp->c6s_len1 << 8) | (cdbp->c6s_len2 << 16));
1186: #endif
1187: }
1188:
1189: int
1190: er_info_value (struct esense_reply *esrp)
1191: {
1192: #if __BIG_ENDIAN__
1193: return (esrp->er_info);
1194: #elif __LITTLE_ENDIAN__
1195: return (esrp->er_info0 | (esrp->er_info1 << 8) |
1196: (esrp->er_info2 << 16) | (esrp->er_info3 << 24));
1197: #endif
1198: }
1199:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.