예제 #1
0
static void
tws_drain_reserved_reqs(struct tws_softc *sc)
{
    struct tws_request *r;

    r = &sc->reqs[TWS_REQ_TYPE_AEN_FETCH];
    if ( r->state != TWS_REQ_STATE_FREE ) {
        TWS_TRACE_DEBUG(sc, "reset aen req", 0, 0);
        untimeout(tws_timeout, r, r->thandle);
        tws_unmap_request(sc, r);
        free(r->data, M_TWS);
        r->state = TWS_REQ_STATE_FREE;
        r->error_code = TWS_REQ_RET_RESET;
    } 

    r = &sc->reqs[TWS_REQ_TYPE_PASSTHRU];
    if ( r->state == TWS_REQ_STATE_BUSY ) {
        TWS_TRACE_DEBUG(sc, "reset passthru req", 0, 0);
        r->error_code = TWS_REQ_RET_RESET;
    } 

    r = &sc->reqs[TWS_REQ_TYPE_GETSET_PARAM];
    if ( r->state != TWS_REQ_STATE_FREE ) {
        TWS_TRACE_DEBUG(sc, "reset setparam req", 0, 0);
        untimeout(tws_timeout, r, r->thandle);
        tws_unmap_request(sc, r);
        free(r->data, M_TWS);
        r->state = TWS_REQ_STATE_FREE;
        r->error_code = TWS_REQ_RET_RESET;
    } 
}
예제 #2
0
int
tws_get_param(struct tws_softc *sc, u_int32_t table_id, u_int32_t param_id,
              u_int32_t param_size, void *data)
{
    struct tws_request *req;
    struct tws_command_packet *cmd_pkt;
    union tws_command_giga *cmd;
    struct tws_getset_param *param;
    u_int16_t reqid;
    u_int64_t mfa;
    int error = SUCCESS;


    req = tws_get_request(sc, TWS_REQ_TYPE_GETSET_PARAM);
    if ( req == NULL ) {
        TWS_TRACE_DEBUG(sc, "null req", 0, 0);
        return(FAILURE);
    }

    req->length = TWS_SECTOR_SIZE;
    req->data = malloc(TWS_SECTOR_SIZE, M_TWS, M_NOWAIT);
    if ( req->data == NULL )
        return(FAILURE);
    bzero(req->data, TWS_SECTOR_SIZE);
    param = (struct tws_getset_param *)req->data;

    req->cb = NULL;
    req->flags = TWS_DIR_IN;
    cmd_pkt = req->cmd_pkt;

    cmd = &cmd_pkt->cmd.pkt_g;
    cmd->param.sgl_off__opcode =
            BUILD_SGL_OFF__OPCODE(2, TWS_FW_CMD_GET_PARAM);
    cmd->param.request_id = (u_int8_t)req->request_id;
    cmd->param.host_id__unit = 0;
    cmd->param.param_count = 1;
    cmd->param.size = 2; /* map routine will add sgls */

    /* Specify which parameter we want to set. */
    param->table_id = (table_id | TWS_9K_PARAM_DESCRIPTOR);
    param->parameter_id = (u_int8_t)(param_id);
    param->parameter_size_bytes = (u_int16_t)param_size;
   
    error = tws_map_request(sc, req);
    if (!error) {
        reqid = tws_poll4_response(sc, &mfa);
        tws_unmap_request(sc, req);

        if ( reqid == TWS_REQ_TYPE_GETSET_PARAM ) {
            memcpy(data, param->data, param_size);
        } else {
            error = FAILURE;
        }
    }
  
    free(req->data, M_TWS);
    req->state = TWS_REQ_STATE_FREE;
    return(error);

}
예제 #3
0
static void
tws_drain_busy_queue(struct tws_softc *sc)
{
    struct tws_request *req;
    union ccb          *ccb;
    TWS_TRACE_DEBUG(sc, "entry", 0, 0);

    mtx_lock(&sc->q_lock);
    req = tws_q_remove_tail(sc, TWS_BUSY_Q);
    mtx_unlock(&sc->q_lock);
    while ( req ) {
        TWS_TRACE_DEBUG(sc, "moved to TWS_COMPLETE_Q", 0, req->request_id);
        untimeout(tws_timeout, req, req->ccb_ptr->ccb_h.timeout_ch);

        req->error_code = TWS_REQ_RET_RESET;
        ccb = (union ccb *)(req->ccb_ptr);

        ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
        ccb->ccb_h.status |=  CAM_REQUEUE_REQ;
        ccb->ccb_h.status |=  CAM_SCSI_BUS_RESET;

        tws_unmap_request(req->sc, req);

        mtx_lock(&sc->sim_lock);
        xpt_done(req->ccb_ptr);
        mtx_unlock(&sc->sim_lock);

        mtx_lock(&sc->q_lock);
        tws_q_insert_tail(sc, req, TWS_FREE_Q);
        req = tws_q_remove_tail(sc, TWS_BUSY_Q);
        mtx_unlock(&sc->q_lock);
    } 
}
예제 #4
0
static void
tws_drain_reserved_reqs(struct tws_softc *sc)
{

    struct tws_request *r;

    r = &sc->reqs[1];
    if ( r->state != TWS_REQ_STATE_FREE ) {
        TWS_TRACE_DEBUG(sc, "drained aen req", 0, 0);
	callout_stop(&r->thandle);
        tws_unmap_request(sc, r);
        kfree(r->data, M_TWS);
        lockmgr(&sc->gen_lock, LK_EXCLUSIVE);
        r->state = TWS_REQ_STATE_FREE;
        lockmgr(&sc->gen_lock, LK_RELEASE);
    }
    r = &sc->reqs[2];
    if ( r->state != TWS_REQ_STATE_FREE ) {
        TWS_TRACE_DEBUG(sc, "drained passthru req", 0, 0);
        r->error_code = TWS_REQ_REQUEUE;
        tws_passthru_complete(r);
    }
    r = &sc->reqs[3];
    if ( r->state != TWS_REQ_STATE_FREE ) {
        TWS_TRACE_DEBUG(sc, "drained set param req", 0, 0);
        tws_getset_param_complete(r);
    }

}
예제 #5
0
static void
tws_drain_busy_queue(struct tws_softc *sc)
{

    struct tws_request *req;
    TWS_TRACE_DEBUG(sc, "entry", 0, 0);

    lockmgr(&sc->q_lock, LK_EXCLUSIVE);
    req = tws_q_remove_tail(sc, TWS_BUSY_Q);
    lockmgr(&sc->q_lock, LK_RELEASE);
    while ( req ) {
	callout_stop(req->ccb_ptr->ccb_h.timeout_ch);
        tws_unmap_request(req->sc, req);

        TWS_TRACE_DEBUG(sc, "drained", 0, req->request_id);

        lockmgr(&sc->sim_lock, LK_EXCLUSIVE);
        req->ccb_ptr->ccb_h.status = CAM_REQUEUE_REQ;
        xpt_done(req->ccb_ptr);
        lockmgr(&sc->sim_lock, LK_RELEASE);

        lockmgr(&sc->q_lock, LK_EXCLUSIVE);
        tws_q_insert_tail(sc, req, TWS_FREE_Q);
        req = tws_q_remove_tail(sc, TWS_BUSY_Q);
        lockmgr(&sc->q_lock, LK_RELEASE);
    }

}
예제 #6
0
void
tws_cmd_complete(struct tws_request *req)
{
    struct tws_softc *sc = req->sc;

    untimeout(tws_timeout, req, req->ccb_ptr->ccb_h.timeout_ch);
    tws_unmap_request(sc, req);
}
예제 #7
0
void
tws_cmd_complete(struct tws_request *req)
{
    struct tws_softc *sc = req->sc;

    callout_stop(req->ccb_ptr->ccb_h.timeout_ch);
    tws_unmap_request(sc, req);

}
예제 #8
0
static void
tws_scsi_err_complete(struct tws_request *req, struct tws_command_header *hdr)
{
    u_int8_t *sense_data;
    struct tws_softc *sc = req->sc;
    union ccb *ccb = req->ccb_ptr;

    TWS_TRACE_DEBUG(sc, "sbe, cmd_status", hdr->status_block.error,
                                 req->cmd_pkt->cmd.pkt_a.status);
    if ( hdr->status_block.error == TWS_ERROR_LOGICAL_UNIT_NOT_SUPPORTED ||
         hdr->status_block.error == TWS_ERROR_UNIT_OFFLINE ) {

        if ( ccb->ccb_h.target_lun ) {
            TWS_TRACE_DEBUG(sc, "invalid lun error",0,0);
            ccb->ccb_h.status |= CAM_LUN_INVALID;
        } else {
            TWS_TRACE_DEBUG(sc, "invalid target error",0,0);
            ccb->ccb_h.status |= CAM_TID_INVALID;
        }

    } else {
        TWS_TRACE_DEBUG(sc, "scsi status  error",0,0);
        ccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR;
        if (((ccb->csio.cdb_io.cdb_bytes[0] == 0x1A) &&
              (hdr->status_block.error == TWS_ERROR_NOT_SUPPORTED))) {
            ccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR | CAM_AUTOSNS_VALID;
            TWS_TRACE_DEBUG(sc, "page mode not supported",0,0);
        }
    }

    /* if there were no error simply mark complete error */
    if (ccb->ccb_h.status == 0)
        ccb->ccb_h.status = CAM_REQ_CMP_ERR;

    sense_data = (u_int8_t *)&ccb->csio.sense_data;
    if (sense_data) {
        memcpy(sense_data, hdr->sense_data, TWS_SENSE_DATA_LENGTH );
        ccb->csio.sense_len = TWS_SENSE_DATA_LENGTH;
        ccb->ccb_h.status |= CAM_AUTOSNS_VALID;
    }
    ccb->csio.scsi_status = req->cmd_pkt->cmd.pkt_a.status;

    ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
    lockmgr(&sc->sim_lock, LK_EXCLUSIVE);
    xpt_done(ccb);
    lockmgr(&sc->sim_lock, LK_RELEASE);

    callout_stop(req->ccb_ptr->ccb_h.timeout_ch);
    tws_unmap_request(req->sc, req);
    lockmgr(&sc->q_lock, LK_EXCLUSIVE);
    tws_q_remove_request(sc, req, TWS_BUSY_Q);
    tws_q_insert_tail(sc, req, TWS_FREE_Q);
    lockmgr(&sc->q_lock, LK_RELEASE);

}
예제 #9
0
void
tws_getset_param_complete(struct tws_request *req)
{
    struct tws_softc *sc = req->sc;

    TWS_TRACE_DEBUG(sc, "getset complete", req, req->request_id);

    untimeout(tws_timeout, req, req->thandle);
    tws_unmap_request(sc, req);

    free(req->data, M_TWS);

    req->state = TWS_REQ_STATE_FREE;
}
예제 #10
0
void
tws_getset_param_complete(struct tws_request *req)
{
    struct tws_softc *sc = req->sc;

    TWS_TRACE_DEBUG(sc, "getset complete", req, req->request_id);

    callout_stop(&req->thandle);
    tws_unmap_request(sc, req);

    kfree(req->data, M_TWS);

    lockmgr(&sc->gen_lock, LK_EXCLUSIVE);
    req->state = TWS_REQ_STATE_FREE;
    lockmgr(&sc->gen_lock, LK_RELEASE);

}
예제 #11
0
static void
tws_scsi_complete(struct tws_request *req)
{
    struct tws_softc *sc = req->sc;

    mtx_lock(&sc->q_lock);
    tws_q_remove_request(sc, req, TWS_BUSY_Q);
    mtx_unlock(&sc->q_lock);

    untimeout(tws_timeout, req, req->ccb_ptr->ccb_h.timeout_ch);
    tws_unmap_request(req->sc, req);


    req->ccb_ptr->ccb_h.status = CAM_REQ_CMP;
    mtx_lock(&sc->sim_lock);
    xpt_done(req->ccb_ptr);
    mtx_unlock(&sc->sim_lock);

    mtx_lock(&sc->q_lock);
    tws_q_insert_tail(sc, req, TWS_FREE_Q);
    mtx_unlock(&sc->q_lock);
}
예제 #12
0
static void
tws_scsi_complete(struct tws_request *req)
{
    struct tws_softc *sc = req->sc;

    lockmgr(&sc->q_lock, LK_EXCLUSIVE);
    tws_q_remove_request(sc, req, TWS_BUSY_Q);
    lockmgr(&sc->q_lock, LK_RELEASE);

    callout_stop(req->ccb_ptr->ccb_h.timeout_ch);
    tws_unmap_request(req->sc, req);


    lockmgr(&sc->sim_lock, LK_EXCLUSIVE);
    req->ccb_ptr->ccb_h.status = CAM_REQ_CMP;
    xpt_done(req->ccb_ptr);
    lockmgr(&sc->sim_lock, LK_RELEASE);

    lockmgr(&sc->q_lock, LK_EXCLUSIVE);
    tws_q_insert_tail(sc, req, TWS_FREE_Q);
    lockmgr(&sc->q_lock, LK_RELEASE);

}
예제 #13
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);
}
예제 #14
0
void
tws_aen_complete(struct tws_request *req)
{
    struct tws_softc *sc = req->sc;
    struct tws_command_header *sense;
    struct tws_event_packet event;
    u_int16_t aen_code=0;

    TWS_TRACE_DEBUG(sc, "aen complete", 0, req->request_id);

    untimeout(tws_timeout, req, req->thandle);
    tws_unmap_request(sc, req);

    sense = (struct tws_command_header *)req->data;

    TWS_TRACE_DEBUG(sc,"sense code, key",sense->sense_data[0], 
                                   sense->sense_data[2]);
    TWS_TRACE_DEBUG(sc,"sense rid, seve",sense->header_desc.request_id, 
                                   sense->status_block.res__severity);
    TWS_TRACE_DEBUG(sc,"sense srcnum, error",sense->status_block.srcnum, 
                                   sense->status_block.error);
    TWS_TRACE_DEBUG(sc,"sense shdr, ssense",sense->header_desc.size_header, 
                                   sense->header_desc.size_sense);

    aen_code = sense->status_block.error;

    switch ( aen_code ) {
        case TWS_AEN_SYNC_TIME_WITH_HOST :
            tws_aen_synctime_with_host(sc);
            break;
        case TWS_AEN_QUEUE_EMPTY :
            break;
        default :
            bzero(&event, sizeof(struct tws_event_packet));
            event.sequence_id = sc->seq_id;
            event.time_stamp_sec = (u_int32_t)TWS_LOCAL_TIME;
            event.aen_code = sense->status_block.error;
            event.severity = sense->status_block.res__severity & 0x7;
            event.event_src = TWS_SRC_CTRL_EVENT;
            strcpy(event.severity_str, tws_sev_str[event.severity]);
            event.retrieved = TWS_AEN_NOT_RETRIEVED;

            bcopy(sense->err_specific_desc, event.parameter_data, 
                                    TWS_ERROR_SPECIFIC_DESC_LEN);
            event.parameter_data[TWS_ERROR_SPECIFIC_DESC_LEN - 1] = '\0';
            event.parameter_len = (u_int8_t)strlen(event.parameter_data)+1;

            if ( event.parameter_len < TWS_ERROR_SPECIFIC_DESC_LEN ) {
                event.parameter_len += ((u_int8_t)strlen(event.parameter_data +
                                                event.parameter_len) + 1);
            }

            device_printf(sc->tws_dev, "%s: (0x%02X: 0x%04X): %s: %s\n",
                event.severity_str,
                event.event_src,
                event.aen_code,
                event.parameter_data + 
                     (strlen(event.parameter_data) + 1), 
                event.parameter_data);

            mtx_lock(&sc->gen_lock);
            tws_circular_aenq_insert(sc, &sc->aen_q, &event);
            sc->seq_id++;
            mtx_unlock(&sc->gen_lock);
            break;

    }
    
    free(req->data, M_TWS);

    req->state = TWS_REQ_STATE_FREE;

    if ( aen_code != TWS_AEN_QUEUE_EMPTY ) {
        /* timeout(tws_fetch_aen, sc, 1);*/
        sc->stats.num_aens++;
        tws_fetch_aen((void *)sc);
    } 
}
예제 #15
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);
}