예제 #1
0
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");
}
예제 #2
0
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);
}
예제 #3
0
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);
    }
}
예제 #4
0
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);
    }
}
예제 #5
0
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);
}
예제 #6
0
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);
}
예제 #7
0
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);
}
예제 #8
0
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);
}
예제 #9
0
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);
}