/* * Verify validity of request ID */ LOCAL ReqCB* check_reqid( ID reqid, OpnCB *opncb ) { ReqCB *reqcb; if ( reqid < 1 || reqid > MaxReqDev ) { return NULL; } reqcb = REQCB(reqid); if ( reqcb->opncb != opncb ) { return NULL; } return reqcb; }
/* * Verify validity of request ID */ LOCAL ReqCB* knl_check_reqid( ID reqid, OpnCB *opncb ) { ReqCB *reqcb; if ( reqid < 1 || reqid > CFN_MAX_REQDEV ) { return NULL; } reqcb = REQCB(reqid); if ( reqcb->opncb != opncb ) { return NULL; } return reqcb; }
/* * Request completion wait */ SYSCALL ID tk_wai_dev_impl( ID dd, ID reqid, W *asize, ER *ioer, TMO tmout ) { WAIFN waitfn; VP exinf; #if TA_GP VP gp; #endif OpnCB *opncb; DevCB *devcb; ReqCB *reqcb; T_DEVREQ *devreq; INT reqno, nreq; ID tskid; ER ercd; tskid = tk_get_tid_impl(); LockDM(); ercd = knl_check_devdesc(dd, 0, &opncb); if ( ercd < E_OK ) { goto err_ret2; } devcb = opncb->devcb; waitfn = (WAIFN)devcb->ddev.waitfn; exinf = devcb->ddev.exinf; #if TA_GP gp = devcb->ddev.gp; #endif if ( reqid == 0 ) { /* When waiting for completion of any of requests for 'dd' */ if ( opncb->nwaireq > 0 || opncb->waitone > 0 ) { ercd = E_OBJ; goto err_ret2; } if ( isQueEmpty(&opncb->requestq) ) { ercd = E_NOEXS; goto err_ret2; } /* Create wait request list */ reqcb = (ReqCB*)opncb->requestq.next; for ( nreq = 1;; nreq++ ) { reqcb->tskid = tskid; devreq = &reqcb->req; reqcb = (ReqCB*)reqcb->q.next; if ( reqcb == (ReqCB*)&opncb->requestq ) { break; } devreq->next = &reqcb->req; } devreq->next = NULL; devreq = &((ReqCB*)opncb->requestq.next)->req; opncb->waireqlst = devreq; opncb->nwaireq = nreq; } else { /* Wait for completion of abort request processing */ reqcb = knl_check_reqid(reqid, opncb); if ( reqcb == NULL ) { ercd = E_ID; goto err_ret2; } if ( opncb->nwaireq > 0 || reqcb->tskid > 0 ) { ercd = E_OBJ; goto err_ret2; } /* Create waiting request list */ reqcb->tskid = tskid; devreq = &reqcb->req; devreq->next = NULL; nreq = 1; opncb->waitone++; } UnlockDM(); /* Device driver call */ DISABLE_INTERRUPT; knl_ctxtsk->sysmode++; ENABLE_INTERRUPT; #if TA_GP reqno = CallDeviceDriver(devreq, nreq, tmout, exinf, (FP)waitfn, gp); #else reqno = (*waitfn)(devreq, nreq, tmout, exinf); #endif DISABLE_INTERRUPT; knl_ctxtsk->sysmode--; ENABLE_INTERRUPT; if ( reqno < E_OK ) { ercd = reqno; } if ( reqno >= nreq ) { ercd = E_SYS; } LockDM(); /* Free wait processing */ if ( reqid == 0 ) { opncb->nwaireq = 0; } else { opncb->waitone--; } /* If there is an abort completion wait task, notify abort completion */ if ( opncb->abort_tskid > 0 && --opncb->abort_cnt == 0 ) { tk_sig_sem_impl(opncb->abort_semid, 1); } /* Get processing result */ while ( devreq != NULL ) { reqcb = DEVREQ_REQCB(devreq); if ( reqno-- == 0 ) { reqid = REQID(reqcb); *asize = devreq->asize; *ioer = devreq->error; } reqcb->tskid = 0; devreq = devreq->next; } if ( ercd < E_OK ) { goto err_ret2; } /* Unregister completed request */ knl_delReqCB(REQCB(reqid)); UnlockDM(); return reqid; err_ret2: UnlockDM(); DEBUG_PRINT(("tk_wai_dev_impl ercd = %d\n", ercd)); return ercd; }
/* * wait for I/O completion for a device */ LOCAL ID waitcomplete( ID dd, ID reqid, W *asize, ER *ioer, TMO_U tmout, enum ReqType syncreq ) { ATR drvatr; OpnCB *opncb; DevCB *devcb; ReqCB *reqcb; DEVREQ *devreq; INT reqno, nreq; ID tskid; BOOL abort; ER ercd; tskid = tk_get_tid(); LockDM(); ercd = check_devdesc(dd, 0, &opncb); if ( ercd < E_OK ) { goto err_ret1; } /* Check whether there is a break request */ abort = FALSE; ercd = check_break(); if ( ercd < E_OK ) { if ( syncreq == AsyncReq ) goto err_ret1; abort = TRUE; } devcb = opncb->devcb; drvatr = devcb->ddev.drvatr; if ( reqid == 0 ) { /* When waiting for completion of any of requests for 'dd' */ if ( opncb->nwaireq > 0 || opncb->waitone > 0 || opncb->syncreq > 0 ) { ercd = E_OBJ; goto err_ret1; } if ( isQueEmpty(&opncb->requestq) ) { ercd = E_NOEXS; goto err_ret1; } /* Create wait request list */ reqcb = (ReqCB*)opncb->requestq.next; for ( nreq = 1;; nreq++ ) { reqcb->tskid = tskid; devreq = &reqcb->req; reqcb = (ReqCB*)reqcb->q.next; if ( reqcb == (ReqCB*)&opncb->requestq ) { break; } devreq->c.next = &reqcb->req; } devreq->c.next = NULL; devreq = &((ReqCB*)opncb->requestq.next)->req; opncb->waireqlst = devreq; opncb->nwaireq = nreq; } else { /* Wait for completion of abort request processing */ reqcb = check_reqid(reqid, opncb); if ( reqcb == NULL ) { ercd = E_ID; goto err_ret1; } if ( opncb->nwaireq > 0 || reqcb->tskid > 0 ) { ercd = E_OBJ; goto err_ret1; } /* Create waiting request list */ reqcb->tskid = tskid; devreq = &reqcb->req; devreq->c.next = NULL; if ( abort ) devreq->c.abort = TRUE; nreq = 1; opncb->waitone++; } /* Device driver call */ UnlockDM(); reqno = call_waitfn(devcb, devreq, nreq, tmout); LockDM(); if ( reqno < E_OK ) { ercd = reqno; } else if ( reqno >= nreq ) { ercd = E_SYS; } LockDAbort(); /* Free wait processing */ if ( reqid == 0 ) { opncb->nwaireq = 0; } else { opncb->waitone--; } /* If there is an abort completion wait task, notify abort completion */ if ( opncb->abort_tskid > 0 && --opncb->abort_cnt == 0 ) { SyncSignalDM(opncb->abort_tskid); } /* Get processing result */ while ( devreq != NULL ) { reqcb = DEVREQ_REQCB(devreq); if ( reqno-- == 0 ) { reqid = REQID(reqcb); if ( (drvatr & TDA_DEV_D) == 0 ) { *asize = devreq->s.asize; *ioer = devreq->s.error; } else { *asize = devreq->l.asize; *ioer = devreq->l.error; } } reqcb->tskid = 0; devreq = devreq->c.next; } UnlockDAbort(); if ( ercd < E_OK ) { goto err_ret1; } if ( syncreq == SyncReq ) { opncb->syncreq--; } /* Unregister completed request */ delReqCB(REQCB(reqid)); UnlockDM(); return reqid; err_ret1: if ( syncreq == SyncReq ) { opncb->syncreq--; } UnlockDM(); DEBUG_PRINT(("waitcomplete ercd = %d\n", ercd)); return ercd; }