#define DBGPRINT 1 #define MSEC 11 /* MSEC is wait before each scsi io$_diagnose gets done */ #ifdef DBGPRINT #include void waitabit(); #endif #ifdef MSEC #include #endif /* GKCONTROLV.C This program uses the SCSI generic class driver to send an inquiry command to a device on the SCSI bus. Alcita control version This module implements the device setup and read/write needed to control SCSI disks via the Alcita IDEplex board(s). It uses a limited number of commands to do this control. It is presumed that the device being controlled is indeed a disk of some kind. This "V" variant is meant to add the ability to deal with disks whose blocksize is a multiple of 512 bytes. Calling LBNs will be treated as 32 bit numbers since VMS works that way, but internally we will block and deblock. It is conceivable very large future disks with large blocksizes might be usable as several vms disks this way. */ #include ctype /* Define the descriptor used to pass the SCSI information to GKDRIVER */ /* following are offsets of longwords (or pointers in the case of addresses) in the 15-longword buffer */ /* 0 = SCSI operation code (cdrecord uses 1) 1 = SCSI flags (bitmapped) 2 = SCSI command buffer address 3 = SCSI command buffer length, bytes 4 = SCSI data buffer address 5 = SCSI data length, bytes 6 = SCSI pad length, bytes 7 = SCSI phase change timeout (sec) 8 = SCSI disconnect timeout (sec) 9 = SCSI sense buffer address (new drivers do request sense automatically) 10 = SCSI sense buffer length 11,12,13,14 = pad */ #define OPCODE 0 #define FLAGS 1 #define COMMAND_ADDRESS 2 #define COMMAND_LENGTH 3 #define DATA_ADDRESS 4 #define DATA_LENGTH 5 #define PAD_LENGTH 6 #define PHASE_TIMEOUT 7 #define DISCONNECT_TIMEOUT 8 #define SENSEADDR 9 #define SENSELEN 10 #define FLAGS_WRITE 0 #define FLAGS_READ 1 #define FLAGS_DISCONNECT 2 #define FLAGS_SYNCH 4 #define FLAGS_ASENSE 256 #define GK_EFN 1 #define SCSI_STATUS_MASK 0X3E #define INQUIRY_OPCODE 0x12 #define INQUIRY_DATA_LENGTH 0x30 #define ZRBLK 8192 /* ZRBLK is size of buffer in zrdriver, biggest thing we are gonna handle */ globalvalue IO$_DIAGNOSE; /* static global data */ /* Data storage. Use this to store one block from the device. (Later we could alter this to store several and use as a cache.) Keep track of what device block is stored here. Then supply calls to read a block or write a block. Ultimately there should be a buffer for the beginning and for the end of a long transfer so we could move a larger buffer all at once. For the present though, for devices of blocksize not equal to 512 let's just handle everything at once by doing a block at a time. First cut even let it write the block multiple times for each 512 bytes added...) */ static char Dbuff[ZRBLK]; static long pad1,pad2; static long Lbn; /* which large sized block number is in Dbuff */ static long Lbn512; /* 512 byte based LBN in Dbuff */ static long Blksz; static long Blkfc; /* block factor, i.e., multiple of 512 */ static short gk_chan, transfer_length; static int ixi, ixstatus, gk_device_desc[2], gk_iosb[2], gk_desc[15]; static char inquiry_cmd [6] = {18 , 0, 0, 0, 36, 0}, test_unit_ready_cmd [6] = {0, 0, 0, 0, 0, 0}, request_sense_cmd [6] = {3, 0, 0, 0, 18, 0}, start_unit_cmd [6] = {27, 1, 0, 0, 1, 0}, mode_sense_cmd [6] = {26, 0, 0x1, 0, 0x96, 0}, read_capacity_cmd [10] = {37, 0, 0, 0, 0, 0, 0, 0, 0, 0}, mode_select_cmd [6] = {21 , 0x1, 0, 0, 23, 0}, read_cmd [6] = {8, 0, 0, 0, 01, 0}, write_cmd [6] = {10, 0, 0, 0, 0, 0}, read10_cmd [10] = {0x28,0,0,0,0,0,0,0,01,0}, write10_cmd [10] = {0x2a,0,0,0,0,0,0,0,0,0}, reassign_blocks_cmd [6] = {7, 0, 0, 0, 0, 0}, rewind_command [6] = {1, 0, 0, 0, 0, 0}, weof_command[6] = {16, 0, 0,0,1,0}, inquiry_data[INQUIRY_DATA_LENGTH], mode_sel_data[23] = {0x00, 0x0, 0x0, 0x08, 0x00, 0x00, 0x00, 0x00, 00, 00, 02, 00, 0x1, 0x0a, 0xE0, 03, 0x0, 0x0, 00, 03, 0x0, 00, 0x0}; /* in write10_cmd, offset 2-5 is LBN, 7-8 is length in blocks */ int get_blk(short chan, char* buf, int lbn); int put_blk(short chan, char* buf, int lbn, int ithis, int itot); int dsk_setup(short chan, long *maxblk, int *cyl, int *sect, int *trks,int *blksize); int read_gk_blk(short chan, char* buf, long bytes, long lbn, long * got); int write_gk_blk(short chan, char* buf, long bytes, long lbn, long *bgot); int setr_command (short chan, char* cmd, int cmd_len, char* obuf, int data_len, long *got); int setw_command (short chan,char* cmd,int cmd_len,char* indata,int data_len, long *tlength); void sendd_command (short chan,char * cmd,int cmd_len,int data_len); void emit_command (short chan, char *cmd,int cmd_len,char * indata,int data_len); /* one=512-block get and put routines */ /* st = get_blk(chan, p, k); */ /* st = put_blk(chan, p, k, i, ii); */ /* chan = i/o chnl p = buffer pointer k = block number (512 byte blk measure) i = sub-blk we are doing this call ii = number sub-blocks we will do */ int get_blk(short chan, char* buf, int lbn) { /* if data is in Dbuf, just return it. If not go read it. */ int lbnlo, lbnhi; char* pp; char isensek; int k; char gbuf[512]; int status, scsi_status; int got; char sensedata[512]; int i,ii; int dostart = 0; /* zap the device only if several retries failed */ int iii; char * p; p = buf; k = lbn; lbnlo = Lbn512; lbnhi = Lbn512 + Blkfc - 1; if (Lbn512 != -1 && (k >= lbnlo && k <= lbnhi)){ /* Data is in buffer. Return it. */ pp = &Dbuff[(512*(k - lbnlo))]; for (ii=0; ii < 512; ii++){ *p = *pp; p++; pp++; } return (1); } else { /* Need to read data off disk */ Lbn512 = k; Lbn = k / Blkfc; Lbn512 = Lbn * Blkfc; /* fill in transfer length in blocks */ /* Round DOWN; we do not want to overwrite! */ /* actually set to read one block only */ read10_cmd[7] = 0; read10_cmd[8] = 1; /* notice 1 block transferred at a time! */ /* Fill in LBN */ ii = Lbn; read10_cmd[2] = (ii >>24) & 255; read10_cmd[3] = (ii >>16) & 255; read10_cmd[4] = (ii >>8) & 255; read10_cmd[5] = (ii ) & 255; /* Set up the descriptor with the SCSI information to be sent to the target */ gk_desc[OPCODE] = 1; gk_desc[FLAGS] = FLAGS_READ + FLAGS_SYNCH + FLAGS_ASENSE; /* note FLAGS_DISCONNECT omitted from above */ gk_desc[COMMAND_ADDRESS] = read10_cmd; gk_desc[COMMAND_LENGTH] = 10; gk_desc[DATA_ADDRESS] = Dbuff; gk_desc[DATA_LENGTH] = Blksz; gk_desc[PAD_LENGTH] = 0; gk_desc[PHASE_TIMEOUT] = 25; gk_desc[DISCONNECT_TIMEOUT] = 10; for (i=9; i<15; i++) gk_desc[i] = 0; /* Clear reserved fields */ gk_desc[SENSEADDR] = sensedata; gk_desc[SENSELEN] = 250; /* Issue the QIO to send the inquiry command and receive the inquiry data */ #ifdef MSEC waitabit(); #endif status = sys$qiow (GK_EFN, chan, IO$_DIAGNOSE, gk_iosb, 0, 0, &gk_desc[0], 15*4, 0, 0, 0, 0); /* Check the various returned status values */ if (!(status & 1)) return(status); if (!(gk_iosb[0] & 1)){ /* if something goes wrong with the write, try start unit followed by test unit ready to resynch */ dostart = dostart + 1; if (dostart > 5){ dostart = 0; i = setr_command(chan, start_unit_cmd, 6, gbuf, 0, &got); i = setr_command(chan, test_unit_ready_cmd, 6, gbuf, 0, &got); } return(4); } scsi_status = (gk_iosb[1] >> 24) & SCSI_STATUS_MASK; /* look at sense key; 0 or 1 are ok */ if (scsi_status){ isensek = sensedata[2] & 15; /* sense key 0 is normal return, 1 is recovered error */ if (isensek == 1 || isensek == 0){ scsi_status = 0; } } if (scsi_status) { /* if something goes wrong with the write, try start unit followed by test unit ready to resynch */ dostart = dostart + 1; if (dostart > 5){ dostart = 0; i = setr_command(chan, start_unit_cmd, 6, gbuf, 0, &got); i = setr_command(chan, test_unit_ready_cmd, 6, gbuf, 0, &got); } return(8); } /* command worked. Return success. */ dostart = 0; /* got = gk_iosb[0] >> 16;*/ /* of course, get the data first!!! */ k = lbn; lbnlo = Lbn512; /* Data is in buffer. Return it. */ pp = &Dbuff[(512*(k - lbnlo))]; p = buf; for (ii=0; ii < 512; ii++){ *p = *pp; p++; pp++; } return(status); } } /* put_blk */ int put_blk(short chan, char* buf, int lbn, int ithis, int itot){ /* If writing and the correct big block is in Dbuff now, just fill in the new part and write to disk. Otherwise read the correct block in, update our bit, and THEN write it out. */ int lbnlo, lbnhi; char* pp; int status, scsi_status; int got; int dostart = 0; char sensedata[512]; char isensek; int iii; int k,i,ii; char gbuf[512]; char * p; p = buf; k = lbn; lbnlo = Lbn512; lbnhi = Lbn512 + Blkfc - 1; if (Lbn512 != -1 && (k >= lbnlo && k <= lbnhi)){ /* Data is in buffer. Update it. */ pp = &Dbuff[(512*(k - lbnlo))]; for (ii=0; ii < 512; ii++){ *pp = *p; p++; pp++; } /* now write the mess out again to real disk */ /* Do this in final part */ } else { /* Need to read data off disk */ /* Note that block low 512-byte LBN is truncated */ Lbn = k / Blkfc; Lbn512 = Lbn * Blkfc; /* fill in transfer length in blocks */ /* Round DOWN; we do not want to overwrite! */ /* do one block only here */ read10_cmd[7] = 0; read10_cmd[8] = 1; /* Fill in LBN */ ii = Lbn; read10_cmd[2] = (ii >>24) & 255; read10_cmd[3] = (ii >>16) & 255; read10_cmd[4] = (ii >>8) & 255; read10_cmd[5] = (ii ) & 255; /* Set up the descriptor with the SCSI information to be sent to the target */ gk_desc[OPCODE] = 1; gk_desc[FLAGS] = FLAGS_READ + FLAGS_SYNCH + FLAGS_ASENSE; /* note FLAGS_DISCONNECT omitted from above */ gk_desc[COMMAND_ADDRESS] = read10_cmd; gk_desc[COMMAND_LENGTH] = 10; gk_desc[DATA_ADDRESS] = Dbuff; gk_desc[DATA_LENGTH] = Blksz; gk_desc[PAD_LENGTH] = 0; gk_desc[PHASE_TIMEOUT] = 10; gk_desc[DISCONNECT_TIMEOUT] = 10; for (i=9; i<15; i++) gk_desc[i] = 0; /* Clear reserved fields */ gk_desc[SENSEADDR] = sensedata; gk_desc[SENSELEN] = 250; /* Issue the QIO to send the inquiry command and receive the inquiry data */ #ifdef MSEC waitabit(); #endif status = sys$qiow (GK_EFN, chan, IO$_DIAGNOSE, gk_iosb, 0, 0, &gk_desc[0], 15*4, 0, 0, 0, 0); /* Check the various returned status values */ if (!(status & 1)) return(status); if (!(gk_iosb[0] & 1)){ /* if something goes wrong with the write, try start unit followed by test unit ready to resynch */ dostart = dostart + 1; if (dostart > 5){ dostart = 0; i = setr_command(chan, start_unit_cmd, 6, gbuf, 0, &got); i = setr_command(chan, test_unit_ready_cmd, 6, gbuf, 0, &got); } return(4); } scsi_status = (gk_iosb[1] >> 24) & SCSI_STATUS_MASK; if (scsi_status){ isensek = sensedata[2] & 15; /* sense key 0 is normal return, 1 is recovered error */ if (isensek == 1 || isensek == 0){ scsi_status = 0; } } if (scsi_status) { /* if something goes wrong with the write, try start unit followed by test unit ready to resynch */ dostart = dostart + 1; if (dostart > 5){ dostart = 0; i = setr_command(chan, start_unit_cmd, 6, gbuf, 0, &got); i = setr_command(chan, test_unit_ready_cmd, 6, gbuf, 0, &got); } return(8); } /* command worked. Return success. */ dostart = 0; /* got = gk_iosb[0] >> 16; */ /* Now we have all the data in Dbuff, so merge in whatever the user wanted to write. */ lbnlo = Lbn512; lbnhi = lbnlo + Blkfc - 1; /* maintain these together at all times */ /* Data is in buffer. Update it. */ pp = &Dbuff[(512*(k - lbnlo))]; p = buf; for (ii=0; ii < 512; ii++){ *pp = *p; p++; pp++; } } /* Here write the buffer back to disk*/ write10_cmd[7] = 0; write10_cmd[8] = 1; /* one device block only */ /* Fill in LBN */ /* Note that this is the big-block LBN, not the 512 byte block LBN */ ii = Lbn; write10_cmd[2] = (ii >>24) & 255; write10_cmd[3] = (ii >>16) & 255; write10_cmd[4] = (ii >>8) & 255; write10_cmd[5] = (ii ) & 255; gk_desc[OPCODE] = 1; /* gk_desc[FLAGS] = FLAGS_WRITE + FLAGS_DISCONNECT + FLAGS_SYNCH + FLAGS_ASENSE; */ gk_desc[FLAGS] = FLAGS_WRITE + FLAGS_SYNCH + FLAGS_ASENSE; gk_desc[COMMAND_ADDRESS] = write10_cmd; gk_desc[COMMAND_LENGTH] = 10; gk_desc[DATA_ADDRESS] = Dbuff; gk_desc[DATA_LENGTH] = Blksz; gk_desc[PAD_LENGTH] = 0; gk_desc[PHASE_TIMEOUT] = 10; gk_desc[DISCONNECT_TIMEOUT] = 10; for (i=9; i<15; i++) gk_desc[i] = 0; /* Clear reserved fields */ /* gk_desc[SENSEADDR] = sensedata; gk_desc[SENSELEN] = 18; */ /* Issue the QIO to send the inquiry command and receive the inquiry data */ #ifdef MSEC waitabit(); #endif status = sys$qiow (GK_EFN, chan, IO$_DIAGNOSE, gk_iosb, 0, 0, &gk_desc[0], 15*4, 0, 0, 0, 0); /* Check the various returned status values */ if (!(status & 1)) return(status); if (!(gk_iosb[0] & 1)) return(4); scsi_status = (gk_iosb[1] >> 24) & SCSI_STATUS_MASK; if (scsi_status){ isensek = sensedata[2] & 15; /* sense key 0 is normal return, 1 is recovered error */ if (isensek == 1 || isensek == 0){ scsi_status = 0; } } if (scsi_status) { return(8); } /* The command succeeded. */ got = gk_iosb[0] >> 16; return(1); } int dsk_setup(short chan, long *maxblk, int *cyl, int *sect, int *trks, int *blksize) { char gbuf[512]; int i, ii; long mxb; long got; long gba,gbb,gbc,gbd; long wcyl; long gbf,gbg; long wmxb; Lbn = -1; /* init Lbn so we don't start thinking we have blk*/ Lbn512 = -1; /* spin up the disk and get size and make up geometry */ i = setr_command(chan, start_unit_cmd, 6, gbuf, 0, &got); if (i != 1) return(i); i = setr_command(chan, test_unit_ready_cmd, 6, gbuf, 0, &got); if (i != 1) return(i); i = setr_command(chan, read_capacity_cmd, 10, gbuf, 8, &got); if (i != 1) return(i); /* check if 512 byte blocks. If not, try to set the mode and then recheck. */ gbf = (gbuf[6] & 255); gbg = (gbuf[7] & 255); ii = gbf <<8 + gbg; if (ii != 512){ /* do a mode sense/mode select and try to set blocksize to 512. If it fails, just proceed. */ sendd_command(chan, mode_sense_cmd, 6, 150); emit_command(chan, mode_select_cmd, 6, mode_sel_data, 22); } i = setr_command(chan, read_capacity_cmd, 10, gbuf, 8, &got); if (i != 1) return(i); /* Should have device capacity in bigendian order here. Fix and save. */ gba = (gbuf[0] & 255); gbb = (gbuf[1] & 255); gbc = (gbuf[2] & 255); gbd = (gbuf[3] & 255); mxb=( gba << 24) + (gbb << 16) + ( gbc <<8 ) + gbd + 1; *maxblk = mxb; gbf = (gbuf[6] & 255); gbg = (gbuf[7] & 255); ii = gbf <<8 + gbg; Blksz = ii; *blksize = ii; Blkfc = ii / 512; /* if (ii != 512) return 1;*/ /* From here on for geometry fake things up */ /* Note this MUST be changed for disks bigger than 1 TB!!! */ /* This just means though that VMS blocks are figured as 512 bytes so we fake it. */ mxb = Blkfc * mxb; *maxblk = mxb; /* compute geometry */ *trks = 6; *sect = 4; wcyl = mxb / 24; wmxb = (mxb % 24); if (wmxb != 0) wcyl++; *cyl = wcyl; if (*cyl < 65534) return (1); /* sector count too large ... try 32 by 32 by n */ *trks = 32; *sect = 32; wcyl = mxb/1024; wmxb = mxb % 1024; if (wmxb != 0) wcyl++; *cyl = wcyl; if (*cyl < 65534) return (1); /* want this to work like dkdriver so try 96 *96 *N next */ *trks = 96; *sect = 96; wcyl = mxb / 9216; wmxb = mxb % 9216; if (wmxb != 0) wcyl++; *cyl = wcyl; if (*cyl < 65534) return (1); /* Too big for 32X32Xn so try 255X255Xn */ *trks = 255; *sect = 255; wcyl = mxb / 65025; wmxb = mxb % 65025; if (wmxb != 0) wcyl++; if (wcyl > 65535) wcyl = 65535; *cyl = wcyl; /* if this won't fit, just force fit and use what can be used. */ return (1); } /* read block */ /* variable size disk block */ int read_gk_blk(short chan, char* buf, long bytes, long lbn, long * got) { int i,ii; char gbuf[512]; int xgot; int dozot = 0; int st, k; char * p; /* First set up the SCSI command to read, then do the read. Use read(10) for simplicity. */ if (Blksz == 512){ ii = (bytes + 511) / 512; /* number of blocks */ /* fill in transfer length in blocks */ /* Round DOWN; we do not want to overwrite! */ /* no, on second thought round UP and just be sure bytecount is right for the io$_diagnose so we get the last bits of any transfer. */ read10_cmd[7] = (ii/256) & 255; read10_cmd[8] = (ii & 255); /* shift order for SCSI */ /* Fill in LBN */ ii = lbn; read10_cmd[2] = (ii >>24) & 255; read10_cmd[3] = (ii >>16) & 255; read10_cmd[4] = (ii >>8) & 255; read10_cmd[5] = (ii ) & 255; i = setr_command(chan, read10_cmd, 10, buf, bytes, got); if ((i & 1) != 0) {dozot = 0;} if ((i & 1) == 0) { dozot = dozot + 1; if (dozot > 5){ /* start unit, wait ready */ ii = setr_command(chan, start_unit_cmd, 6, gbuf, 0, &xgot); ii = setr_command(chan, test_unit_ready_cmd, 6, gbuf, 0, &xgot); } } return(i); } if (Blksz != 512){ /* nonstd blocksize device. Read out of buffer or off disk...*/ st = 1; ii = (bytes) / 512; for (i=0; i < ii; i++){ k = lbn + i; p = buf + (i * 512); /* get the data 1 blk at a time */ st = get_blk(chan, p, k); } return (st); } } /* Write block */ int write_gk_blk(short chan, char* buf, long bytes, long lbn, long *bgot) { int ii; int i; int iii; char gbuf[512]; int got; int dozot = 0; int st, k; char * p; /* First set up the SCSI command to write, then do the write. Use write(10) for simplicity. */ ii = (bytes + 511) / 512; /* number of blocks */ if (Blksz == 512){ /* fill in transfer length in blocks */ /* Round DOWN; we do not want to overwrite! */ write10_cmd[7] = (ii/256) & 255; write10_cmd[8] = (ii & 255); /* shift order for SCSI */ /* Fill in LBN */ ii = lbn; write10_cmd[2] = (ii >>24) & 255; write10_cmd[3] = (ii >>16) & 255; write10_cmd[4] = (ii >>8) & 255; write10_cmd[5] = (ii ) & 255; i = setw_command(chan, write10_cmd, 10, buf, bytes, bgot); if ((i & 1) != 0) {dozot = 0;} if ((i & 1) == 0) { dozot = dozot + 1; if (dozot > 5){ /* start unit, wait ready */ ii = setr_command(chan, start_unit_cmd, 6, gbuf, 0, &got); ii = setr_command(chan, test_unit_ready_cmd, 6, gbuf, 0, &got); } } return(i); } if (Blksz != 512){ /* nonstd blocksize device. write to buffer or onto disk...*/ /* for nonstandard blocksize just hope we get block multiples. */ st = 1; ii = (bytes) / 512; iii = ii; for (i=0; i < ii; i++){ k = lbn + i; p = buf + (i * 512); /* put the data 1 blk at a time. Pass in loop indices so we can tell if the buffer will be written in this operation. If so we need not do read/write extra times to ensure that everything gets to disk after the i/o since it isn't over yet. Not yet used. */ st = put_blk(chan, p, k, i, iii); /* chan = i/o chnl p = buffer pointer k = block number (512 byte blk measure) i = sub-blk we are doing this call iii = number sub-blocks we will do */ } return (st); } } /* Read type command sent to device to read data of data_len */ int setr_command (igk_chan, cmd, cmd_len, obuf, data_len, got) short igk_chan; long *got; char *cmd; int cmd_len, data_len; char obuf[512]; { int i,status; int scsi_status; char isensek; char sensedata[512]; /* Set up the descriptor with the SCSI information to be sent to the target */ /* for (i=0;i<511;i++)sensedata[i] = 0;*/ gk_desc[OPCODE] = 1; gk_desc[FLAGS] = FLAGS_READ + FLAGS_SYNCH + FLAGS_ASENSE; /* note FLAGS_DISCONNECT omitted from above */ gk_desc[COMMAND_ADDRESS] = cmd; gk_desc[COMMAND_LENGTH] = cmd_len; gk_desc[DATA_ADDRESS] = obuf; gk_desc[DATA_LENGTH] = data_len; gk_desc[PAD_LENGTH] = 0; gk_desc[PHASE_TIMEOUT] = 10; gk_desc[DISCONNECT_TIMEOUT] = 10; for (i=9; i<15; i++) gk_desc[i] = 0; /* Clear reserved fields */ gk_desc[SENSEADDR] = sensedata; gk_desc[SENSELEN] = 250; /* Issue the QIO to send the inquiry command and receive the inquiry data */ gk_chan=igk_chan; #ifdef MSEC waitabit(); #endif status = sys$qiow (GK_EFN, igk_chan, IO$_DIAGNOSE, gk_iosb, 0, 0, &gk_desc[0], 15*4, 0, 0, 0, 0); /* Check the various returned status values */ #ifdef DBGPRINT if (!(status & 1)) fprintf(stderr,"qio sts %d\n",status); #endif if (!(status & 1)) return(status); #ifdef DBGPRINT if (!(gk_iosb[0] & 1)) fprintf(stderr,"iosb err %d %d\n",gk_iosb[0],gk_iosb[1]); #endif if (!(gk_iosb[0] & 1)) return(4); scsi_status = (gk_iosb[1] >> 24) & SCSI_STATUS_MASK; if (scsi_status){ isensek = sensedata[2] & 15; #ifdef DBGPRINT fprintf(stderr,"scsi stat %d sensekey %d\n",scsi_status,isensek); #endif /* sense key 0 is normal return, 1 is recovered error */ if (isensek == 1 || isensek == 0){ scsi_status = 0; } } if (scsi_status) { return(8); } /* command worked. Return success. */ *got = gk_iosb[0] >> 16; return(1); } int setw_command (chan, cmd, cmd_len, indata, data_len, transfer_length) short chan; char *cmd, *indata; long * transfer_length; int cmd_len, data_len; { int scsi_status; int i,status,kkk,kkkk; char isensek; char *pk; char sensedata[512]; /* for (i=0;i<511;i++)sensedata[i] = 0; */ kkkk = 0; /* Set up the descriptor with the SCSI information to be sent to the target */ gk_desc[OPCODE] = 1; /* gk_desc[FLAGS] = FLAGS_WRITE + FLAGS_DISCONNECT + FLAGS_SYNCH + FLAGS_ASENSE; */ gk_desc[FLAGS] = FLAGS_WRITE + FLAGS_SYNCH + FLAGS_ASENSE; gk_desc[COMMAND_ADDRESS] = cmd; gk_desc[COMMAND_LENGTH] = cmd_len; gk_desc[DATA_ADDRESS] = indata; gk_desc[DATA_LENGTH] = data_len; gk_desc[PAD_LENGTH] = 0; gk_desc[PHASE_TIMEOUT] = 10; gk_desc[DISCONNECT_TIMEOUT] = 10; for (i=9; i<15; i++) gk_desc[i] = 0; /* Clear reserved fields */ /* gk_desc[SENSEADDR] = sensedata; gk_desc[SENSELEN] = 18; */ /* Issue the QIO to send the inquiry command and receive the inquiry data */ #ifdef MSEC waitabit(); #endif status = sys$qiow (GK_EFN, chan, IO$_DIAGNOSE, gk_iosb, 0, 0, &gk_desc[0], 15*4, 0, 0, 0, 0); /* Check the various returned status values */ #ifdef DBGPRINT if (!(status & 1)) fprintf(stderr,"qio sts %d\n",status); #endif if (!(status & 1)) return(status); #ifdef DBGPRINT if (!(gk_iosb[0] & 1)) fprintf(stderr,"iosb err %d %d\n",gk_iosb[0],gk_iosb[1]); #endif if (!(gk_iosb[0] & 1)) return(4); scsi_status = (gk_iosb[1] >> 24) & SCSI_STATUS_MASK; if (scsi_status){ isensek = sensedata[2] & 15; #ifdef DBGPRINT fprintf(stderr,"scsi stat %d sensekey %d\n",scsi_status,isensek); #endif /* sense key 0 is normal return, 1 is recovered error */ if (isensek == 1 || isensek == 0){ scsi_status = 0; } } if (scsi_status) { return(8); } /* The command succeeded. */ *transfer_length = gk_iosb[0] >> 16; return(1); } void emit_command (short chan, char *cmd,int cmd_len,char * indata,int data_len) { int kkk,kkkk; int i; int scsi_status; int status; char *pk; char buf [2512]; char sensedata[512]; for (i=0;i<511;i++)sensedata[i] = 0; kkkk = 0; pk = indata; for (kkk = data_len; kkk > 0; kkk--){ buf[kkkk] = *pk; kkkk++; pk++; } /* Set up the descriptor with the SCSI information to be sent to the target */ gk_desc[OPCODE] = 1; gk_desc[FLAGS] = FLAGS_WRITE + FLAGS_DISCONNECT + FLAGS_SYNCH + FLAGS_ASENSE; gk_desc[COMMAND_ADDRESS] = cmd; gk_desc[COMMAND_LENGTH] = cmd_len; gk_desc[DATA_ADDRESS] = buf; gk_desc[DATA_LENGTH] = data_len; gk_desc[PAD_LENGTH] = 0; gk_desc[PHASE_TIMEOUT] = 10; gk_desc[DISCONNECT_TIMEOUT] = 10; for (i=9; i<15; i++) gk_desc[i] = 0; /* Clear reserved fields */ /* gk_desc[SENSEADDR] = sensedata; gk_desc[SENSELEN] = 18; */ /* Issue the QIO to send the inquiry command and receive the inquiry data */ #ifdef MSEC waitabit(); #endif status = sys$qiow (GK_EFN, chan, IO$_DIAGNOSE, gk_iosb, 0, 0, &gk_desc[0], 15*4, 0, 0, 0, 0); /* Check the various returned status values */ if (!(status & 1)) sys$exit (status); if (!(gk_iosb[0] & 1)) sys$exit (gk_iosb[0] & 0xffff); scsi_status = (gk_iosb[1] >> 24) & SCSI_STATUS_MASK; return; } void sendd_command (chan, cmd, cmd_len, data_len) char *cmd; short chan; int cmd_len, data_len; { int i, status; char buf [512]; char sensedata[512]; /* Set up the descriptor with the SCSI information to be sent to the target */ for (i=0;i<511;i++)sensedata[i] = 0; /* Fill buf with something recognizable so if we read anything it will be obvious it changed. */ for (i=0;i<511;i++)buf[i] = 120; gk_desc[OPCODE] = 1; gk_desc[FLAGS] = FLAGS_READ + FLAGS_DISCONNECT + FLAGS_SYNCH + FLAGS_ASENSE; /* gk_desc[FLAGS] = FLAGS_READ + FLAGS_SYNCH + FLAGS_ASENSE;*/ gk_desc[COMMAND_ADDRESS] = cmd; gk_desc[COMMAND_LENGTH] = cmd_len; gk_desc[DATA_ADDRESS] = buf; gk_desc[DATA_LENGTH] = data_len; gk_desc[PAD_LENGTH] = 0; gk_desc[PHASE_TIMEOUT] = 10; gk_desc[DISCONNECT_TIMEOUT] = 10; for (i=9; i<15; i++) gk_desc[i] = 0; /* Clear reserved fields */ gk_desc[SENSEADDR] = sensedata; gk_desc[SENSELEN] = 250; /* Issue the QIO to send the inquiry command and receive the inquiry data */ #ifdef MSEC waitabit(); #endif status = sys$qiow (GK_EFN, chan, IO$_DIAGNOSE, gk_iosb, 0, 0, &gk_desc[0], 15*4, 0, 0, 0, 0); /* Check the various returned status values */ return; } #ifdef MSEC void waitabit(){ int i; unsigned int msec; msec = MSEC; i = usleep(msec); return; } #endif