migh@cuuxb.ATT.COM (~XT6561110~Mike Hall~C24~M26a~6029~) (12/20/89)
= In article <1753@agora.UUCP> billsey@.UUCP (Bill Seymour) writes: = >In article <1842@sauron.Columbia.NCR.COM: stevem@sauron.UUCP (Steve McClure) writes: = This is good news, thanks Bill. I had talked to Supra and was told flatly = there was no example code. I did however have minimal success using the = device. SCSI devices responded, but I did not figure out how to read the = results of an Inquiry. In the back of Xetec's manual, they list a one-page routine to do "SCSI direct". They use the "harddisk.device", however. Is that going to be non-standard? As for reading/interpreting the Inquiry data... I'm glad you asked! I was going to post this today, and you've given me a nice lead-in.. Thank you! What follows is a shell archive of "inq.c" - the guy that examines the Inquiry response, and two other files. I didn't like the way that Xetec's implementation of accessing the SCSI device was so dense: open everything, do it, close everything. (I want to write a tape application that actually works - unlike their own product...grrr.) Sooo... I chopped it up into OpenSCSI, DoSCSI, and CloseSCSI. I've also invented a new structure to hold all the crap - SCSIcb (SCSI command block). I would appreciate near-lethal comments and criticisms of this code. It wasn't written in the wee hours, but it _was_ getting pretty late... :-) Thanks! --- cut here --- --- --- --- --- --- --- --- --- --- # The rest of this file is a shell script which will extract: # inq.c scsinfc.c scsinfc.h echo x - inq.c cat >inq.c <<'!Funky!Stuff!' /* * SCSI Device Inquiry */ #include <exec/types.h> #include <exec/io.h> #include <devices/scsidisk.h> #include <FastTrak.h> #include "SCSInfc.h" #include <stdio.h> #include <string.h> #define MAX_PD_TYPE 10 char *pdtypes[] = { "disk", "tape", "printer", "processor", "worm", "rodisk", "scanner", "optical", "changer", "communication", "(unknown)" }; #define INQRESP 128 long resp[INQRESP/4]; /* Inquiry response - watch alignment! */ char cdb[10] = /* SCSI command itself (ditto!) */ { 0x12, 0, 0, 0, INQRESP, 0, 0, 0, 0, 0 }; struct SCSIcb scb; /* general SCSI control block */ void showinfo(unit, params) short unit; char params[]; { char vendor[10], product[18], prodrev[6]; int rmb, devtype; devtype = params[0]; if ( devtype < 0 || devtype > MAX_PD_TYPE ) devtype = MAX_PD_TYPE+1; rmb = params[1]&0x80; strncpy(vendor, ¶ms[8], 8); vendor[8] = '\0'; strncpy(product, ¶ms[16], 16); product[16] = '\0'; strncpy(prodrev, ¶ms[32], 4); prodrev[4] = '\0'; printf(" \033[1m%d\033[0m: %s %s \033[7m%s\033[0m \033[7m%s\033[0m \033[7m%s\033[0m\n", unit, rmb ? "Removable" : "Non-removable", pdtypes[devtype], vendor, product, prodrev); } void showfail(unit, r) short unit, r; { printf(" \033[1m%d\033[0m: \033[3;33mfail, %s\033[0;31m\n", unit, fterrmsg(r)); } void inquire(unit) int unit; { int r; scb.unit = unit; scb.SCmd.scsi_Data = (APTR) resp; scb.SCmd.scsi_Length = INQRESP; scb.SCmd.scsi_Command = cdb; scb.SCmd.scsi_CmdLength = 6; scb.SCmd.scsi_Flags = SCSIF_READ; if ( r = OpenSCSI(&scb) ) { showfail(unit, r); return; } else if ( (r = DoSCSI(&scb)) ) { showfail(unit, r); } else { showinfo(unit, resp); } CloseSCSI(&scb); } void main(argc,argv) int argc; char *argv[]; { int unit; if ( argc > 2 || *argv[1] == '?' || /* bad args */ (*argv[1] == '-' && argv[1][1] == '?') ) { /* (poor code!) */ printf("Usage: %ls <unit>\n",argv[0]); exit(FALSE); } else if ( argc == 1 ) { /* no args: do all */ for ( unit = 0; unit <= 7; unit++ ) inquire(unit); } else { /* one arg: do one */ unit = atoi(argv[1]); if ( unit < 0 || unit > 7 ) { printf("Use: %ls <unit>\n", argv[0]); exit(FALSE); } inquire(unit); } } !Funky!Stuff! echo x - scsinfc.c cat >scsinfc.c <<'!Funky!Stuff!' /* * SCSI general interface routines */ #include <exec/types.h> #include <exec/io.h> #include <devices/scsidisk.h> #include <FastTrak.h> #include "scsinfc.h" int OpenSCSI(scb) struct SCSIcb *scb; { int ret; scb->flags = 0; if ( scb->Port = (struct MsgPort *)CreatePort("ft_Tools",0) ) { if ( scb->Req = (struct IOStdReq *)CreateStdIO(scb->Port) ) { if ( ret = OpenDevice("harddisk.device", scb->unit, scb->Req, 0) ) { DeleteStdIO(scb->Req); DeletePort(scb->Port); } else { scb->flags = 1; scb->Req->io_Command = 28; scb->Req->io_Data = (APTR)&scb->SCmd; scb->Req->io_Length = sizeof(struct SCSICmd); } } } return ret; } void CloseSCSI(scb) struct SCSIcb *scb; { if ( scb->flags ) { AbortIO(scb->Req); WaitIO(scb->Req); CloseDevice(scb->Req); scb->flags = 0; } if ( scb->Req ) { DeleteStdIO(scb->Req); scb->Req = NULL; } if ( scb->Port ) { DeletePort(scb->Port); scb->Port = NULL; } } int DoSCSI(scb) struct SCSIcb *scb; { DoIO(scb->Req); /* Or... SendIO(req); WaitIO(req); */ /* Actual = scb->SCmd.scsi_Actual; */ return (int) scb->SCmd.scsi_Status; } /* * Return error message given FastTrak error code */ char *fterrmsg(err) int err; { switch (err) { case FTERR_SelfUnit: return "cannot issue SCSI command to self"; case FTERR_DMA: return "DMA error"; case FTERR_Phase: return "illegal or unexpected SCSI phase"; case FTERR_Parity: return "SCSI parity error"; case FTERR_SelTimeout: return "select timed out"; case FTERR_BadStatus: return "status and/or sense error"; case FTERR_NoBoard: return "open failed for non-existant board"; default: return "unknown error"; } } !Funky!Stuff! echo x - scsinfc.h cat >scsinfc.h <<'!Funky!Stuff!' /* * definitions for SCSInfc.c */ struct SCSIcb { /* SCSI control block */ short flags; /* open or not */ short unit; /* which SCSI unit this is for */ struct IOStdReq *Req; /* IORequest */ struct MsgPort *Port; /* and Message Port */ struct SCSICmd SCmd; /* and the SCSI Command ptrs */ }; int OpenSCSI(struct SCSIcb *); void CloseSCSI(struct SCSIcb *); int DoSCSI(struct SCSIcb *); char *fterrmsg(int); !Funky!Stuff! ------ that's all --- Mike Hall att!cuuxb!migh migh@cuuxb.att.com