/* * */ #include #include #include #include #include #include #include #include #include "request.h" #include "globals.h" #include "global.h" #include "aspi.h" #include "callaspi.h" #include "aspi_rw.h" #include "rb.h" #include "dmem.h" #include "buf.h" #include "kbd.h" #include "al6000.h" #include "script.h" #include "print.h" #define SCSI_WRITE_VER 0x2E // SCSI Write Verify #define SCSI_WRITE 0x2A // SCSI Write #define SCSI_READ 0x28 struct FAR_OBJ { unsigned int offset; unsigned int segment; }; union PTR_OBJ { struct FAR_OBJ seg_off; char far *ptr; }; static union PTR_OBJ ptr; static struct RB_OBJ *rb_list = NULL; static void prt_status(int status_byte,struct STATUS_OBJ *status); static void scsi_info(IO_REQ *aspi_req); struct STATUS_OBJ { int code; char *description; }; static struct STATUS_OBJ aspi_status_byte[] = { {0x00,"SCSI request in progress"}, {0x01,"SCSI request complete without error"}, {0x02,"SCSI request aborted by host"}, {0x04,"SCSI request completed with error"}, {0x80,"Invalid SCSI request"}, {0x81,"Invalid Host Adapter Number"}, {0x82,"SCSI device not installed"}, {NULL,NULL} }; static struct STATUS_OBJ adapter_status[] = { {0x00,"Host adapter did not detect any error"}, {0x11,"Selection timeout"}, {0x12,"Data over-run/under-run"}, {0x13,"Unexpected Bus Free"}, {0x14,"Target bus phase sequence failure"}, {NULL,NULL} }; static struct STATUS_OBJ target_status[] = { {0x00,"No target status"}, {0x02,"Check status (Sense data is in SENSE ALLOCATION AREA"}, {0x08,"Specified Target/LUN is busy"}, {0x18,"Reservation conflict"}, {NULL,NULL} }; /* * Number of outstanding ASPI requests to allow to be outstanding at * any given time. If 1, this is equivalent to a single threaded * operating environment. */ static int allow_req_outs = 1; /* * Delay between ASPI requests. */ static int req_delay = 0; /* * ASPI statistics */ static unsigned long tot_req_pending = 0, tot_req_successful = 0, tot_req_error = 0; static FLAG init = FALSE; static FLAG flush = FALSE; static unsigned long aspi_tag = 1L; /*************************************************************************** * * aspi_rw(...) * ***************************************************************************/ FLAG aspi_rw( char *cmd, unsigned int scsi_id, unsigned long blk_num, unsigned int num_blks, unsigned int tag, unsigned int pattern) { int scsi_op; int ha = 0; union SCSI_CDB cdb; IO_REQ *aspi_req; char *buf; unsigned long num_bytes; struct RB_OBJ *req; struct PAT_OBJ pat; // // Hold off issuing any more requests then are allowed to be // outstanding. // while (aspi_poll() >= allow_req_outs) if (kbd_esc("Stop waiting for outstanding ASPI requests before sending new ones")) { return (FALSE); } // // Initialize adapters and do an inquery. // if (!init /* Initialized yet? */ && /* and */ !diag_here(DIAG_ASPI_DISABLE)) /* ASPI diabled? */ { printf("Initializing ASPI, adapter(s) and device(s)...\n"); Init_ASPI(); Get_HAs(); printf("Done initializing adapters.\n"); check_devices(0); init = TRUE; /* Spec initialized */ } req = rb_new(&rb_list); // Get request aspi_req = req; // Allias as ASPI req if (!req) // Did not issue req? return (FALSE); // Do nothing num_bytes = num_blks * SCSI_BLK_SIZE; // Amt of data mem to alloc buf = buf_get(num_bytes); // Alloc data mem if (!buf) // Could not alloc? return (FALSE); // Do nothing req->data_size = num_bytes; // Spec size of data mem alloc req->scsi_id = scsi_id; req->blk_num = blk_num; req->num_blks = num_blks; req->pattern = pattern; /* Save current pattern */ // req->tag = aspi_tag++; // Use ASPI tag // This is done so data patteren can be passed as a byte from // the script file. req->tag = tag; // Use ASPI tag pat.scsi_id = scsi_id; pat.blk_num = blk_num; pat.num_blks = num_blks; pat.num_bytes = num_bytes; pat.tag = tag; switch (cmd[0]) { case 'W': /****************************************** Write? */ case 'w': if (cmd[1] && toupper(cmd[1]) == 'V') // Verify? scsi_op = SCSI_WRITE_VER; else scsi_op = SCSI_WRITE; buf_pattern('m',buf,pattern,&pat); if (diag_here(DIAG_VERBOSE)) printf("SCSI_ID=%u BLK_NUM=0x%lX NUM_BLKS=0x%X TAG=0x%lX\n", scsi_id,blk_num,num_blks,req->tag); if (diag_here(DIAG_BUF_DUMP)) print_dump_byte(buf,64); break; case 'R': /****************************************** Read? */ case 'r': scsi_op = SCSI_READ; buf_fill(buf,0L,num_bytes); /* Init read buf */ if (diag_here(DIAG_ASPI_DISABLE)) /* ASPI disabled? */ buf_pattern('m',buf,pattern,&pat); break; default: /******************************************* Ill ASPI cmd? */ error("Unknown ASPI command"); dmem_free(&buf); // Dealloc data mem rb_free(&rb_list); // Dealloc request mem return (FALSE); // Do nothing } cdb.SCSI10[0] = scsi_op; cdb.SCSI10[1] = 0; /* LUN, Reserved, RelAdr */ cdb.SCSI10[2] = LONG2BYTE(3,blk_num); /* Logical Block Addr BYTE 3 */ cdb.SCSI10[3] = LONG2BYTE(2,blk_num); /* Logical Block Addr BYTE 2 */ cdb.SCSI10[4] = LONG2BYTE(1,blk_num); /* Logical Block Addr BYTE 1 */ cdb.SCSI10[5] = LONG2BYTE(0,blk_num); /* Logical Block Addr BYTE 0 */ cdb.SCSI10[6] = 0; /* Reserved */ cdb.SCSI10[7] = WORD2BYTE(1,num_blks);/* Xfer, n blocks BYTE 1 */ cdb.SCSI10[8] = WORD2BYTE(0,num_blks);/* Xfer, n blocks BYTE 0 */ cdb.SCSI10[9] = 0; /* Vendor Unique, reserved, Flag & Link */ InitRequest( aspi_req, ha, scsi_id, 0, (void far *)buf, num_bytes, (char *)&cdb, 10, NULL); /* * The RB_OBJ is used as an alias for the IO_REQ that is used by * CALLASPI.C */ if (diag_here(DIAG_ASPI_DISABLE)) // ASPI disabled? { aspi_req->Status = 0x01; // Spec completed OK req->issued = TRUE; // Indicate issued } else /* ASPI not disabled */ { if (req_delay) /* Delay? */ delay (req_delay); /* Delay as speced */ DoASPI(aspi_req,FALSE,ASPI_POST); /* Send ASPI cmd */ req->issued = TRUE; // Indicate issued } tot_req_pending++; /* One more pending req */ if (diag_here(DIAG_CHK_WR_BUF) // Check write buffer? && // and (toupper(cmd[0]) == 'W')) // Write? { if (!buf_pattern('c',buf,pattern,&pat)) error("Write buffer corrupted after sending to ASPI"); } return (TRUE); } /*************************************************************************** * * aspi_poll(...) * ***************************************************************************/ int aspi_poll() { FLAG data_ok; IO_REQ *aspi_req; unsigned int req_pending; struct PAT_OBJ pat; if (!rb_list) /* No outstanding reqs? */ return (0); /* Do nothing */ for (aspi_req = rb_first(&rb_list); aspi_req; aspi_req = rb_next(&rb_list)) { if (diag_here(DIAG_ASPI_DISABLE) // ASPI disabled? && // and !flush) // Not flushing reqs? { req_pending = tot_req_pending - tot_req_successful - tot_req_error; if (req_pending < allow_req_outs) // Allow requests to que up? continue; } pat.scsi_id = rb_list->scsi_id; pat.blk_num = rb_list->blk_num; pat.num_blks = rb_list->num_blks; pat.num_bytes = rb_list->num_blks * SCSI_BLK_SIZE; pat.tag = rb_list->tag; if (aspi_req->Status) /* SCSI req not in prog? */ { if (aspi_req->Status != 0x01) /* SCSI req abnormal compl?*/ { scsi_info(aspi_req); prt_status(aspi_req->Status,aspi_status_byte); tot_req_error++; /* Another req with error */ kbd_any_key(); } else if (aspi_req->CDB.SCSI10[0] == SCSI_READ) /* SCSI operation read? */ { data_ok = buf_pattern('c',aspi_req->DataPtr,rb_list->pattern,&pat); if (data_ok) tot_req_successful++; /* Another successful req */ else { tot_req_error++; /* Another req with error */ scsi_info(aspi_req); kbd_any_key(); } if (diag_here(DIAG_VERBOSE)) scsi_info(aspi_req); if (diag_here(DIAG_BUF_DUMP)) print_dump_byte(aspi_req->DataPtr,64); } else // Write { tot_req_successful++; /* Another successful req */ // // Check to see if ASPI corrupted buffer after sending it. // if (diag_here(DIAG_CHK_WR_BUF)) // Check write buffer? if (!buf_pattern('c',aspi_req->DataPtr,rb_list->pattern,&pat)) error("Write buffer corrupted after ASPI complete"); } if (aspi_req->HAStatus) prt_status(aspi_req->HAStatus,adapter_status); if (aspi_req->TStatus) prt_status(aspi_req->TStatus,target_status); dmem_free(&(aspi_req->DataPtr)); // Dealloc data mem rb_list->data_size = 0L; rb_free(&rb_list); if (!rb_list) /* No more reqs? */ return (0); /* Nothing more to do */ } else // Request in progress? { // // Check to see if ASPI corrupted buffer after sending it. // if (diag_here(DIAG_CHK_WR_BUF) // Check write buffer? && // and (aspi_req->CDB.SCSI10[0] != SCSI_READ)) // SCSI write? { if (!buf_pattern('c',aspi_req->DataPtr,rb_list->pattern,&pat)) error("Write buffer corrupted after ASPI complete"); error("Write buffer corrupted while ASPI request pending"); } } } req_pending = tot_req_pending - tot_req_successful - tot_req_error; return (req_pending); } /*************************************************************************** * * prt_status(...) * ***************************************************************************/ static void prt_status(int status_byte,struct STATUS_OBJ *status) { int i; for (i = 0; ; i++) { if (!status[i].description) { printf("ASPI status byte = 0x%.2X\n",status_byte); error("Unrecoginzable status returned from ASPI"); break; } if (status_byte == status[i].code) {printf("ASPI STATUS: %s.\n",status[i].description); break; } } } /*************************************************************************** * * aspi_allow_reqs(...) * ***************************************************************************/ void aspi_allow_reqs(int num) { allow_req_outs = num; printf("Outstanding ASPI requests allowed = %d.\n",num); } /*************************************************************************** * * aspi_req_delay(...) * ***************************************************************************/ void aspi_req_delay(int num) { req_delay = num; printf("ASPI request delay = %d msec.\n",num); } /*************************************************************************** * * aspi_stats(...) * ***************************************************************************/ void aspi_stats(int cmd) { unsigned int req_pending; IO_REQ *aspi_req; if (cmd == 'c') /* Clear? */ {tot_req_pending = 0L; tot_req_successful = 0L; tot_req_error = 0L; diag_msg("ASPI Statistics cleared.\n"); } else { req_pending = tot_req_pending - tot_req_successful - tot_req_error; diag_msg("ASPI Statistics:\n"); printf("\tTotal ASPI read/write requests = %ld.\n",tot_req_pending); printf("\tTotal successful requests = %ld.\n",tot_req_successful); printf("\tTotal error requests = %ld.\n",tot_req_error); printf("\tTotal requests still pending = %d.\n",req_pending); if (req_pending || rb_list) /* No outstanding reqs? */ { if (!rb_list) /* No outstanding reqs? */ diag_msg("Requests pending but list is empty.\n"); if (!req_pending) /* No pending reqs? */ diag_msg("Requests list not empty and requests are not pending.\n"); for (aspi_req = rb_first(&rb_list); aspi_req; aspi_req = rb_next(&rb_list)) { printf("Request tag = 0x%lX.\n",rb_list->tag); scsi_info(aspi_req); if (aspi_req->Status) prt_status(aspi_req->Status,aspi_status_byte); if (aspi_req->HAStatus) prt_status(aspi_req->HAStatus,adapter_status); if (aspi_req->TStatus) prt_status(aspi_req->TStatus,target_status); } // if (kbd_get_yn("Attempt to reset any AL-6000s")) // al6_reset(); } } } /*************************************************************************** * * scsi_info(...) * ***************************************************************************/ static void scsi_info(IO_REQ *aspi_req) { unsigned long num_blks; ptr.ptr = aspi_req; num_blks = (BYTE2WORD(1,aspi_req->CDB.SCSI10[7]) | BYTE2WORD(0,aspi_req->CDB.SCSI10[8]) ); printf("Req SEG:OFF=0x%.4X:0x%.4X SCSI_ID=%u BLK_NUM=0x%lX NUM_BLKS=0x%X.\n", ptr.seg_off.segment,ptr.seg_off.offset, aspi_req->TargetID, (BYTE2LONG(3,aspi_req->CDB.SCSI10[2]) | BYTE2LONG(2,aspi_req->CDB.SCSI10[3]) | BYTE2LONG(1,aspi_req->CDB.SCSI10[4]) | BYTE2LONG(0,aspi_req->CDB.SCSI10[5]) ), num_blks); } /*************************************************************************** * * aspi_flush(...) * ***************************************************************************/ void aspi_flush(void) { unsigned int req_pending; flush = TRUE; req_pending = aspi_poll(); if (req_pending) /* ASPI reqs pending? */ { diag_msg("Press any key to abort waiting for ASPI requests to complete.\n"); printf("Number of outstanding requests to go = %d.\n",req_pending); if (kbd_esc("Abort waiting for ASPI requests to complete")) { req_pending = aspi_poll(); // Give one more change to complete aspi_stats('d'); // Display ASPI statistics return; } kbd_flush(); while (req_pending) /* ASPI reqs still pending?*/ { req_pending = aspi_poll(); /* ASPI reqs pending */ if (kbhit()) {diag_msg("Key pressed, abort waiting for ASPI requests to complete.\n"); printf("Number of outstanding requests to go = %d.\n",req_pending); break; } } } aspi_stats('d'); /* Display ASPI statistics */ }