/* * Device management cleanup function */ EXPORT void knl_devmgr_cleanup( void ) { OpnCB *opncb; /* Do nothing if it is not used even once */ if ( knl_resource_control_block.openq.next == NULL ) { return; } LockDM(); /* Free suspend disable request */ knl_DisSusCnt -= knl_resource_control_block.dissus; knl_resource_control_block.dissus = 0; /* Close all open devices */ while ( !isQueEmpty(&(knl_resource_control_block.openq)) ) { opncb = RESQ_OPNCB(knl_resource_control_block.openq.next); /* Indicate that it is during close processing */ opncb->resid = 0; UnlockDM(); /* Device close processing */ knl_close_device(opncb, 0); LockDM(); } UnlockDM(); return; }
/* * Device close */ SYSCALL ER tk_cls_dev_impl( ID dd, UINT option ) { OpnCB *opncb; ER ercd; LockDM(); ercd = knl_check_devdesc(dd, 0, &opncb); if ( ercd < E_OK ) { UnlockDM(); goto err_ret; } opncb->resid = 0; /* Indicate that it is during close processing */ UnlockDM(); /* Device close processing */ ercd = knl_close_device(opncb, option); err_ret: #ifdef DEBUG if ( ercd < E_OK ) { DEBUG_PRINT(("tk_cls_dev_impl ercd = %d\n", ercd)); } #endif return ercd; }
/* * Device close processing */ LOCAL ER close_device( OpnCB *opncb, UINT option ) { ID devid; DevCB *devcb; INT unitno; WaitQ waiq; ER ercd = E_OK; /* Abort all requests during processing */ abort_allrequest(opncb); LockDM(); devcb = opncb->devcb; unitno = opncb->unitno; devid = DEVID(devcb, unitno); /* Multiple tasks can initiate open/close processing, so ensure processing only by one task at a time. */ if ( enterSyncWait(&devcb->syncq, &waiq) ) { /* Wait for synchronization for concurrent open/close */ UnlockDM(); SyncWaitDM(); LockDM(); } /* Is device driver call required? */ if ( chkopen(devcb, unitno, opncb) ) { if ( (devcb->ddev.drvatr & TDA_OPENREQ) == 0 ) { goto no_drvcall; } option &= ~TD_EJECT; /* EJECT is effective at last close */ } /* Device driver call */ UnlockDM(); ercd = call_closefn(devcb, DEVID(devcb, unitno), option); LockDM(); no_drvcall: /* Free open management block */ delOpnCB(opncb); /* Wake up task waiting for synchronization for concurrent open/close */ leaveSyncWait(&devcb->syncq, &waiq); UnlockDM(); ERCD_PRINT(("close_device ercd = %d\n", ercd)); return ercd; }
/* * Suspend */ LOCAL ER do_suspend( void ) { ER ercd; /* Stop accepting device registration/unregistration */ LockREG(); /* Suspend processing of device except for disks */ ercd = sendevt_alldevice(TDV_SUSPEND, FALSE); #ifdef DEBUG if ( ercd < E_OK ) { DEBUG_PRINT(("2. do_suspend -> sendevt_alldevice ercd = %d\n", ercd)); } #endif /* Suspend processing of disk device */ ercd = sendevt_alldevice(TDV_SUSPEND, TRUE); #ifdef DEBUG if ( ercd < E_OK ) { DEBUG_PRINT(("3. do_suspend -> sendevt_alldevice ercd = %d\n", ercd)); } #endif /* Stop accepting new requests */ LockDM(); /* * Insert code to transit to suspend state here */ /* * Insert code executed on returning from suspend state */ /* Resume accepting requests */ UnlockDM(); /* Resume processing of disk device */ ercd = sendevt_alldevice(TDV_RESUME, TRUE); #ifdef DEBUG if ( ercd < E_OK ) { DEBUG_PRINT(("7. do_suspend -> sendevt_alldevice ercd = %d\n", ercd)); } #endif /* Resume processing of device except for disks */ ercd = sendevt_alldevice(TDV_RESUME, FALSE); #ifdef DEBUG if ( ercd < E_OK ) { DEBUG_PRINT(("8. do_suspend -> sendevt_alldevice ercd = %d\n", ercd)); } #endif /* Resume accepting device registration/unregistration */ UnlockREG(); return ercd; }
/* * Suspend */ LOCAL ER do_suspend( void ) { ER ercd; /* Stop accepting device registration/unregistration */ LockREG(); /* Processing before starting subsystem suspend */ ercd = tk_evt_ssy(0, TSEVT_SUSPEND_BEGIN, 0, 0); ERCD_PRINT(("1. do_suspend -> tk_evt_ssy ercd = %d\n", ercd)); /* Suspend processing of device except for disks */ ercd = sendevt_alldevice(TDV_SUSPEND, FALSE); ERCD_PRINT(("2. do_suspend -> sendevt_alldevice ercd = %d\n", ercd)); /* Suspend processing of disk device */ ercd = sendevt_alldevice(TDV_SUSPEND, TRUE); ERCD_PRINT(("3. do_suspend -> sendevt_alldevice ercd = %d\n", ercd)); /* Stop accepting new requests */ LockDM(); /* Processing after completion of subsystem suspend */ ercd = tk_evt_ssy(0, TSEVT_SUSPEND_DONE, 0, 0); ERCD_PRINT(("4. do_suspend -> tk_evt_ssy ercd = %d\n", ercd)); /* Transit to suspend state */ ercd = tk_set_pow(TPW_DOSUSPEND); ERCD_PRINT(("5. do_suspend -> tk_set_pow ercd = %d\n", ercd)); /* Return from suspend state */ /* Processing before starting subsystem resume */ ercd = tk_evt_ssy(0, TSEVT_RESUME_BEGIN, 0, 0); ERCD_PRINT(("6. do_suspend -> tk_evt_ssy ercd = %d\n", ercd)); /* Resume accepting requests */ UnlockDM(); /* Resume processing of disk device */ ercd = sendevt_alldevice(TDV_RESUME, TRUE); ERCD_PRINT(("7. do_suspend -> sendevt_alldevice ercd = %d\n", ercd)); /* Resume processing of device except for disks */ ercd = sendevt_alldevice(TDV_RESUME, FALSE); ERCD_PRINT(("8. do_suspend -> sendevt_alldevice ercd = %d\n", ercd)); /* Resume accepting device registration/unregistration */ UnlockREG(); /* Processing after completion of subsystem resume */ ercd = tk_evt_ssy(0, TSEVT_RESUME_DONE, 0, 0); ERCD_PRINT(("9. do_suspend -> tk_evt_ssy ercd = %d\n", ercd)); return ercd; }
/* * Device management cleanup function */ EXPORT void devmgr_cleanup( ID resid, INT info ) { ResCB *rescb; OpnCB *opncb; ER ercd; ercd = tk_get_res(resid, DEVICE_SVC, (void**)&rescb); if ( ercd < E_OK ) { goto err_ret; } /* Do nothing if it is not used even once */ if ( rescb->openq.next == NULL ) { return; } LockDM(); /* Free suspend disable request */ DisSusCnt -= rescb->dissus; rescb->dissus = 0; /* Close all open devices */ while ( !isQueEmpty(&rescb->openq) ) { opncb = RESQ_OPNCB(rescb->openq.next); /* Indicate that it is during close processing */ opncb->resid = -1; /* Device close processing */ UnlockDM(); close_device(opncb, 0); LockDM(); } UnlockDM(); return; err_ret: DEBUG_PRINT(("devmgr_cleanup ercd = %d\n", ercd)); return; }
/* * Device management break function */ EXPORT void devmgr_break( ID tskid ) { ResCB *rescb; OpnCB *opncb; ReqCB *reqcb; QUEUE *q, *r; DEVREQ *devreq = NULL; INT nreq; /* Get resource management block */ rescb = GetResCB(DEVICE_SVC, tskid); if ( rescb == NULL ) { return; } LockDM(); /* Search the request if 'tskid' task is executing and request abort */ nreq = 0; for ( q = rescb->openq.next; q != &rescb->openq; q = q->next ) { opncb = RESQ_OPNCB(q); if ( opncb->nwaireq > 0 ) { /* Multiple requests wait */ reqcb = DEVREQ_REQCB(opncb->waireqlst); if ( reqcb->tskid == tskid ) { devreq = opncb->waireqlst; nreq = opncb->nwaireq; } } else { /* Start request or single request wait */ for ( r = opncb->requestq.next; r != &opncb->requestq; r = r->next ) { reqcb = (ReqCB*)r; if ( reqcb->tskid == tskid ) { devreq = &reqcb->req; devreq->c.abort = TRUE; nreq = 1; break; } } } if ( nreq > 0 ) { LockDAbort(); break; } } UnlockDM(); if ( nreq > 0 ) { /* Abort request: Device driver call */ call_abortfn(opncb->devcb, tskid, devreq, nreq); UnlockDAbort(); } }
/* * Device management startup function */ EXPORT void knl_devmgr_startup( void ) { LockDM(); /* Initialization of open device management queue */ QueInit(&(knl_resource_control_block.openq)); knl_resource_control_block.dissus = 0; UnlockDM(); return; }
/* * Get resource management information */ EXPORT ResCB* knl_GetResCB( void ) { LockDM(); /* If the startup function is not called, initialize at this point */ if ( knl_resource_control_block.openq.next == NULL ) { /* Initialization of open device management queue */ QueInit(&(knl_resource_control_block.openq)); } UnlockDM(); return &knl_resource_control_block; }
/* * Device close */ EXPORT ER _tk_cls_dev( ID dd, UINT option ) { OpnCB *opncb; ER ercd; LockDM(); ercd = check_devdesc(dd, 0, &opncb); if ( ercd < E_OK ) { UnlockDM(); goto err_ret; } opncb->resid = -1; /* Indicate that it is during close processing */ UnlockDM(); /* Device close processing */ ercd = close_device(opncb, option); err_ret: ERCD_PRINT(("_tk_cls_dev ercd = %d\n", ercd)); return ercd; }
/* * Get resource management information */ LOCAL ResCB* GetResCB( ID ssid, ID tskid ) { ResCB *rescb; rescb = GetResBlk(ssid, tskid); if ( rescb == NULL ) { return NULL; } LockDM(); /* If the startup function is not called, initialize at this point */ if ( rescb->openq.next == NULL ) { /* Initialization of open device management queue */ QueInit(&rescb->openq); } UnlockDM(); return rescb; }
/* * Device management startup function */ EXPORT void devmgr_startup( ID resid, INT info ) { ResCB *rescb; ER ercd; ercd = tk_get_res(resid, DEVICE_SVC, (void**)&rescb); if ( ercd < E_OK ) { goto err_ret; } LockDM(); /* Initialization of open device management queue */ QueInit(&rescb->openq); rescb->dissus = 0; UnlockDM(); return; err_ret: DEBUG_PRINT(("devmgr_cleanup ercd = %d\n", ercd)); return; }
/* * Suspend processing */ SYSCALL INT tk_sus_dev_impl( UINT mode ) { ResCB *rescb; BOOL suspend = FALSE; ER ercd; /* Get resource management information */ rescb = knl_GetResCB(); if ( rescb == NULL ) { ercd = E_CTX; goto err_ret1; } LockDM(); switch ( mode & 0xf ) { case TD_SUSPEND: /* Suspend */ if ( knl_DisSusCnt > 0 && (mode & TD_FORCE) == 0 ) { ercd = E_BUSY; goto err_ret2; } suspend = TRUE; break; case TD_DISSUS: /* Disable suspend */ if ( knl_DisSusCnt >= MAX_DISSUS ) { ercd = E_QOVR; goto err_ret2; } knl_DisSusCnt++; rescb->dissus++; break; case TD_ENASUS: /* Enable suspend */ if ( rescb->dissus > 0 ) { rescb->dissus--; knl_DisSusCnt--; } break; case TD_CHECK: /* Get suspend disable request count */ break; default: ercd = E_PAR; goto err_ret2; } UnlockDM(); if ( suspend ) { /* Suspend */ ercd = do_suspend(); if ( ercd < E_OK ) { goto err_ret1; } } return knl_DisSusCnt; err_ret2: UnlockDM(); err_ret1: DEBUG_PRINT(("tk_sus_dev_impl ercd = %d\n", ercd)); return ercd; }
/* * 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; }
/* * Request for starting input/output to device */ EXPORT ID knl_request( ID dd, W start, VP buf, W size, TMO tmout, INT cmd ) { EXCFN execfn; VP exinf; #if TA_GP VP gp; #endif OpnCB *opncb; DevCB *devcb; ReqCB *reqcb; UINT m; ER ercd; LockDM(); if ( start <= -0x00010000 && start >= -0x7fffffff ) { m = 0; /* Ignore open mode */ } else { m = ( cmd == TDC_READ )? TD_READ: TD_WRITE; } ercd = knl_check_devdesc(dd, m, &opncb); if ( ercd < E_OK ) { goto err_ret1; } devcb = opncb->devcb; execfn = (EXCFN)devcb->ddev.execfn; exinf = devcb->ddev.exinf; #if TA_GP gp = devcb->ddev.gp; #endif /* Get request management block */ reqcb = newReqCB(opncb); if ( reqcb == NULL ) { ercd = E_LIMIT; goto err_ret1; } /* Set request packet */ reqcb->req.next = NULL; reqcb->req.exinf = NULL; reqcb->req.devid = DEVID(devcb, opncb->unitno); reqcb->req.cmd = cmd; reqcb->req.abort = FALSE; reqcb->req.start = start; reqcb->req.size = size; reqcb->req.buf = buf; reqcb->req.asize = 0; reqcb->req.error = 0; /* Indicate that it is during processing */ reqcb->tskid = tk_get_tid_impl(); UnlockDM(); /* Device driver call */ DISABLE_INTERRUPT; knl_ctxtsk->sysmode++; ENABLE_INTERRUPT; #if TA_GP ercd = CallDeviceDriver(&reqcb->req, tmout, exinf, 0, (FP)execfn, gp); #else ercd = (*execfn)(&reqcb->req, tmout, exinf); #endif DISABLE_INTERRUPT; knl_ctxtsk->sysmode--; ENABLE_INTERRUPT; LockDM(); /* Indicate that it is not during processing */ reqcb->tskid = 0; /* 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); } if ( ercd < E_OK ) { goto err_ret2; } UnlockDM(); return REQID(reqcb); err_ret2: knl_delReqCB(reqcb); err_ret1: UnlockDM(); DEBUG_PRINT(("knl_request ercd = %d\n", ercd)); return ercd; }
/* * Device open */ EXPORT ID _tk_opn_dev( CONST UB *devnm, UINT omode ) { UB pdevnm[L_DEVNM + 1]; INT unitno; ResCB *rescb; DevCB *devcb; OpnCB *opncb; WaitQ waiq; ER ercd; ercd = ChkSpaceBstrR(devnm, 0); if ( ercd < E_OK ) { goto err_ret1; } unitno = phydevnm(pdevnm, devnm); /* Get resource management information */ rescb = GetResCB(DEVICE_SVC, TSK_SELF); if ( rescb == NULL ) { ercd = E_CTX; goto err_ret1; } LockDM(); /* Search device to open */ devcb = searchDevCB(pdevnm); if ( devcb == NULL || unitno > devcb->ddev.nsub ) { ercd = E_NOEXS; goto err_ret2; } /* Check open mode */ ercd = chkopenmode(devcb, unitno, omode); if ( ercd < E_OK ) { goto err_ret2; } /* Get open management block */ opncb = newOpnCB(devcb, unitno, omode, rescb); if ( opncb == NULL ) { ercd = E_LIMIT; goto err_ret2; } /* Multiple tasks can initiate open/close processing, so ensure processing only by one task at a time. */ if ( enterSyncWait(&devcb->syncq, &waiq) ) { /* Wait for synchronization for concurrent open/close */ UnlockDM(); SyncWaitDM(); LockDM(); } /* Is device driver call required? */ if ( ! ( chkopen(devcb, unitno, opncb) && (devcb->ddev.drvatr & TDA_OPENREQ) == 0 ) ) { /* Device driver call */ UnlockDM(); ercd = call_openfn(devcb, DEVID(devcb, unitno), omode); LockDM(); if ( ercd < E_OK ) { goto err_ret3; } } opncb->resid = tk_get_rid(TSK_SELF); /* Indicate that open processing is completed */ /* Wake up task waiting for synchronization for concurrent open/close */ leaveSyncWait(&devcb->syncq, &waiq); UnlockDM(); return DD(opncb); err_ret3: delOpnCB(opncb); leaveSyncWait(&devcb->syncq, &waiq); err_ret2: UnlockDM(); err_ret1: DEBUG_PRINT(("_tk_opn_dev ercd = %d\n", ercd)); return ercd; }
/* * Device close processing */ EXPORT ER knl_close_device( OpnCB *opncb, UINT option ) { CLSFN closefn; VP exinf; #if TA_GP VP gp; #endif ID devid; DevCB *devcb; INT unitno; ER ercd = E_OK; /* Abort all requests during processing */ abort_allrequest(opncb); LockDM(); devcb = opncb->devcb; unitno = opncb->unitno; closefn = (CLSFN)devcb->ddev.closefn; exinf = devcb->ddev.exinf; #if TA_GP gp = devcb->ddev.gp; #endif devid = DEVID(devcb, unitno); /* Delete semaphore for completion check of abortion */ tk_del_sem_impl(opncb->abort_semid); /* Free open management block */ knl_delOpnCB(opncb, FALSE); /* Is device driver call required? */ if ( knl_chkopen(devcb, unitno) ) { option &= ~TD_EJECT; if ( (devcb->ddev.drvatr & TDA_OPENREQ) == 0 ) { closefn = NULL; } } UnlockDM(); if ( closefn != NULL ) { /* Device driver call */ DISABLE_INTERRUPT; knl_ctxtsk->sysmode++; ENABLE_INTERRUPT; #if TA_GP ercd = CallDeviceDriver(devid, option, exinf, 0, (FP)closefn, gp); #else ercd = (*closefn)(devid, option, exinf); #endif DISABLE_INTERRUPT; knl_ctxtsk->sysmode--; ENABLE_INTERRUPT; } LockDM(); /* Return open management block to FreeQue */ QueInsert(&opncb->q, &knl_FreeOpnCB); UnlockDM(); #ifdef DEBUG if ( ercd < E_OK ) { DEBUG_PRINT(("knl_close_device ercd = %d\n", ercd)); } #endif return ercd; }
/* * Abort all requests */ LOCAL void abort_allrequest( OpnCB *opncb ) { ABTFN abortfn; WAIFN waitfn; VP exinf; #if TA_GP VP gp; #endif DevCB *devcb; ReqCB *reqcb; QUEUE *q; /* If 'execfn' and 'waitfn' are called, execute abort request. */ LockDM(); devcb = opncb->devcb; abortfn = (ABTFN)devcb->ddev.abortfn; waitfn = (WAIFN)devcb->ddev.waitfn; exinf = devcb->ddev.exinf; #if TA_GP gp = devcb->ddev.gp; #endif opncb->abort_tskid = tk_get_tid_impl(); opncb->abort_cnt = 0; if ( opncb->nwaireq > 0 ) { /* Multiple requests wait */ reqcb = DEVREQ_REQCB(opncb->waireqlst); /* Device driver call */ DISABLE_INTERRUPT; knl_ctxtsk->sysmode++; ENABLE_INTERRUPT; #if TA_GP CallDeviceDriver(reqcb->tskid, opncb->waireqlst, opncb->nwaireq, exinf, (FP)abortfn, gp); #else (*abortfn)(reqcb->tskid, opncb->waireqlst, opncb->nwaireq, exinf); #endif DISABLE_INTERRUPT; knl_ctxtsk->sysmode--; ENABLE_INTERRUPT; opncb->abort_cnt++; } else { /* Start request or single request wait */ for ( q = opncb->requestq.next; q != &opncb->requestq; q = q->next ) { reqcb = (ReqCB*)q; if ( reqcb->tskid == 0 ) { continue; } reqcb->req.abort = TRUE; /* Device driver call */ DISABLE_INTERRUPT; knl_ctxtsk->sysmode++; ENABLE_INTERRUPT; #if TA_GP CallDeviceDriver(reqcb->tskid, &reqcb->req, 1, exinf, (FP)abortfn, gp); #else (*abortfn)(reqcb->tskid, &reqcb->req, 1, exinf); #endif DISABLE_INTERRUPT; knl_ctxtsk->sysmode--; ENABLE_INTERRUPT; opncb->abort_cnt++; } } UnlockDM(); if ( opncb->abort_cnt > 0 ) { /* Wait for completion of abort request processing */ tk_wai_sem_impl(opncb->abort_semid, 1, TMO_FEVR); } opncb->abort_tskid = 0; /* Abort remaining requests and wait for completion */ LockDM(); while ( !isQueEmpty(&opncb->requestq) ) { reqcb = (ReqCB*)opncb->requestq.next; reqcb->req.abort = TRUE; UnlockDM(); /* Device driver call */ DISABLE_INTERRUPT; knl_ctxtsk->sysmode++; ENABLE_INTERRUPT; #if TA_GP CallDeviceDriver(&reqcb->req, 1, TMO_FEVR, exinf, (FP)waitfn, gp); #else (*waitfn)(&reqcb->req, 1, TMO_FEVR, exinf); #endif DISABLE_INTERRUPT; knl_ctxtsk->sysmode--; ENABLE_INTERRUPT; LockDM(); /* Unregister completed request */ knl_delReqCB(reqcb); } UnlockDM(); }
/* * Device open */ SYSCALL ID tk_opn_dev_impl( UB *devnm, UINT omode ) { OPNFN openfn; VP exinf; #if TA_GP VP gp; #endif UB pdevnm[L_DEVNM + 1]; INT unitno; ResCB *rescb; DevCB *devcb; OpnCB *opncb; ER ercd; ID semid; unitno = knl_phydevnm(pdevnm, devnm); /* Get resource management information */ rescb = knl_GetResCB(); if ( rescb == NULL ) { ercd = E_CTX; goto err_ret1; } LockDM(); /* Search device to open */ devcb = knl_searchDevCB(pdevnm); if ( devcb == NULL || unitno > devcb->ddev.nsub ) { ercd = E_NOEXS; goto err_ret2; } /* Check open mode */ ercd = chkopenmode(devcb, unitno, omode); if ( ercd < E_OK ) { goto err_ret2; } openfn = (OPNFN)devcb->ddev.openfn; exinf = devcb->ddev.exinf; #if TA_GP gp = devcb->ddev.gp; #endif /* Is device driver call required? */ if ( knl_chkopen(devcb, unitno) && (devcb->ddev.drvatr & TDA_OPENREQ) == 0 ) { openfn = NULL; } /* Get open management block */ opncb = newOpnCB(devcb, unitno, omode, rescb); if ( opncb == NULL ) { ercd = E_LIMIT; goto err_ret2; } semid = tk_cre_sem_impl(&knl_pk_csem_DM); if ( semid < E_OK ) { ercd = E_SYS; goto err_ret2_5; } opncb->abort_semid = semid; UnlockDM(); if ( openfn != NULL ) { /* Device driver call */ DISABLE_INTERRUPT; knl_ctxtsk->sysmode++; ENABLE_INTERRUPT; #if TA_GP ercd = CallDeviceDriver(DEVID(devcb, unitno), omode, exinf, 0, (FP)openfn, gp); #else ercd = (*openfn)(DEVID(devcb, unitno), omode, exinf); #endif DISABLE_INTERRUPT; knl_ctxtsk->sysmode--; ENABLE_INTERRUPT; if ( ercd < E_OK ) { goto err_ret3; } } LockDM(); opncb->resid = 1; /* Indicate that open processing is completed */ UnlockDM(); return DD(opncb); err_ret3: LockDM(); err_ret2_5: knl_delOpnCB(opncb, TRUE); err_ret2: UnlockDM(); err_ret1: DEBUG_PRINT(("tk_opn_dev_impl ercd = %d\n", ercd)); return ercd; }
/* * Abort all requests */ LOCAL void abort_allrequest( OpnCB *opncb ) { DevCB *devcb; ReqCB *reqcb; QUEUE *q; /* If 'execfn' and 'waitfn' are called, execute abort request. */ LockDM(); devcb = opncb->devcb; opncb->abort_tskid = tk_get_tid(); opncb->abort_cnt = 0; LockDAbort(); UnlockDM(); if ( opncb->nwaireq > 0 ) { /* Multiple requests wait */ reqcb = DEVREQ_REQCB(opncb->waireqlst); /* Device driver call */ call_abortfn(devcb, reqcb->tskid, opncb->waireqlst, opncb->nwaireq); opncb->abort_cnt++; } else { /* Start request or single request wait */ for ( q = opncb->requestq.next; q != &opncb->requestq; q = q->next ) { reqcb = (ReqCB*)q; if ( reqcb->tskid == 0 ) { continue; } reqcb->req.c.abort = TRUE; /* Device driver call */ call_abortfn(devcb, reqcb->tskid, &reqcb->req, 1); opncb->abort_cnt++; } } UnlockDAbort(); if ( opncb->abort_cnt > 0 ) { /* Wait for completion of abort request processing */ SyncWaitDM(); } opncb->abort_tskid = 0; /* Abort remaining requests and wait for completion */ LockDM(); while ( !isQueEmpty(&opncb->requestq) ) { reqcb = (ReqCB*)opncb->requestq.next; reqcb->req.c.abort = TRUE; /* Device driver waitfn call */ UnlockDM(); call_waitfn(devcb, &reqcb->req, 1, TMO_FEVR); LockDM(); /* Unregister completed request */ delReqCB(reqcb); } UnlockDM(); }
/* * 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; }
/* * Request for starting input/output to device */ LOCAL ID request( ID dd, D start, void *buf, INT size, TMO_U tmout, INT cmd, enum ReqType syncreq ) { ATR drvatr; OpnCB *opncb; DevCB *devcb; ReqCB *reqcb; UINT m; ER ercd; LockDM(); /* Check whether there is a break request */ ercd = check_break(); if ( ercd < E_OK ) { goto err_ret1; } m = ( cmd == TDC_READ )? TD_READ: TD_WRITE; ercd = check_devdesc(dd, m, &opncb); if ( ercd < E_OK ) { goto err_ret1; } if ( syncreq == SyncReq ) { /* synchronous I/O is prohibited while there are pending I/O requests for completion */ if ( opncb->nwaireq > 0 ) { ercd = E_OBJ; goto err_ret1; } opncb->syncreq++; } devcb = opncb->devcb; drvatr = devcb->ddev.drvatr; /* check the range of parameter value */ if ( (drvatr & TDA_DEV_D) == 0 ) { if ( start > 0x7fffffff || start < (-0x7fffffff-1) ) { ercd = E_PAR; goto err_ret2; } } /* Get request management block */ reqcb = newReqCB(opncb); if ( reqcb == NULL ) { ercd = E_LIMIT; goto err_ret2; } /* Set request packet */ MEMSET(&reqcb->req, 0, sizeof(DEVREQ)); reqcb->req.c.devid = DEVID(devcb, opncb->unitno); reqcb->req.c.cmd = cmd; if ( (opncb->omode & TD_NOLOCK) != 0 ) { reqcb->req.c.nolock = TRUE; } if ( (drvatr & TDA_DEV_D) == 0 ) { reqcb->req.s.start = start; reqcb->req.s.size = size; reqcb->req.s.buf = buf; } else { reqcb->req.l.start_d = start; reqcb->req.l.size = size; reqcb->req.l.buf = buf; } ercd = tk_get_tsp(TSK_SELF, &reqcb->req.c.tskspc); if ( ercd < E_OK ) { goto err_ret3; } /* Indicate that it is during processing */ reqcb->tskid = tk_get_tid(); /* Device driver call */ UnlockDM(); ercd = call_execfn(devcb, &reqcb->req, tmout); LockDM(); LockDAbort(); /* Indicate that it is not during processing */ reqcb->tskid = 0; /* If there is an abort completion wait task, notify abort completion */ if ( opncb->abort_tskid > 0 && --opncb->abort_cnt == 0 ) { SyncSignalDM(opncb->abort_tskid); } UnlockDAbort(); if ( ercd < E_OK ) { goto err_ret3; } UnlockDM(); return REQID(reqcb); err_ret3: delReqCB(reqcb); err_ret2: if ( syncreq == SyncReq ) { opncb->syncreq--; } err_ret1: UnlockDM(); DEBUG_PRINT(("request ercd = %d\n", ercd)); return ercd; }