This is SCSI.m in view mode; [Download] [Up]
// // SCSI.m // // SCSI generic driver object library (phew) // Version 3 (Revision 3.0) // // The SCSI class source, header, and documentation are all // Copyright (C) 1990 by Jiro Nakamura and Canon, Inc. // Copyright (C) 1991 by Jiro Nakamura and Canon, Inc. // Copyright (C) 1992 by Jiro Nakamura // All Rights Reserved. // // // Original Author: Jiro Nakamura // Created: June 12, 1990 // Last Modified: July 12, 1991 // // RCS Information // Revision Number-> $Revision: 3.1 $ // Last Revised-> $Date: 92/11/13 02:31:51 $ // static char rcsid[]="$Id: SCSI.m,v 3.1 92/11/13 02:31:51 jiro Exp Locker: jiro $"; static char copyrightid[]="$Copyright: Copyright (C) 1992 by Jiro Nakamura$"; #define VERSION 3 #import "SCSI.h" #import <libc.h> #import <stdio.h> #import <fcntl.h> #import <stdio.h> #import <objc/typedstream.h> #import <appkit/nextstd.h> // For NXLogError #import <appkit/Application.h> #import <appkit/Panel.h> // SCSI produces a whole truckload of debugging code. Usually we don't // want it on. #ifdef DEBUG #define DEBUG2 #undef DEBUG #endif @implementation SCSI +new { self = [super new]; target = -1; lun = 0; dev_name = "/dev/sg"; // last digit gets appended later scsiOpen = FALSE; return self; return self; } + (void )clearCommandBlock: (union cdb *) cd { int i; char *p; p = (char *)cd; for(i=0; i<sizeof(union cdb); i++) *p++ = 0; return; } - (int) version { return VERSION; } - (int) openSCSI { char tmpBuf[20]; unsigned int tmp; // *No* program should try to open a driver that's already open. // Bad, bad, bad. if( scsiOpen == TRUE) { sprintf(errorString, "SCSI Device already open -- " "bug in program..."); return fd; } for( tmp = 0; ; tmp ++) { sprintf(tmpBuf, "%s%1X", dev_name, tmp) ; #ifdef DEBUG fprintf(stderr, "SCSI: Opening device: %s\n", tmpBuf); #endif if( access(tmpBuf, F_OK) ) // no existo break; if( access(tmpBuf, R_OK | W_OK) ) // cannot access continue; if ((fd = open(tmpBuf, O_RDWR)) >= 0) { scsiOpen = TRUE; return 0; } } sprintf(errorString,"Could not open SCSI " "generic driver <%sX>.\n" "File descriptor = 0x%X\n", tmpBuf, (unsigned int) fd); perror("open"); scsiOpen = FALSE; return -1; } - (int) openSCSIAt: (int) trg lun: (int) ln { if( [self openSCSI] ) return -1; return( [self setTarget: trg lun: ln]); } - (int) setTarget: (int) trg lun: (int) ln { sa.sa_target = target = trg; sa.sa_lun = lun = ln; if (ioctl(fd,SGIOCSTL,&sa) < 0) { sprintf(errorString,"ioctl(SGIOCSTL): " "Error setting target %d lun %d (errno = %d)\n", target,lun, errno); return -1; } return 0; } - (int) closeSCSI { if( scsiOpen == FALSE) { sprintf(errorString, "SCSI device already closed. " "Error in program..."); return -1; } if ( close(fd) < 0) { sprintf(errorString, "Could not close %sX - fd = %XH\n" "errno = %d\n", dev_name, (unsigned int) fd ,errno); perror("close"); return -1; } scsiOpen = FALSE; return 0; } - (BOOL) scsiOpen { return( scsiOpen); } - (struct scsi_req *) statusReq { return &sr; } - (char *) errorString { return errorString; } - (int) findDevice { return [self findDevice: 0]; } - (int) findDevice: (int) trg { int tmp; if( scsiOpen) return [self findDeviceSCSI: trg]; else { if([self openSCSI] ) { sprintf(errorString,"Can't open SCSI driver"); return -1; } tmp = [self findDeviceSCSI: trg]; [self closeSCSI]; return( tmp); } } - (int) findDeviceSCSI: (int) trg { int tmp, oldTarg, oldLun; oldTarg = target; oldLun = lun; for( tmp = trg; tmp < 8; tmp ++) { if( [self setTarget: tmp lun: 0] ) continue; // no device if( [self isDeviceSCSI]) { [self setTarget: oldTarg lun: oldLun]; return( tmp); } } [self setTarget: oldTarg lun: oldLun]; return( -1); } - (BOOL) isDevice { BOOL tmp; if( scsiOpen) return [self isDeviceSCSI]; if([self openSCSI] ) { sprintf(errorString,"SCSI: Can't open SCSI driver"); NXLogError(errorString); return NO; } tmp = [self isDeviceSCSI]; [self closeSCSI]; return( tmp); } - (BOOL) isDeviceSCSI // Subclasses should implement this { [self subclassResponsibility: _cmd]; return NO; } // ===================================================== // Archiving methods // ===================================================== - write: (NXTypedStream *) stream { [super write: stream]; NXWriteTypes( stream, "ii**", &target, &lun, &dev_name, &errorString); return self; } - read: (NXTypedStream *) stream { [super read: stream]; NXReadTypes( stream, "ii**", &target, &lun, &dev_name, &errorString); return self; } // ===================================================== // Internal Routines // ===================================================== - (int) performSCSIRequest { if (ioctl(fd,SGIOCREQ, &sr) < 0) { #ifdef DEBUG printf("..Error executing ioctl\n"); printf("errno = %d\n",errno); #endif return errno; } #ifdef DEBUG fprintf(stderr, "SCSI Command %x ==> %d byte(s) in %d.%06d sec\n", sr.sr_cdb.cdb_c6.c6_opcode, sr.sr_dma_xfr, (int) sr.sr_exec_time.tv_sec, (int) sr.sr_exec_time.tv_usec); #endif if(sr.sr_io_status || sr.sr_scsi_status) { #ifdef DEBUG2 fprintf(stderr, "sr_io_status = 0x%02X\n", (unsigned int) sr.sr_io_status); if(sr.sr_io_status == SR_IOST_CHKSV) { fprintf(stderr, " sense key = 0x%02X sense code = %02XH\n", (unsigned int) sr.sr_esense.er_sensekey, (unsigned int) sr.sr_esense.er_addsensecode); } fprintf(stderr, "SCSI status = 0x%02X\n", (unsigned int) sr.sr_scsi_status); #endif return sr.sr_io_status; } return 0; } // ===================================================== // SCSI ROUTINES AND MACROS // ===================================================== - (int) inquiry: (struct inquiry_reply *) ibuffer { int tmp; if( scsiOpen) return [self inquirySCSI: ibuffer]; else { if([self openSCSI] ) { sprintf(errorString,"Can't open SCSI driver"); return -1; } tmp = [self inquirySCSI: ibuffer]; [self closeSCSI]; return( tmp); } } - (int) inquirySCSI: (struct inquiry_reply *) ibuffer { struct cdb_6 *cdbp = &sr.sr_cdb.cdb_c6; [SCSI clearCommandBlock: (union cdb *) cdbp]; cdbp->c6_opcode = C6OP_INQUIRY; cdbp->c6_lun = lun; cdbp->c6_len = 36; sr.sr_dma_dir = SR_DMA_RD; sr.sr_addr = (char *) ibuffer; sr.sr_dma_max = 36; sr.sr_ioto = 10; return [self performSCSIRequest]; } - (int) readCapacity: (struct capacity_reply *) rbuffer { int tmp; if( scsiOpen) { return [self readCapacitySCSI: rbuffer]; } else { if([self openSCSI] ) { sprintf(errorString,"Can't open SCSI driver"); return -1; } tmp = [self readCapacitySCSI: rbuffer]; [self closeSCSI]; return( tmp); } } - (int) readCapacitySCSI: (struct capacity_reply *) rbuffer { struct cdb_10 *cdbp = &sr.sr_cdb.cdb_c10; [SCSI clearCommandBlock: (union cdb *) cdbp]; cdbp->c10_opcode = C10OP_READCAPACITY; cdbp->c10_lun = lun; cdbp->c10_len = 0; sr.sr_dma_dir = SR_DMA_RD; sr.sr_addr = (char *) rbuffer; sr.sr_dma_max = 8; sr.sr_ioto = 10; return [self performSCSIRequest]; } - (int) requestSense: (union esenseReply *) rbuffer { int tmp; if( scsiOpen) return [self requestSenseSCSI: rbuffer]; else { if([self openSCSI] ) { sprintf(errorString,"Can't open SCSI driver"); return -1; } tmp = [self requestSenseSCSI: rbuffer]; [self closeSCSI]; return( tmp); } } - (int) requestSenseSCSI: (union esenseReply *) buffer { struct cdb_6 *cdbp = &sr.sr_cdb.cdb_c6; [SCSI clearCommandBlock: (union cdb *) cdbp]; cdbp->c6_opcode = C6OP_REQSENSE; cdbp->c6_lun = lun; cdbp->c6_len = sizeof(*buffer); sr.sr_dma_dir = SR_DMA_RD; sr.sr_addr = (char *) buffer; sr.sr_dma_max = sizeof(*buffer); sr.sr_ioto = 10; return [self performSCSIRequest]; } - (int) receiveDiagnosticAlloc: (int) alloc buffer: (char *) buffer { int tmp; if( scsiOpen) return [self receiveDiagnosticSCSIAlloc: alloc buffer: buffer]; else { if([self openSCSI] ) { sprintf(errorString,"Can't open SCSI driver"); return -1; } tmp = [self receiveDiagnosticSCSIAlloc: alloc buffer: buffer]; [self closeSCSI]; return( tmp); } } - (int) receiveDiagnosticSCSIAlloc: (int) alloc buffer: (char *) buffer { struct cdb_6 *cdbp = &sr.sr_cdb.cdb_c6; [SCSI clearCommandBlock: (union cdb *) cdbp]; cdbp->c6_opcode = C6OP_RECEIVEDIAG; cdbp->c6_lun = lun; cdbp->c6_len = alloc; sr.sr_dma_dir = SR_DMA_RD; sr.sr_addr = (char *) buffer; sr.sr_dma_max = alloc; sr.sr_ioto = 10; return [self performSCSIRequest]; } - (int) sendDiagnosticPf: (BOOL) pf selfTest: (BOOL) st deviceOffLine: (BOOL) dol unitOffLine: (BOOL) uol parameterListLength: (int) pll parameterBuffer: (char *) pbuf { int tmp; if( scsiOpen) return [self sendDiagnosticSCSIPf: pf selfTest: st deviceOffLine: dol unitOffLine: uol parameterListLength: pll parameterBuffer: pbuf]; else { if([self openSCSI] ) { sprintf(errorString,"Can't open SCSI driver"); return -1; } tmp = [self sendDiagnosticSCSIPf: pf selfTest: st deviceOffLine: dol unitOffLine: uol parameterListLength: pll parameterBuffer: pbuf]; [self closeSCSI]; return( tmp); } } - (int) sendDiagnosticSCSIPf: (BOOL) pf selfTest: (BOOL) st deviceOffLine: (BOOL) dol unitOffLine: (BOOL) uol parameterListLength: (int) pll parameterBuffer: (char *) pbuf { struct cdb_6 *cdbp = &sr.sr_cdb.cdb_c6; [SCSI clearCommandBlock: (union cdb *) cdbp]; cdbp->c6_opcode = C6OP_SENDDIAG; cdbp->c6_lun = lun; cdbp->c6_lba = (pf << 20) + (st << 18) + (dol << 17) + (uol << 16) + ((((unsigned int) pll & 0xff00) >> 8) & 0x00ff); cdbp->c6_len = (unsigned int) pll & 0x00ff; sr.sr_dma_dir = SR_DMA_WR; sr.sr_addr = pbuf; sr.sr_dma_max = pll; sr.sr_ioto = 10; #ifdef DEBUG printf("Send diagnostic\n"); printf("LBA = %08X\n", cdbp->c6_lba); printf("Len = %04X\n", cdbp->c6_len); printf("St = %d\n", st); #endif return [self performSCSIRequest]; } - (int) testUnitReady { int tmp; if( scsiOpen) return [self testUnitReadySCSI]; else { if([self openSCSI] ) { sprintf(errorString,"Can't open SCSI driver"); return -1; } tmp = [self testUnitReadySCSI]; [self closeSCSI]; return( tmp); } } - (int) testUnitReadySCSI { struct cdb_6 *cdbp = &sr.sr_cdb.cdb_c6; [SCSI clearCommandBlock: (union cdb *) cdbp]; cdbp->c6_opcode = C6OP_TESTRDY; cdbp->c6_lun = lun; cdbp->c6_len = 0; sr.sr_dma_dir = SR_DMA_RD; sr.sr_addr = (char *) 0; sr.sr_dma_max = 0; sr.sr_ioto = 10; return([self performSCSIRequest]); } - (int) modeSensePage: (int) page pc: (int) pc dbd: (BOOL) dbd mpbuf: (struct mode_parameters *) mpbuf; { int tmp; if( scsiOpen) return [self modeSenseSCSIPage: page pc: pc dbd: dbd mpbuf: mpbuf]; else { if([self openSCSI] ) { sprintf(errorString,"Can't open SCSI driver"); return -1; } tmp = [self modeSenseSCSIPage: page pc: pc dbd: dbd mpbuf: mpbuf]; [self closeSCSI]; return( tmp); } } - (int) modeSenseSCSIPage: (int) page pc: (int) pc dbd: (BOOL) dbd mpbuf: (struct mode_parameters *) mpbuf; { struct cdb_6 *cdbp = &sr.sr_cdb.cdb_c6; char *bufferPointer; int returnValue, i; int pageDataLength, pdOffset; char *pageBeginning; if( (bufferPointer = malloc( MODESENSEBUFLENGTH )) == NULL ) { NXRunAlertPanel("Out of Virtual Memory", "Inexplicably, this program has run out " "of virtual memory. We must quit (and you " "should reboot).", "Quit", NULL, NULL ); [NXApp terminate: self]; } bzero( bufferPointer, MODESENSEBUFLENGTH); [SCSI clearCommandBlock: (union cdb *) cdbp]; cdbp->c6_opcode = C6OP_MODESENSE; cdbp->c6_lun = lun; cdbp->c6_lba = (((unsigned int) dbd) << 19) + (((unsigned int) pc) << 14) + (((unsigned int) page) << 8); cdbp->c6_len = 200; sr.sr_dma_dir = SR_DMA_RD; sr.sr_addr = (char *) bufferPointer; sr.sr_dma_max = 256; sr.sr_ioto = 10; returnValue = [self performSCSIRequest]; #ifdef DEBUG printf("Mode Sense: Return value = %d\n", returnValue); printf("LBA = %08X\n", cdbp->c6_lba); printf("Len = %04X\n", cdbp->c6_len); #endif *mpbuf = * ((struct mode_parameters *) bufferPointer); mpbuf->blockDescriptorCount = mpbuf->mph.dad.blockDescriptorLength / 8; pageDataLength = mpbuf->mph.dad.modeDataLength - 3 - mpbuf->mph.dad.blockDescriptorLength; pageBeginning = bufferPointer + 4 + mpbuf->mph.dad.blockDescriptorLength; #ifdef DEBUG2 fprintf(stderr,"Page Data Length = %d, " "Block Desc Length = %d\n", pageDataLength, mpbuf->mph.dad.blockDescriptorLength); #endif for( i = 0; i < mpbuf->blockDescriptorCount; i ++ ) { #ifdef DEBUG2 fprintf(stderr,"Printing block descriptor #%d\n", i); #endif mpbuf->mpbd[i] = * (struct ModeParameterBlockDescriptor *) (bufferPointer + 4 + (8 * i)); } if( pageDataLength <= 2) { mpbuf->pageCount = 0; return -1; } pdOffset = 0; for( mpbuf->pageCount =0; pdOffset < pageDataLength && mpbuf->pageCount < MAXPAGES; mpbuf->pageCount ++) { mpbuf->mpp[mpbuf->pageCount]= * ((union PageFormat *) pageBeginning + pdOffset); #ifdef DEBUG2 fprintf(stderr, "Page %d -- len %d (pdOffset %d)\n", mpbuf->pageCount, mpbuf->mpp[mpbuf->pageCount].genericPage. pageHeader.pageLength, pdOffset); #endif if( mpbuf->mpp[mpbuf->pageCount]. genericPage.pageHeader.pageLength == 0) break; pdOffset += mpbuf->mpp[mpbuf->pageCount].genericPage. pageHeader.pageLength; } free(bufferPointer); return returnValue; } - (const char *) identifyDeviceType: (struct inquiry_reply *) ibuffer { switch( ibuffer->ir_devicetype ) { case DEVTYPE_DISK: if( ibuffer->ir_removable == YES) return( "Removable-Disk" ); else return( "Hard-Drive" ); case DEVTYPE_TAPE: return( "Tape-Drive" ); case DEVTYPE_PRINTER: return( "Printer"); case DEVTYPE_PROCESSOR: return( "Processor" ); case DEVTYPE_WORM: if( ibuffer->ir_removable == YES) return( "Removable-Worm" ); else return( "Fixed-Worm" ); case DEVTYPE_CDROM: if( ibuffer->ir_removable == YES) return( "Removable-ReadOnly" ); else return( "Fixed-ReadOnly" ); case DEVTYPE_SCANNER: return( "Scanner" ); case DEVTYPE_OPTICAL: return( "Optical" ); case DEVTYPE_STILLVIDEO: return( "Still-Video" ); case DEVTYPE_NOTPRESENT: return( "No-Device" ); default: NXLogError("Unrecognized device type %02Xh (%d).", ibuffer->ir_devicetype , ibuffer->ir_devicetype ); return( "Not-Recognized" ); } } // ===================================================== // EXTERNAL LINKS FOR PROGRAMMERS // ===================================================== - (int) executeRequest: (struct scsi_req *) sp { int error; sr = *sp; error = [self performSCSIRequest]; *sp = sr; return error; } - (int) executeBusReset { if (ioctl(fd,SGIOCRST, NULL) < 0) { #ifdef DEBUG printf("..Error executing ioctl\n"); printf("errno = %d\n",errno); #endif return errno; } return 0; } - (char *) returnError: sender { char *driverStatus, *scsiStatus, *esense; return( [self returnDriverStatus: &driverStatus scsiStatus: &scsiStatus andExtendedSense: &esense] ); } - (char *) returnDriverStatus: (char **) driverStatus scsiStatus: (char **) scsiStatus andExtendedSense: (char **) esense { // we have three error codes // io_status -- Driver status // status -- scsi status byte returned by target // esense -- extended sense data static char stringBuffer[512]; #ifdef DEBUG fprintf( stderr, "Io_Status = %02Xh, Status = %02Xh.\n", sr.sr_io_status, sr.sr_scsi_status); #endif switch( sr.sr_io_status ) { case SR_IOST_GOOD: *driverStatus = "Command successful"; break; case SR_IOST_SELTO: *driverStatus = "Selection timeout"; break; case SR_IOST_CHKSV: *driverStatus = "Check target status and extended sense"; break; case SR_IOST_CHKSNV: *driverStatus = "Check target status"; break; case SR_IOST_DMAOR: *driverStatus = "Target attempted to move more than allocated " "amount of data bytes"; break; case SR_IOST_IOTO: *driverStatus = "Command timed out"; break; case SR_IOST_BV: *driverStatus = "SCSI Bus violation"; break; case SR_IOST_CMDREJ: *driverStatus = "Command rejected by driver"; break; case SR_IOST_MEMALL: *driverStatus = "Memory allocation failure"; break; case SR_IOST_MEMF: *driverStatus = "Memory fault"; break; case SR_IOST_PERM: *driverStatus = "Permission failure (not super user)"; break; case SR_IOST_NOPEN: *driverStatus = "Device not open"; break; case SR_IOST_TABT: *driverStatus = "Target aborted command"; break; case ST_IOST_BADST: *driverStatus = "Bad SCSI status byte " "(other than check status)"; break; case ST_IOST_INT: *driverStatus = "Internal driver error"; break; case SR_IOST_BCOUNT: *driverStatus = "Unexpected byte count seen on SCSI bus"; break; case SR_IOST_VOLNA: *driverStatus = "Desired volume not available"; break; case SR_IOST_WP: *driverStatus = "Media Write Protected"; break; default: *driverStatus = "Unrecognizable status"; break; } switch( sr.sr_scsi_status & STAT_VALIDMASK) { case STAT_GOOD: if( sr.sr_io_status == SR_IOST_GOOD ) *scsiStatus = "GOOD - Command successful"; else *scsiStatus = "Not Applicable " "(Command not executed)"; break; case STAT_CHECK: *scsiStatus = "CHECK CONDITION - " "Abnormal condition occured"; break; case STAT_CONDMET: *scsiStatus = "CONDITION MET / GOOD"; break; case STAT_BUSY: *scsiStatus = "BUSY - Target Busy"; break; case STAT_INTMGOOD: *scsiStatus = "INTERMEDIATE / GOOD"; break; case STAT_INTMCONDMET: *scsiStatus = "INTERMEDIATE / CONDITION MET / GOOD"; break; case STAT_RESERVED: *scsiStatus = "RESERVATION CONFLICT"; break; case STAT_TERMINATED: *scsiStatus = "COMMAND TERMINATED"; break; case STAT_QUEUEFULL: *scsiStatus = "QUEUE FULL"; break; default: *scsiStatus = "Unrecognizable status"; } switch( sr.sr_esense.er_sensekey ) { case SENSE_NOSENSE: *esense = "No error to report"; break; case SENSE_RECOVERED: *esense = "Recovered from error"; break; case SENSE_NOTREADY: *esense = "Target not ready"; break; case SENSE_MEDIA: *esense = "Media flaw"; break; case SENSE_HARDWARE: *esense = "Hardware failure"; break; case SENSE_ILLEGALREQUEST: *esense = "Illegal request"; break; case SENSE_UNITATTENTION: *esense = "Drive attention"; break; case SENSE_DATAPROTECT: *esense = "Drive access protected"; break; case SENSE_ABORTEDCOMMAND: *esense = "Target aborted command"; break; case SENSE_VOLUMEOVERFLOW: *esense = "End of media, some data not " "transfered"; break; case SENSE_MISCOMPARE: *esense = "Source/media data mismatch"; break; default: *esense = "Unrecognizable sense key"; break; } if( SR_IOST_CHKSV == sr.sr_io_status ) sprintf( stringBuffer, "\tDriver Status: \t%s\n" "\tTarget Status: \t%s\n" "\tExtended Sense: \t%s\n", *driverStatus, *scsiStatus, *esense); else { sprintf( stringBuffer, "\tDriver Status: \t%s\n" "\tTarget Status:\t%s\n", *driverStatus, *scsiStatus); *esense = NULL; } #ifdef DEBUG fprintf(stderr, "SCSI Completion string buf = %s\n", stringBuffer); #endif return stringBuffer; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.