home *** CD-ROM | disk | FTP | other *** search
- /*DDK*************************************************************************/
- /* */
- /* COPYRIGHT Copyright (C) 1995 IBM Corporation */
- /* */
- /* The following IBM OS/2 WARP source code is provided to you solely for */
- /* the purpose of assisting you in your development of OS/2 WARP device */
- /* drivers. You may use this code in accordance with the IBM License */
- /* Agreement provided in the IBM Device Driver Source Kit for OS/2. This */
- /* Copyright statement may not be removed. */
- /* */
- /*****************************************************************************/
- /**************************************************************************
- *
- * SOURCE FILE NAME = SCSISUBS.C
- *
- * DESCRIPTIVE NAME = IBM2SCSI.ADD - Adapter Driver for IBM SCSI adapters.
- * General routines.
- *
- *
- * VERSION = V2.0
- *
- * DATE
- *
- * DESCRIPTION This file contains general utility routines for the ADD.
- *
- */
-
- /*----------------------*/
- /* System include files */
- /*----------------------*/
-
- #define INCL_NOBASEAPI
- #define INCL_NOPMAPI
- #include "os2.h"
-
- /*----------------------*/
- /* ADD include files */
- /*----------------------*/
-
- #include "strat2.h"
- #include "dhcalls.h"
- #include "iorb.h"
- #include "scb.h"
- #include "reqpkt.h"
- #include "abios.h"
- #include "scsi.h"
-
- /*----------------------*/
- /* Local include files */
- /*----------------------*/
-
- #include "mmscb.h"
- #include "delivery.h"
- #include "scsiadd.h"
- #include "scsiextn.h"
- #include "scsipro.h"
-
-
- /************************************************************************/
- /* */
- /* FindDeviceEntry */
- /* */
- /* Find the specified unit handle entry and return a pointer to the */
- /* device table entry. */
- /* */
- /* Entry: FindDeviceEntry(uh) */
- /* */
- /* uh - unit handle */
- /* */
- /* Exit: NULL if entry not found */
- /* */
- /************************************************************************/
-
- NPDCB FindDeviceEntry(USHORT uh)
-
- {
-
- /*-------------------------------------------------------------*/
- /* Get the device table entry from the unit handle table. The */
- /* unit handle uh is used as an index into the table. */
- /*-------------------------------------------------------------*/
-
- if (uh < cDevices) {
- return(*(UnitHandleTbl + uh));
- }
- else {
- return(NULL);
- }
- }
-
-
- /************************************************************************/
- /* */
- /* BuildSCB */
- /* */
- /* Build the specified canned SCB. */
- /* */
- /* Entry: BuildSCB(npSCB, type, npDCB, lba, ppBuf, BufLen, BlkCnt, */
- /* BlkSize) */
- /* */
- /* npSCB - ptr to the SCB to be built */
- /* type - type of SCB to build */
- /* npDCB - ptr to the device control block */
- /* lba - logical block address */
- /* ppBuf - phys ptr to the system buffer address (SG list) */
- /* BufLen - Buffer length */
- /* BlkCnt - number of blocks to xfer */
- /* BlkSize - block size */
- /* */
- /* Exit: good always. */
- /* */
- /************************************************************************/
-
- VOID BuildSCB(NPSCB npSCB, USHORT type, NPDCB npDCB, ULONG lba, ULONG ppBuf,
- ULONG BufLen, USHORT BlkCnt, USHORT BlkSize)
- {
-
- /*-------------------------------------------------------------*/
- /* Build the SCB using the switch statement. The SCB built is */
- /* considered a default SCB. It will, if applicable, have the */
- /* scatter/gather list enabled. The caller should turn this */
- /* off if required. All other fields will be zero'd to insure */
- /* the SCB is fresh. The chain field will also be disabled as */
- /* a default. */
- /*-------------------------------------------------------------*/
-
- npSCB->LBA = lba;
- npSCB->ppXferBuf = ppBuf;
- npSCB->XferBufLen = BufLen;
- npSCB->ppTSB = ppData + (USHORT)&npDCB->tsb;
- npSCB->ppNxtSCB = 0L;
- npSCB->EXT.BLK.BlockCnt = BlkCnt;
- npSCB->EXT.BLK.BlockSize = BlkSize;
-
- switch (type) {
-
- case SCB_READ:
- npSCB->Cmd = SCBREAD;
- npSCB->Enable = SCBEWREAD;
- break;
-
- case SCB_WRITE:
-
- npSCB->Cmd = SCBWRITE;
- npSCB->Enable = SCBEWWRITE;
- break;
-
- case SCB_READV:
- npSCB->Cmd = SCBREADV;
- npSCB->Enable = SCBEWREADV;
- break;
-
- case SCB_WRITEV:
- npSCB->Cmd = SCBWRITEV;
- npSCB->Enable = SCBEWWRITEV;
- break;
-
- case SCB_CMDSENSE:
- npSCB->Cmd = SCBCMDSENSE;
- npSCB->Enable = SCBEWCMDSENSE;
- break;
-
- case SCB_DEVICECAP:
- npSCB->Cmd = SCBDEVICECAP;
- npSCB->Enable = SCBEWDEVICECAP;
- break;
-
- case SCB_DEVICEINQ:
- npSCB->Cmd = SCBDEVICEINQ;
- npSCB->Enable = SCBEWDEVICEINQ;
- break;
-
- case SCB_SENDOTHER:
- npSCB->Cmd = SCBSENDOTHER;
- npSCB->Enable = SCBEWSENDOTHER;
- break;
-
- default:
- ERRMSG1("Attempt to build invalid SCB type %w\n\r",type);
-
- }
- }
-
-
- /************************************************************************/
- /* */
- /* AllocSCB */
- /* */
- /* Get an SCB for the caller. An SCB is retrieved from the SCB pool */
- /* free list. If there are no free SCBs then the reserved SCB in */
- /* the DCB is allocated. It is allocated only if the request is in */
- /* the process of being started. This eliminates a possible dead */
- /* lock situation where no SCBs are available. */
- /* */
- /* Entry: AllocSCB() */
- /* */
- /* npDCB - Ptr to the DCB */
- /* pIORB - ptr to the IORB */
- /* */
- /* Exit: NULL if not found, pointer to an SCBCTRL if found. */
- /* */
- /************************************************************************/
-
- NPSCBH AllocSCB(NPDCB npDCB, PIORB pIORB)
-
- {
-
- NPSCBH npSCBH;
-
- SAVEIF(); /* nobody but us messes with the free list for a bit */
-
- /*---------------------------------------------------------------*/
- /* Try to get an SCB from the free list. If no more SCBs on the */
- /* free list then try to allocate the DCB reserved SCB. The SCB */
- /* from the DCB is only allocated if the IORB is in the process */
- /* of starting. */
- /*---------------------------------------------------------------*/
-
- if (npSCBH = npSCBFreeList) { /* asignment intentional !! */
- npSCBFreeList = npSCBFreeList->scbctrl.npNextSCBH;
- npSCBH->scbctrl.npNextSCBH = NULL;
- npSCBH->scbctrl.status = 0;
- }
- else {
- if (!(npDCB->status & UNITSCBBUSY) &&
- (IORBWRKSP(pIORB,Status) & IORBSTARTING ||
- npDCB->state == IDLE)) {
- npSCBH = &(npDCB->ResSCBH);
- npDCB->status |= UNITSCBBUSY;
- npSCBH->scbctrl.status = DCBSCB;
- }
- else {
- npSCBH = NULL;
- }
- }
-
- /*--------------------------------------*/
- /* If we found one, then initialize it. */
- /*--------------------------------------*/
-
- if (npSCBH) {
- npSCBH->scb.LBA = 0L;
- npSCBH->scb.ppXferBuf = 0L;
- npSCBH->scb.XferBufLen = 0L;
- npSCBH->scb.ppNxtSCB = 0L;
- npSCBH->scb.EXT.BLK.BlockCnt = 0;
- npSCBH->scb.EXT.BLK.BlockSize = 0;
- npSCBH->scbctrl.pIORB = pIORB;
- }
-
- RESTOREIF();
-
- return(npSCBH);
-
- }
-
-
- /************************************************************************/
- /* */
- /* FreeSCB */
- /* */
- /* Put the SCB(s) back on the free list. The ptr passed is a ptr */
- /* to a SCB control structure. The number of SCBs in the list */
- /* is also given. The DCB reserved SCB can also be in the list. */
- /* */
- /* Entry: FreeSCB(cSCBs, SCBList, npDCB) */
- /* */
- /* cSCBs - number of SCBs to free in a linked list. */
- /* - 0 indicates all. */
- /* SCBList - ptr to first SCBControl header */
- /* npDCB - ptr to device control block */
- /* */
- /* Exit: returns a ptr to the remainder of the pool list if only */
- /* the first entry is returned. NULL if only 1 item in the */
- /* list or the whole list is freed. */
- /* */
- /* Notes: Only 64K entries can be returned with cSCBs = 0 on input */
- /* This should more than handle any case. */
- /* */
- /************************************************************************/
-
- NPSCBH FreeSCB(USHORT cSCBs, NPSCBH npSCBListH, NPDCB npDCB)
-
- {
-
- NPSCBH npSCBH, nextSCBH;
-
- SAVEIF(); /* save the interrupt flag and disable */
-
- npSCBH = npSCBListH;
-
- do {
- if (!(npSCBH->scbctrl.status & DCBSCB)) {
-
- nextSCBH = npSCBH->scbctrl.npNextSCBH;
- npSCBH->scbctrl.npNextSCBH = npSCBFreeList;
- npSCBFreeList = npSCBH;
- npSCBH = nextSCBH;
- }
- else {
- npDCB->status &= ~UNITSCBBUSY;
- npSCBH = npSCBH->scbctrl.npNextSCBH;
- npDCB->ResSCBH.scbctrl.npNextSCBH = NULL;
- }
- } while (npSCBH && --cSCBs);
-
- RESTOREIF(); /* restore the interrupt flag */
-
- return(npSCBH);
-
- }
-
-
- /************************************************************************/
- /* */
- /* QueueIORB */
- /* */
- /* This routine will place the IORB on the waiting queue for the */
- /* device. The location option indicates if the IORB is to be */
- /* queued at the end or the front. The end of the queue is found by */
- /* walking the chain until the IORB_CHAIN field is not set. This */
- /* will indicate the end of the chain. */
- /* */
- /* Entry: QueueIORB(pIORB, npDCB, loc) */
- /* */
- /* pIORB - ptr to IORB to queue */
- /* npDCB - ptr to device control block */
- /* loc - front or back of the queue */
- /* */
- /* Exit: normal always */
- /* */
- /* Note: This routine can be called at interrupt time. */
- /* */
- /************************************************************************/
-
- VOID QueueIORB(PIORB pIORB, NPDCB npDCB, USHORT loc)
-
- {
-
- PIORB pCurIORB;
-
- SAVEIF(); /* nobody else in here */
- TRACE(TR_QUEUED, pIORB); /* insert a queued trace record */
-
- /*--------------------------------------------------------------*/
- /* If the location is the back of the queue then find the end */
- /* of the queue and link this IORB to last one. If there is no */
- /* queue yet then this IORB becomes the queue. */
- /*--------------------------------------------------------------*/
-
- if (loc == BACK) {
- if (!npDCB->pWorkQ) { /* no work queued */
- npDCB->pWorkQ = pIORB;
- }
- else { /* work is queued */
- pCurIORB = npDCB->pWorkQ;
- while (pCurIORB->RequestControl & IORB_CHAIN) {
- pCurIORB = pCurIORB->pNxtIORB;
- }
- pCurIORB->pNxtIORB = pIORB;
- pCurIORB->RequestControl |= IORB_CHAIN;
- }
- }
-
- /*--------------------------------------------------------------*/
- /* Otherwise the location is the front. Make this IORB the 1st */
- /* IORB in the chain. */
- /*--------------------------------------------------------------*/
-
- else {
- if (npDCB->pWorkQ) { /* work already queued */
- pIORB->RequestControl |= IORB_CHAIN;
- pIORB->pNxtIORB = npDCB->pWorkQ;
- npDCB->pWorkQ = pIORB;
- }
- else {
- npDCB->pWorkQ = pIORB;
- pIORB->RequestControl &= ~IORB_CHAIN;
- }
- }
-
- RESTOREIF();
- }
-
- /************************************************************************/
- /* */
- /* DeQueueIORB */
- /* */
- /* This routine dequeues the first element in the IORB work queue. */
- /* It will return NULL if the work queue is empty. */
- /* */
- /* Entry: DeQueueIORB(npDCB) */
- /* */
- /* npDCB - ptr to device control block */
- /* */
- /* Exit: PIORB = IORB if present, NULL otherwise */
- /* */
- /* Note: This routine can be called at interrupt time. */
- /* */
- /************************************************************************/
-
- PIORB DeQueueIORB(NPDCB npDCB)
-
- {
-
- PIORB pIORB;
-
- /*---------------------------------------------------------------*/
- /* Turn ints off and peel the first IORB from the queue. If no */
- /* IORBs in the queue then return NULL. */
- /*---------------------------------------------------------------*/
-
- SAVEIF();
-
- if (pIORB = npDCB->pWorkQ) { /* assignment intentional !! */
- npDCB->pWorkQ = pIORB->pNxtIORB;
- pIORB->pNxtIORB = NULL;
- pIORB->RequestControl &= ~IORB_CHAIN;
- TRACE(TR_DEQUEUED, pIORB);
- }
-
- RESTOREIF();
- return(pIORB);
- }
-
-
- /*************************************************************************/
- /* */
- /* StartIORB */
- /* */
- /* This routine starts the passed IORB chain. The ABIOS RB in the */
- /* device table entry is set-up to point to the first SCB in hanging */
- /* off the IORB. If an SCB chain is being sent somebody else must */
- /* set up that chain properly. This routine assumes the device is */
- /* is not busy. */
- /* */
- /* Since the device is not busy, when called at task time we know */
- /* that there can be nothing queued. Since nothing is queued, if the */
- /* request completes immediately we don't have to go look for more */
- /* work to start. For this reason the caller is responsible for */
- /* starting more work if there is work queued. */
- /* */
- /* */
- /* Entry: StartIORB(pIORB, npDCB, start, complt, error) */
- /* */
- /* pIORB - ptr to the IORB group to start */
- /* npDCB - ptr to the DCB of the device */
- /* */
- /* Exit: Returns: */
- /* COMPLETE - Request was started and it completed. */
- /* ERROR - Request completed with error. */
- /* */
- /* Note: This routine can be called at interrupt time. */
- /* */
- /* */
- /*************************************************************************/
-
- VOID StartIORB(PIORB pIORB, NPDCB npDCB)
-
- {
-
- USHORT cmd;
- ULONG ppSCB, to_cmd;
-
- /*------------------------------------------------------------*/
- /* Assume the request is going to start OK. Set the IORB to */
- /* show that the IORB is starting. Set the active IORB in */
- /* the DCB, and set the device state. */
- /*------------------------------------------------------------*/
-
- IORBWRKSP(pIORB,Status) |= IORBSTARTING;
- npDCB->pActiveIORB = pIORB;
- npDCB->state = WAITONINT;
-
- /*-------------------------------------------------------------------*/
- /* Before sending the SCB out, see if any adjustments in the adapter */
- /* global command timeout is required. We try to use the adapter */
- /* value, but it is only good upto 128 minutes. Some I/Os take upto */
- /* 4 hours (tape erase and retension). This section of code will */
- /* adjust the adapter global timeout upto the maximum value as req- */
- /* uired by the command. If the timeout specified for the IORB is */
- /* greater than the max adapter value then the adapter timeout is */
- /* disabled and the software timeout is used. Once disabled it will */
- /* never be reset. In general the timeout value is only adjusted */
- /* upwards. It is never lowered. If the t/o value is adjusted with */
- /* an I/O then we exit here w/o starting the actual I/O. The int */
- /* handler will call us back later to start it. */
- /*-------------------------------------------------------------------*/
-
- if (!(npDCB->status & UNITTODISABLED)) { /* only if not disabled */
- if (pIORB->Timeout > npDCB->Timeout) {
- if (pIORB->Timeout > MAX_TIMEOUT) {
- npDCB->status |= UNITTODISABLED;
- to_cmd = SCB_FEATURE;
- }
- else {
- to_cmd = SCB_FEATURE + (pIORB->Timeout << 16); /* REN 91694 */
- }
-
- if (!StartLocateModeSCB(npDCB->ai, to_cmd,
- CMD_IMMEDIATE+(USHORT)npDCB->ldn)) {
- npDCB->Timeout = pIORB->Timeout;
- npDCB->state = WAITONSETTIMEOUT;
- }
-
- STI();
- return ;
- }
- }
- else { /* no adapter op required */
- if (pIORB->Timeout > npDCB->Timeout) {
- npDCB->Timeout = pIORB->Timeout;
- }
- }
-
- /*----------------------------------------------------------------*/
- /* Now for any adapter that has only 1 device attached turn the */
- /* No Disconnect bit in the SCB enable word on. This will in- */
- /* crease performance.
- /*----------------------------------------------------------------*/
-
- if (ACBTbl[npDCB->ai].cDev == 1) {
- IORBWRKSP(pIORB,npSCBH)->scb.Cmd |= SCBCfND;
- }
-
- /*----------------------------------------------------------------*/
- /* Determine the command to send to the adapter. Send the SCB to */
- /* the adapter. If there is an error then the adapter is reset */
- /* by the start routine. The start routine leaves INTs off. */
- /*----------------------------------------------------------------*/
-
- cmd = ((IORBWRKSP(pIORB,Status) & IORBSCBLONG) ? CMD_LONGSCB : CMD_NORMSCB);
- if (IORBWRKSP(pIORB,Status) & IORBPASSTHRUSCB) {
- ppSCB = ((PIORB_ADAPTER_PASSTHRU)pIORB)->ppSCB;
- }
- else {
- ppSCB = IORBWRKSP(pIORB,npSCBH)->scbctrl.ppSCB;
- }
-
- TRACE(TR_STARTED, pIORB);
-
- if (!StartLocateModeSCB(npDCB->ai, ppSCB, cmd+(USHORT)npDCB->ldn)) {
- STARTTIMEOUT(npDCB->ai, npDCB->Timeout+30);
- LED_ON(npDCB);
- }
-
- STI(); /* StartLocateModeSCB leaves ints off */
- return;
-
- }
-
-
- /*************************************************************************/
- /* */
- /* FinishIORB */
- /* */
- /* This routine actually does the finish up processing on the IORB. */
- /* The caller must free any attached SCBs before calling. */
- /* */
- /* 1. If the ADD work space status indicates that a call out is */
- /* needed then it is done. The return code is ignored here */
- /* because it is assumed, by the caller, at this point that */
- /* the request can do no more work. */
- /* */
- /* 2. The done bit in the IORB is set and the call back is done. */
- /* */
- /* Entry: FinishIORB(pIORB, npDCB) */
- /* */
- /* pIORB - ptr to the IORB */
- /* npDCB - ptr to the DCB of the device */
- /* */
- /* Exit: returns */
- /* */
- /* Note: This routine can be called at interrupt time. */
- /* */
- /* The IORB is considered invalid after the callback is */
- /* done. */
- /* */
- /*************************************************************************/
-
- USHORT FinishIORB(PIORB pIORB, NPDCB npDCB)
-
- {
-
- USHORT rc;
-
- rc = COMPLETE; /* assume that we will be done (in case no callout done) */
-
- /*----------------------------------------------------------------------*/
- /* First free any SCBs that were allocated for non move mode devices. */
- /*----------------------------------------------------------------------*/
-
- if (npDCB) {
- if (!(ACBTbl[npDCB->ai].status & MOVEMODE)) {
- if (IORBWRKSP(pIORB,cSCBs)) {
- FreeSCB(IORBWRKSP(pIORB,cSCBs),IORBWRKSP(pIORB,npSCBH),npDCB);
- }
- }
- }
-
- /*----------------------------------------------------------------------*/
- /* Set the error indicator if there was an error. The set our int flag */
- /* so that we know it is OK to use the reserved SCB for this device if */
- /* another stage is required. */
- /*----------------------------------------------------------------------*/
-
- pIORB->Status |= (pIORB->ErrorCode) ? IORB_ERROR : 0;
- IORBWRKSP(pIORB,Status) |= IORBINTERRUPT;
-
- /*----------------------------------------------------------------------*/
- /* Now do our local callout if needed. The call out is done only if */
- /* there was no error or if the call out on error bit is set, or there */
- /* is a recovered error. */
- /*----------------------------------------------------------------------*/
-
- if ( (IORBWRKSP(pIORB,Status) & IORBCALLOUT) &&
- ( !(pIORB->ErrorCode) ||
- (pIORB->Status & IORB_RECOV_ERROR) ||
- (IORBWRKSP(pIORB,Status) & IORBCALLOUTERR))) {
-
- rc = (*IORBWRKSP(pIORB,npfnCallOut))(pIORB, npDCB);
- }
-
- /*----------------------------------------------------------------------*/
- /* If the callout returned COMPLETE (or rc is default value) and the */
- /* IORB has the async callback bit set then make the call back. */
- /*----------------------------------------------------------------------*/
-
- if (rc == COMPLETE) {
- pIORB->Status |= IORB_DONE;
-
- TRACE(TR_FINISHED, pIORB);
- if (pIORB->RequestControl & IORB_ASYNC_POST) {
- *(pIORB->NotifyAddress)(pIORB);
- }
- }
- return(rc);
- }
-
-
- /*************************************************************************/
- /* */
- /* ValidIORBCommand */
- /* */
- /* Determine if the IORB is valid. This call validates the IORB cmd */
- /* itself, the state of the device, and the state of the adapter. */
- /* */
- /* Entry: ValidIORBCommand(pIORB) */
- /* */
- /* pIORB - pointer to the IORB. */
- /* */
- /* Exit: Returns the DCB ptr if valid, or NULL if not required. */
- /* If on return the IORB error code is not 0 then there */
- /* was an error. */
- /* */
- /*************************************************************************/
-
- NPDCB ValidIORBCommand(PIORB pIORB)
-
- {
-
- USHORT cc; /* command code */
- NPDCB npDCB;
-
- cc = pIORB->CommandCode;
- npDCB = NULL;
-
- if (cc <= MAX_IOCC_COMMAND &&
- pIORB->CommandModifier <= IORBCallTbl[cc].maxcm) {
-
- if (IORBCallTbl[cc].control & NEEDDCB) {
- if ((npDCB = FindDeviceEntry(pIORB->UnitHandle)) != NULL) {
-
- if (npDCB->UnitInfo.UnitFlags & UF_DEFECTIVE) {
- pIORB->ErrorCode = IOERR_DEVICE_DIAGFAIL;
- return(NULL);
- }
-
- if (ACBTbl[npDCB->ai].status & ADAPTERDEFECTIVE) {
- pIORB->ErrorCode = IOERR_ADAPTER_DIAGFAIL;
- return(NULL);
- }
-
- if (ACBTbl[npDCB->ai].status & RESETINPROGRESS ||
- npDCB->status & UNITDEVCTRL) {
- pIORB->ErrorCode = IOERR_DEVICE_BUSY;
- return(NULL);
- }
- }
- else {
- ERRMSG1("IORB unable to find specified DCB for unit %w\n\r",
- pIORB->UnitHandle);
- pIORB->ErrorCode = IOERR_CMD_SYNTAX;
- return(NULL);
- }
- }
-
- if (IORBCallTbl[cc].control & NEEDALLOC) {
- if (!(npDCB->status & UNITALLOCATED)) {
- pIORB->ErrorCode = IOERR_UNIT_NOT_ALLOCATED;
- return(NULL);
- }
- }
-
- }
-
- else {
- pIORB->ErrorCode = IOERR_CMD_NOT_SUPPORTED;
- return(NULL);
- }
-
- return(npDCB);
-
- }
-
- /*************************************************************************/
- /* */
- /* CountSGBlocks */
- /* */
- /* Determine the number of blocks in the SG list. */
- /* */
- /* Entry: CountSGBlocks(pSGList, cSGEntries, BlkSize) */
- /* */
- /* pSGList - ptr to the SG list */
- /* cSGEntries - number of entries */
- /* BlkSize - block size */
- /* */
- /* Exit: USHORT - number of blocks */
- /* */
- /* Notes: This routine can be called at interrupt time. */
- /* */
- /*************************************************************************/
-
- USHORT CountSGBlocks(PSCATGATENTRY pSGList, USHORT cSGEntries, USHORT BlkSize)
-
- {
-
- USHORT i;
- ULONG ByteCount;
-
- ByteCount = 0;
-
- for (i=0; i<cSGEntries; i++) {
- ByteCount += (pSGList+i)->XferBufLen;
- }
-
- return((USHORT)(ByteCount/BlkSize));
-
- }
-
-
- /*************************************************************************/
- /* */
- /* InitIORBWorkSpace */
- /* */
- /* This routine initializes the IORB ADD work space. */
- /* */
- /* Entry: InitIORBWorkSpace(pIORB) */
- /* */
- /* pIORB - ptr to the IORB. */
- /* */
- /* Exit: good always. */
- /* */
- /*************************************************************************/
-
-
- VOID InitIORBWorkSpace(PIORB pIORB)
-
- {
-
- USHORT i;
-
- for (i=0; i< ADD_WORKSPACE_SIZE; i++) {
- pIORB->ADDWorkSpace[i]=0;
- }
- IORBWRKSP(pIORB,Status) |= IORBLAST;
- IORBWRKSP(pIORB,cRetries) = RetryCount;
-
- }
-
-
- /*************************************************************************/
- /* */
- /* GetNextWork */
- /* */
- /* This routine builds the next unit of work for the device. It */
- /* removes IORBs from the waiting queue and goups them together to */
- /* form a SCB chain for the device. If an IORB is marked as one that */
- /* cannot be grouped with others then it is returned as a separate */
- /* piece of work. See below. */
- /* */
- /* Entry: GetNextWork(npDCB) */
- /* */
- /* npDCB - ptr to the DCB. */
- /* */
- /* Exit: pIORB if work ready. */
- /* NULL if no work waiting. */
- /* */
- /*************************************************************************/
-
- PIORB GetNextWork(NPDCB npDCB)
-
- {
-
- PIORB pCurIORB, /* current IORB we are working on */
- pHeadIORB, /* head of entire group/chain being built.*/
- pLastIORB; /* last IORB in current group/chain */
-
- NPSCBH npSCBH; /* scb ptr */
-
- USHORT i, j, rc;
-
- pHeadIORB = pLastIORB = NULL;
-
- /*-------------------------------------------------*/
- /* Build an IORB/SCB chain of upto size GroupSize. */
- /*-------------------------------------------------*/
-
- for (i=0; i<GroupSize; i++) {
-
- if (!(pCurIORB = DeQueueIORB(npDCB))) {
- break;
- }
-
- if (!pHeadIORB) pHeadIORB = pLastIORB = pCurIORB;
-
- /*---------------------------------------------------------------*/
- /* First mark the IORB as starting. Next check the status of */
- /* the IORB to see if it was setup completely (all resources */
- /* allocated). If so then continue. If not then make the reqd */
- /* callout (which should be a setup routine). On retrurn if */
- /* the return code is NORESOURCE then this IORB is not ready to */
- /* be started, so requeue it (at the front) and break out of the */
- /* loop now. If the return code is INCOMPLETE, then the IORB */
- /* has had some resources allocated to it is OK to start it. A */
- /* subsequent interrupt will try again to allocated more re- */
- /* sources. For this case it is OK to put the IORB on the chain */
- /* but it must be the last one, so set the loop var to the term- */
- /* inating value. */
- /*---------------------------------------------------------------*/
-
- IORBWRKSP(pCurIORB,Status) |= IORBSTARTING; /* set started bit */
-
- if (IORBWRKSP(pCurIORB,Status) & IORBINCOMPLT) {
- if (IORBWRKSP(pCurIORB,Status) & IORBCALLOUT) {
- rc = (*IORBWRKSP(pCurIORB,npfnCallOut))(pCurIORB,npDCB);
- if (rc == NORESOURCE) {
- INFMSG1("GetNextWork - callout returned no resource (%p)\n\r",
- pCurIORB);
- QueueIORB(pCurIORB, npDCB, FRONT);
- break; /* break out now */
- }
- else if (rc == INCOMPLETE) {
- i = GroupSize;
- }
- }
- else {
- ERRMSG1("Incomplete IORB found w/o callout address (%p)\n\r",
- pCurIORB);
- }
- }
-
- /*-------------------------------------------------------------------*/
- /* Now see it the IORB can be grouped with others. If it is OK then */
- /* continue. If not then see if a chain has already been started. */
- /* If so then requeue this IORB to the front of the queue and break. */
- /* If not then just break. (out of the loop) */
- /*-------------------------------------------------------------------*/
-
- if (IORBWRKSP(pCurIORB,Status) & IORBNOGROUP) {
- if (pCurIORB != pHeadIORB) {
- QueueIORB(pCurIORB, npDCB, FRONT);
- }
- break;
- }
-
- /*-------------------------------------------------------------------*/
- /* If we get here we know that the IORB is ready to be chained into */
- /* the group. A chain has been started if the current IORB is != to */
- /* the last IORB. To put the IORB on the chain, the 1st SCB in the */
- /* current IORB is linked to the last SCB on the current chain. If */
- /* no chain has been started then initialize the chain. */
- /*-------------------------------------------------------------------*/
-
- if (pCurIORB != pLastIORB) {
-
- IORBWRKSP(pLastIORB,Status) &= ~IORBLAST;
- pLastIORB->pNxtIORB = pCurIORB;
- pLastIORB->RequestControl |= IORB_CHAIN;
-
- npSCBH = IORBWRKSP(pLastIORB,npSCBH);
- for (j=0; j<IORBWRKSP(pLastIORB,cSCBs)-1; j++) {
- npSCBH = npSCBH->scbctrl.npNextSCBH;
- }
-
- npSCBH->scbctrl.npNextSCBH = IORBWRKSP(pCurIORB,npSCBH);
-
- npSCBH->scb.ppNxtSCB =
- IORBWRKSP(pCurIORB,npSCBH)->scbctrl.ppSCB;
-
- npSCBH->scb.Enable |= SCBEfCC;
-
- }
- pLastIORB = pCurIORB;
-
- if (IORBWRKSP(pCurIORB,Status) & IORBINCOMPLT) {
- break;
- }
- }
-
- return(pHeadIORB); /* return the head pointer */
- }
-
-
-
- /*************************************************************************/
- /* */
- /* Trace */
- /* */
- /* This routine inserts the info in the trace buffer. */
- /* */
- /* Entry: Trace(event, pIORB) */
- /* */
- /* event - event to put in buffer. */
- /* */
- /*************************************************************************/
-
- VOID Trace(USHORT event, PIORB pIORB)
-
- {
-
- USHORT temp; /* DO NOT REMOVE !! */
-
-
- SAVEIF();
-
- TraceIndex = (TraceIndex == MAXTRACE-1) ? 0 : ++TraceIndex;
-
- (TraceBuf+TraceIndex)->event = event;
- (TraceBuf+TraceIndex)->unit = pIORB->UnitHandle;
- (TraceBuf+TraceIndex)->pIORB = pIORB;
- (TraceBuf+TraceIndex)->cm = (UCHAR)pIORB->CommandModifier;
- (TraceBuf+TraceIndex)->cc = (UCHAR)pIORB->CommandCode;
- (TraceBuf+TraceIndex)->status = pIORB->Status;
- (TraceBuf+TraceIndex)->ec = pIORB->ErrorCode;
- (TraceBuf+TraceIndex)->npSCBH = IORBWRKSP(pIORB,npSCBH);
-
- RESTOREIF();
-
- }
-
- /*************************************************************************/
- /* */
- /* VirtToPhys */
- /* */
- /* This routine converts a virtual address to a physical address. It */
- /* will work at interrupt time. */
- /* */
- /* Entry: VirtToPhys(VirtAddr) */
- /* */
- /* VirtAddr - virtual address to be converted */
- /* */
- /* Exit: returns ULONG physical address. */
- /* */
- /*************************************************************************/
-
- ULONG VirtToPhys (PBYTE VirtAddr)
-
- {
-
- USHORT rc;
- SCATGATENTRY ScatGatEntry;
- ULONG VirtLinAddr, ScatLinAddr, PageListCount;
-
- DevHelp_VirtToLin(SELECTOROF(VirtAddr), (ULONG)(OFFSETOF(VirtAddr)),
- (PLIN)&VirtLinAddr);
-
- DevHelp_VirtToLin((USHORT)(((ULONG)((PVOID)&ScatGatEntry)) >> 16),
- (ULONG)((USHORT)((PVOID)&ScatGatEntry)),
- (PLIN)&ScatLinAddr);
-
- DevHelp_LinToPageList(VirtLinAddr, 1, ScatLinAddr, (PULONG)&PageListCount);
-
- return(ScatGatEntry.ppXferBuf);
-
- }
-
-
- /*************************************************************************/
- /* */
- /* CompleteIORBChain */
- /* */
- /* This routine loops through an IORB chain completing the IORBs as */
- /* needed. It will stop at the IORB which caused an error if */
- /* requested. */
- /* */
- /* Entry: CompleteIORBChain(npDCB, pHeadIORB, pLastIORB) */
- /* */
- /* npDCB - DCB for device */
- /* pHeadIORB - IORB at the head of the chain */
- /* pLastIORB - last IORB. This IORB will NOT be processed.*/
- /* use NULL for entire chain. */
- /* ec - error code (0 to ignore) */
- /* */
- /* Exit: pIORB - ptr to an IORB */
- /* */
- /* if pLastIORB == NULL then */
- /* pIORB = NULL if all IORBs where completed */
- /* = IORB that needs to be started (may not have */
- /* been setup completely) */
- /* */
- /* if pLastIORB <> NULL */
- /* pIORB = the error IORB if found */
- /* = NULL if not found (error condition) */
- /* */
- /*************************************************************************/
-
- PIORB CompleteIORBChain(NPDCB npDCB, PIORB pHeadIORB, PIORB pLastIORB,
- USHORT ec)
-
- {
- PIORB pCurIORB, pNextIORB;
- BOOL done;
- USHORT rc;
-
- done = FALSE;
- pCurIORB = pHeadIORB;
-
- /*------------------------------------------------------------------*/
- /* Follow the chain of IORBs finishing them until pLastIORB is */
- /* reached. An IORB is finished if it is not incomplete or an */
- /* error code was specified. If an error code is passed in then */
- /* the IORB error code is set. In all cases the IORB pointed to by */
- /* pLastIORB is not finished and is passed back. A value of NULL */
- /* for pLastIORB will complete an entire chain. The recovered */
- /* error bit is set if the IORB already has an error code and no */
- /* error code was passed in. */
- /*------------------------------------------------------------------*/
-
- while (!done && pCurIORB) {
-
- pNextIORB = pCurIORB->pNxtIORB;
-
- if (!(IORBWRKSP(pCurIORB,Status) & IORBINCOMPLT) || ec) {
-
- if (pCurIORB != pLastIORB) {
-
- if (ec) {
- pCurIORB->ErrorCode = ec;
- }
- else if (pCurIORB->ErrorCode) {
- pCurIORB->Status |= IORB_RECOV_ERROR;
- }
-
- rc = FinishIORB(pCurIORB, npDCB); /*@V95775*/
- if (rc != COMPLETE) { /*@V95775*/
- break; /* get out now and go finish */
- } /*@V95775*/
- else {
- pCurIORB = pNextIORB;
- }
- }
- }
- else {
- IORBWRKSP(pCurIORB,Status) |= IORBINTERRUPT;
- (*IORBWRKSP(pCurIORB,npfnCallOut))(pCurIORB, npDCB);
-
- #ifdef DEBUG
- if (!(IORBWRKSP(pCurIORB,Status) & IORBLAST)) {
- ERRMSG1("Incomplete IORB not last %p\n\r",pCurIORB);
- }
- #endif
- }
-
- if (pCurIORB == pLastIORB) {
- done = TRUE;
- }
- }
-
- return(pCurIORB);
-
- }
-
- /*************************************************************************/
- /* */
- /* StartLocateModeSCB */
- /* */
- /* This routine will start the requested SCB. It calls the assembler */
- /* routine to start it. Upon return if there is an error then a */
- /* reset will be done. This keeps the reset on start code in one */
- /* place. Other parts of the code may call the assembler routine */
- /* directly and do somethin different on an error if needed. This is */
- /* mainly during intialization where we are not setup to do a reset. */
- /* */
- /* If the actual start of the SCB fails, bsr never goes non busy, */
- /* then we do a reset. */
- /* */
- /* Entry: StartLocateModeSCB(IOAddr, ppSCB, ldn, flag) */
- /* */
- /* ai - adapter index */
- /* ppSCB - phys ptr to the SCB (chain) */
- /* cmd - command to the attention register of the card. */
- /* */
- /* Exit: <> 0 if some error, 0 if none, ints disabled if IORB */
- /* was started. */
- /* */
- /*************************************************************************/
-
- USHORT StartLocateModeSCB(USHORT ai, ULONG ppSCB, USHORT cmd)
-
- {
-
- USHORT ec = 0;
-
- if (_StartIO(ACBTbl[ai].baseIO, ppSCB, cmd)) {
- ResetAdapter(ai);
- ec = ERROR;
- }
-
- return(ec);
-
- }
-