static void tws_reset_cb(void *arg) { struct tws_softc *sc = (struct tws_softc *)arg; time_t endt; int found = 0; u_int32_t reg; if ( tws_get_state(sc) != TWS_RESET ) { return; } // device_printf(sc->tws_dev, "Draining Busy Queue\n"); tws_drain_busy_queue(sc); // device_printf(sc->tws_dev, "Draining Reserved Reqs\n"); tws_drain_reserved_reqs(sc); // device_printf(sc->tws_dev, "Draining Response Queue\n"); tws_drain_response_queue(sc); // device_printf(sc->tws_dev, "Looking for controller ready flag...\n"); endt = TWS_LOCAL_TIME + TWS_POLL_TIMEOUT; while ((TWS_LOCAL_TIME <= endt) && (!found)) { reg = tws_read_reg(sc, TWS_I2O0_SCRPD3, 4); if ( reg & TWS_BIT13 ) { found = 1; // device_printf(sc->tws_dev, " ... Got it!\n"); } } if ( !found ) device_printf(sc->tws_dev, " ... Controller ready flag NOT found!\n"); }
void tws_reset(void *arg) { struct tws_softc *sc = (struct tws_softc *)arg; mtx_lock(&sc->gen_lock); if ( tws_get_state(sc) == TWS_RESET ) { mtx_unlock(&sc->gen_lock); return; } tws_teardown_intr(sc); xpt_freeze_simq(sc->sim, 1); tws_send_event(sc, TWS_RESET_START); device_printf(sc->tws_dev, "Resetting controller\n"); tws_assert_soft_reset(sc); tws_turn_off_interrupts(sc); tws_reset_cb( (void*) sc ); tws_reinit( (void*) sc ); // device_printf(sc->tws_dev, "Controller Reset complete!\n"); tws_send_event(sc, TWS_RESET_COMPLETE); mtx_unlock(&sc->gen_lock); xpt_release_simq(sc->sim, 1); tws_setup_intr(sc, sc->irqs); }
static void tws_timeout(void *arg) { struct tws_request *req = (struct tws_request *)arg; struct tws_softc *sc = req->sc; if ( tws_get_state(sc) != TWS_RESET ) { device_printf(sc->tws_dev, "Request timed out.\n"); tws_reset(sc); } }
void tws_intr(void *arg) { struct tws_softc *sc = (struct tws_softc *)arg; u_int32_t histat=0, db=0; if (!(sc)) { device_printf(sc->tws_dev, "null softc!!!\n"); return; } if ( tws_get_state(sc) == TWS_RESET ) { return; } if ( tws_get_state(sc) != TWS_ONLINE ) { return; } sc->stats.num_intrs++; histat = tws_read_reg(sc, TWS_I2O0_HISTAT, 4); if ( histat & TWS_BIT2 ) { TWS_TRACE_DEBUG(sc, "door bell :)", histat, TWS_I2O0_HISTAT); db = tws_read_reg(sc, TWS_I2O0_IOBDB, 4); if ( db & TWS_BIT21 ) { tws_intr_attn_error(sc); return; } if ( db & TWS_BIT18 ) { tws_intr_attn_aen(sc); } } if ( histat & TWS_BIT3 ) { tws_intr_resp(sc); } }
void tws_timeout(void *arg) { struct tws_request *req = (struct tws_request *)arg; struct tws_softc *sc = req->sc; if ( req->error_code == TWS_REQ_RET_RESET ) { return; } mtx_lock(&sc->gen_lock); if ( req->error_code == TWS_REQ_RET_RESET ) { mtx_unlock(&sc->gen_lock); return; } if ( tws_get_state(sc) == TWS_RESET ) { mtx_unlock(&sc->gen_lock); return; } tws_teardown_intr(sc); xpt_freeze_simq(sc->sim, 1); tws_send_event(sc, TWS_RESET_START); if (req->type == TWS_REQ_TYPE_SCSI_IO) { device_printf(sc->tws_dev, "I/O Request timed out... Resetting controller\n"); } else if (req->type == TWS_REQ_TYPE_PASSTHRU) { device_printf(sc->tws_dev, "IOCTL Request timed out... Resetting controller\n"); } else { device_printf(sc->tws_dev, "Internal Request timed out... Resetting controller\n"); } tws_assert_soft_reset(sc); tws_turn_off_interrupts(sc); tws_reset_cb( (void*) sc ); tws_reinit( (void*) sc ); // device_printf(sc->tws_dev, "Controller Reset complete!\n"); tws_send_event(sc, TWS_RESET_COMPLETE); mtx_unlock(&sc->gen_lock); xpt_release_simq(sc->sim, 1); tws_setup_intr(sc, sc->irqs); }
static void tws_reset_cb(void *arg) { struct tws_softc *sc = (struct tws_softc *)arg; u_int32_t reg; if ( tws_get_state(sc) != TWS_RESET ) { return; } reg = tws_read_reg(sc, TWS_I2O0_SCRPD3, 4); if (!( reg & TWS_BIT13 )) { callout_reset(&sc->reset_cb_handle, hz/10, tws_reset_cb, sc); return; } tws_drain_response_queue(sc); tws_drain_busy_queue(sc); tws_drain_reserved_reqs(sc); callout_reset(&sc->reinit_handle, 5*hz, tws_reinit, sc); }
void tws_reset(void *arg) { struct tws_softc *sc = (struct tws_softc *)arg; if ( tws_get_state(sc) == TWS_RESET ) { return; } device_printf(sc->tws_dev, "Resetting controller\n"); lockmgr(&sc->gen_lock, LK_EXCLUSIVE); tws_send_event(sc, TWS_RESET_START); lockmgr(&sc->gen_lock, LK_RELEASE); tws_turn_off_interrupts(sc); lockmgr(&sc->sim_lock, LK_EXCLUSIVE); tws_freeze_simq(sc); lockmgr(&sc->sim_lock, LK_RELEASE); tws_assert_soft_reset(sc); callout_reset(&sc->reset_cb_handle, hz/10, tws_reset_cb, sc); }
static int tws_passthru(struct tws_softc *sc, void *buf) { struct tws_request *req; struct tws_ioctl_no_data_buf *ubuf = (struct tws_ioctl_no_data_buf *)buf; int error; u_int16_t lun4; if ( tws_get_state(sc) != TWS_ONLINE) { return(EBUSY); } //============================================================================================== // Get a command // do { req = tws_get_request(sc, TWS_REQ_TYPE_PASSTHRU); if ( !req ) { error = tsleep(sc, 0, "tws_sleep", TWS_IOCTL_TIMEOUT*hz); if ( error == EWOULDBLOCK ) { return(ETIMEDOUT); } } else { // Make sure we are still ready for new commands... if ( tws_get_state(sc) != TWS_ONLINE) { return(EBUSY); } break; } } while(1); req->length = (ubuf->driver_pkt.buffer_length + 511) & ~511; TWS_TRACE_DEBUG(sc, "datal,rid", req->length, req->request_id); if ( req->length ) { req->data = sc->ioctl_data_mem; req->dma_map = sc->ioctl_data_map; //========================================================================================== // Copy data in from user space // error = copyin(ubuf->pdata, req->data, req->length); } //============================================================================================== // Set command fields // req->flags = TWS_DIR_IN | TWS_DIR_OUT; req->cb = tws_passthru_complete; memcpy(&req->cmd_pkt->cmd, &ubuf->cmd_pkt.cmd, sizeof(struct tws_command_apache)); if ( GET_OPCODE(req->cmd_pkt->cmd.pkt_a.res__opcode) == TWS_FW_CMD_EXECUTE_SCSI ) { lun4 = req->cmd_pkt->cmd.pkt_a.lun_l4__req_id & 0xF000; req->cmd_pkt->cmd.pkt_a.lun_l4__req_id = lun4 | req->request_id; } else { req->cmd_pkt->cmd.pkt_g.generic.request_id = (u_int8_t) req->request_id; } //============================================================================================== // Send command to controller // error = tws_map_request(sc, req); if (error) { ubuf->driver_pkt.os_status = error; goto out_data; } if ( req->state == TWS_REQ_STATE_COMPLETE ) { ubuf->driver_pkt.os_status = req->error_code; goto out_unmap; } mtx_lock(&sc->gen_lock); error = mtx_sleep(req, &sc->gen_lock, 0, "tws_passthru", TWS_IOCTL_TIMEOUT*hz); mtx_unlock(&sc->gen_lock); if (( req->state != TWS_REQ_STATE_COMPLETE ) && ( error == EWOULDBLOCK )) { TWS_TRACE_DEBUG(sc, "msleep timeout", error, req->request_id); tws_timeout((void*) req); } out_unmap: if ( req->error_code == TWS_REQ_RET_RESET ) { error = EBUSY; req->error_code = EBUSY; TWS_TRACE_DEBUG(sc, "ioctl reset", error, req->request_id); } tws_unmap_request(sc, req); //============================================================================================== // Return command status to user space // memcpy(&ubuf->cmd_pkt.hdr, &req->cmd_pkt->hdr, sizeof(struct tws_command_apache)); memcpy(&ubuf->cmd_pkt.cmd, &req->cmd_pkt->cmd, sizeof(struct tws_command_apache)); out_data: if ( req->length ) { //========================================================================================== // Copy data out to user space // if ( !error ) error = copyout(req->data, ubuf->pdata, ubuf->driver_pkt.buffer_length); } if ( error ) TWS_TRACE_DEBUG(sc, "errored", error, 0); if ( req->error_code != TWS_REQ_RET_SUBMIT_SUCCESS ) ubuf->driver_pkt.os_status = error; //============================================================================================== // Free command // req->state = TWS_REQ_STATE_FREE; wakeup_one(sc); return(error); }
static int tws_passthru(struct tws_softc *sc, void *buf) { struct tws_request *req; struct tws_ioctl_no_data_buf *ubuf = (struct tws_ioctl_no_data_buf *)buf; int error; u_int16_t lun4; if ( tws_get_state(sc) == TWS_RESET ) { return(EBUSY); } do { req = tws_get_request(sc, TWS_PASSTHRU_REQ); if ( !req ) { sc->chan = 1; error = tsleep((void *)&sc->chan, 0, "tws_sleep", TWS_IO_TIMEOUT*hz); if ( error == EWOULDBLOCK ) { return(ETIMEDOUT); } } else { break; } }while(1); req->length = ubuf->driver_pkt.buffer_length; TWS_TRACE_DEBUG(sc, "datal,rid", req->length, req->request_id); if ( req->length ) { req->data = kmalloc(req->length, M_TWS, M_WAITOK | M_ZERO); error = copyin(ubuf->pdata, req->data, req->length); } req->flags = TWS_DIR_IN | TWS_DIR_OUT; req->cb = tws_passthru_complete; memcpy(&req->cmd_pkt->cmd, &ubuf->cmd_pkt.cmd, sizeof(struct tws_command_apache)); if ( GET_OPCODE(req->cmd_pkt->cmd.pkt_a.res__opcode) == TWS_FW_CMD_EXECUTE_SCSI ) { lun4 = req->cmd_pkt->cmd.pkt_a.lun_l4__req_id & 0xF000; req->cmd_pkt->cmd.pkt_a.lun_l4__req_id = lun4 | req->request_id; } else { req->cmd_pkt->cmd.pkt_g.generic.request_id = (u_int8_t) req->request_id; } lockmgr(&sc->gen_lock, LK_EXCLUSIVE); req->error_code = tws_map_request(sc, req); error = lksleep(req, &sc->gen_lock, 0, "tws_passthru", TWS_IO_TIMEOUT*hz); if ( error == EWOULDBLOCK ) { error = ETIMEDOUT; TWS_TRACE_DEBUG(sc, "lksleep timeout", error, req->request_id); tws_reset((void *)sc); } if ( req->error_code == TWS_REQ_REQUEUE ) { error = EBUSY; } tws_unmap_request(sc, req); memcpy(&ubuf->cmd_pkt.hdr, &req->cmd_pkt->hdr, sizeof(struct tws_command_apache)); memcpy(&ubuf->cmd_pkt.cmd, &req->cmd_pkt->cmd, sizeof(struct tws_command_apache)); if ( !error && req->length ) { error = copyout(req->data, ubuf->pdata, req->length); } kfree(req->data, M_TWS); req->state = TWS_REQ_STATE_FREE; lockmgr(&sc->gen_lock, LK_RELEASE); if ( error ) TWS_TRACE_DEBUG(sc, "errored", error, 0); if ( req->error_code != TWS_REQ_SUBMIT_SUCCESS ) ubuf->driver_pkt.os_status = error; if ( sc->chan && tws_get_state(sc) != TWS_RESET ) { sc->chan = 0; wakeup((void *)&sc->chan); } return(error); }