Path: utzoo!attcan!uunet!portal!cup.portal.com!ts From: ts@cup.portal.com (Tim W Smith) Newsgroups: comp.sys.mac.programmer Subject: Re: Simple instructional SCSI manager program wanted Message-ID: <13264@cup.portal.com> Date: 7 Jan 89 09:28:15 GMT References: <4451@Portia.Stanford.EDU> Organization: The Portal System (TM) Lines: 87 Here's a function that will show using the SCSI manager. It is used to perform 6 byte SCSI commands that will have a DATA IN phase. SCSI6read( id, a, b, c, d, e, f, buf, len ) int id; char a, b, c, d, e, f; char * buf; int len; { char block[6]; int stat, mesg; SCSIInstr t[2]; int result; t[0].scOpcode = scNoInc; t[0].scParam1 = (long)buf; t[0].scParam2 = len; t[1].scOpcode = scStop; t[1].scParam1 = 0; t[1].scParam2 = 0; block[0] = a; block[1] = b; block[2] = c; block[3] = d; block[4] = e; block[5] = f; if ( SCSIGet() ) return -1; if ( SCSISelect( id ) ) return -2; if ( SCSICmd( block, 6 ) ) return -3; result = SCSIRead(t); if ( SCSIComplete( &stat, &mesg, 180L ) ) return -5; if ( result ) return -4; return (stat<<8) | mesg; } Usage is result=SCSI6read( target_id, cmd_byte0, ... , cmd_byte5, buffer_pointer, buffer_length ); For example, SCSI6read( 0, 18, 0, 0, 0, 128, 0, buffer, 128 ) would fill memory at address "buffer" with the data returned by an INQUIRY command on target 0. Up to 128 bytes of inquiry data would be returned. result will be -1 to -5 if a SCSI Manager call fails, otherwise, it will be the status and message returned by SCSIComplete. Note that if one does a SCSICmd() that does not get an error, one must at some point do SCSIComplete(), or the bus will be hung. Thus, if SCSIRead or SCSIWrite fails, you must still do the SCSIComplete. Tim Smith ps: I have found a certain set of functions useful for my SCSI work. Here is an overview: SCSI6read, SCSI6write, and SCSI6cmd are similar to the example above, and are used for commands with DATA IN, DATA OUT, or no DATA phase. However, these are not implemented like the above example. Rather, they build the command block and TIB and call the next function, SCSIdoCmd. SCSIdoCmd has this interface: result = SCSIdoCmd( cmdBuf, cmdLen, tibPtr, bufPtr, bufLen, dirFlag ); where cmdBuf is a pointer to the command block, cmdLen is the length of the command block, tibPtr is a pointer to the TIB, or 0 if no DATA phase is expected, bufPtr and bufLen specify a buffer ( only used if tibPtr != 0 ), and dirFlag ( if tibPtr != 0 ) indicates the direction of data transfer. If I need the 10 byte commands, then SCSI10{read,write,cmd} are written. They are similar to SCSI6{read,write,cmd}. If you want to get fancy, you can make SCSIdoCmd do an automatic REQUEST SENSE when an error occurs, and store the result somewhere. You can even make it handle certain errors transparently ( for example, if the command fails because of a UNIT ATTENTION condition, you can make SCSIdoCmd retry the command ). Write these functions once and make them into a LightspeedC library and you can for the most part ignore the SCSI manager from then on. Also, it's a very good idea to go through some routines like this anyway, since Apple is going to be changing the SCSI manager sometime "soon" ( according to MACDTS ). If all your SCSI calls go through a set of routines like this, adpating to new SCSI Manager features will be easier.