int tws_ioctl(struct cdev *dev, u_long cmd, caddr_t buf, int flags, d_thread_t *proc) { struct tws_softc *sc = (struct tws_softc *)(dev->si_drv1); int error; TWS_TRACE_DEBUG(sc, "entry", sc, cmd); sc->stats.ioctls++; switch(cmd) { case TWS_IOCTL_FIRMWARE_PASS_THROUGH : error = tws_passthru(sc, (void *)buf); break; case TWS_IOCTL_SCAN_BUS : TWS_TRACE_DEBUG(sc, "scan-bus", 0, 0); error = tws_bus_scan(sc); break; default : TWS_TRACE_DEBUG(sc, "ioctl-aen", cmd, buf); error = tws_ioctl_aen(sc, cmd, (void *)buf); break; } return(error); }
int tws_init_ctlr(struct tws_softc *sc) { u_int64_t reg; u_int32_t regh, regl; TWS_TRACE_DEBUG(sc, "entry", sc, sc->is64bit); sc->obfl_q_overrun = false; if ( tws_init_connect(sc, tws_queue_depth) ) { TWS_TRACE_DEBUG(sc, "initConnect failed", 0, sc->is64bit); return(FAILURE); } while( 1 ) { regh = tws_read_reg(sc, TWS_I2O0_IOPOBQPH, 4); regl = tws_read_reg(sc, TWS_I2O0_IOPOBQPL, 4); reg = (((u_int64_t)regh) << 32) | regl; TWS_TRACE_DEBUG(sc, "host outbound cleanup",reg, regl); if ( regh == TWS_FIFO_EMPTY32 ) break; } tws_init_obfl_q(sc); tws_display_ctlr_info(sc); tws_write_reg(sc, TWS_I2O0_HOBDBC, ~0, 4); tws_turn_on_interrupts(sc); return(SUCCESS); }
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; } }
int tws_send_generic_cmd(struct tws_softc *sc, u_int8_t opcode) { struct tws_request *req; struct tws_cmd_generic *cmd; TWS_TRACE_DEBUG(sc, "entry", sc, opcode); req = tws_get_request(sc, TWS_REQ_TYPE_INTERNAL_CMD); if ( req == NULL ) { TWS_TRACE_DEBUG(sc, "no requests", 0, 0); return(FAILURE); } cmd = &(req->cmd_pkt->cmd.pkt_g.generic); bzero(cmd, sizeof(struct tws_cmd_generic)); /* req->cmd_pkt->hdr.header_desc.size_header = 128; */ req->cb = tws_cmd_complete; cmd->sgl_off__opcode = BUILD_RES__OPCODE(0, opcode); cmd->size = 2; cmd->request_id = req->request_id; cmd->host_id__unit = 0; cmd->status = 0; cmd->flags = 0; cmd->count = 0; req->error_code = tws_submit_command(sc, req); return(SUCCESS); }
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); } }
int tws_ioctl(struct dev_ioctl_args *ap) { cdev_t dev = ap->a_head.a_dev; u_long cmd = ap->a_cmd; caddr_t buf = ap->a_data; struct tws_softc *sc = (struct tws_softc *)(dev->si_drv1); int error; TWS_TRACE_DEBUG(sc, "entry", sc, cmd); sc->stats.ioctls++; switch(cmd) { case TWS_IOCTL_FIRMWARE_PASS_THROUGH : error = tws_passthru(sc, (void *)buf); break; case TWS_IOCTL_SCAN_BUS : TWS_TRACE_DEBUG(sc, "scan-bus", 0, 0); lockmgr(&sc->sim_lock, LK_EXCLUSIVE); error = tws_bus_scan(sc); lockmgr(&sc->sim_lock, LK_RELEASE); break; default : TWS_TRACE_DEBUG(sc, "ioctl-aen", cmd, buf); error = tws_ioctl_aen(sc, cmd, (void *)buf); break; } return(error); }
void tws_init_obfl_q(struct tws_softc *sc) { int i=0; u_int64_t paddr; u_int32_t paddrh, paddrl, status; TWS_TRACE_DEBUG(sc, "entry", 0, sc->obfl_q_overrun); while ( i < tws_queue_depth ) { if ( !sc->sense_bufs[i].posted ) { paddr = sc->sense_bufs[i].hdr_pkt_phy; paddrh = (u_int32_t)( paddr>>32); paddrl = (u_int32_t) paddr; tws_write_reg(sc, TWS_I2O0_HOBQPH, paddrh, 4); tws_write_reg(sc, TWS_I2O0_HOBQPL, paddrl, 4); status = tws_read_reg(sc, TWS_I2O0_STATUS, 4); if ( status & TWS_BIT13 ) { TWS_TRACE_DEBUG(sc, "OBFL Overrun", status, TWS_I2O0_STATUS); sc->obfl_q_overrun = true; break; } sc->sense_bufs[i].posted = true; } i++; }
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); } }
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); } }
static void tws_err_complete(struct tws_softc *sc, u_int64_t mfa) { struct tws_command_header *hdr; struct tws_sense *sen; struct tws_request *req; u_int16_t req_id; u_int32_t reg, status; if ( !mfa ) { TWS_TRACE_DEBUG(sc, "null mfa", 0, mfa); return; } else { /* lookup the sense */ sen = tws_find_sense_from_mfa(sc, mfa); if ( sen == NULL ) { TWS_TRACE_DEBUG(sc, "found null req", 0, mfa); return; } hdr = sen->hdr; TWS_TRACE_DEBUG(sc, "sen, hdr", sen, hdr); req_id = hdr->header_desc.request_id; req = &sc->reqs[req_id]; TWS_TRACE_DEBUG(sc, "req, id", req, req_id); if ( req->error_code != TWS_REQ_RET_SUBMIT_SUCCESS ) TWS_TRACE_DEBUG(sc, "submit failure?", 0, req->error_code); } switch (req->type) { case TWS_REQ_TYPE_PASSTHRU : tws_passthru_err_complete(req, hdr); break; case TWS_REQ_TYPE_GETSET_PARAM : tws_getset_param_complete(req); break; case TWS_REQ_TYPE_SCSI_IO : tws_scsi_err_complete(req, hdr); break; } mtx_lock(&sc->io_lock); hdr->header_desc.size_header = 128; reg = (u_int32_t)( mfa>>32); tws_write_reg(sc, TWS_I2O0_HOBQPH, reg, 4); reg = (u_int32_t)(mfa); tws_write_reg(sc, TWS_I2O0_HOBQPL, reg, 4); status = tws_read_reg(sc, TWS_I2O0_STATUS, 4); if ( status & TWS_BIT13 ) { device_printf(sc->tws_dev, "OBFL Overrun\n"); sc->obfl_q_overrun = true; } mtx_unlock(&sc->io_lock); }
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); }
void tws_fetch_aen(void *arg) { struct tws_softc *sc = (struct tws_softc *)arg; int error = 0; TWS_TRACE_DEBUG(sc, "entry", 0, 0); if ((error = tws_send_scsi_cmd(sc, 0x03 /* REQUEST_SENSE */))) { TWS_TRACE_DEBUG(sc, "aen fetch send in progress", 0, 0); } }
static void tws_poll(struct cam_sim *sim) { struct tws_softc *sc = (struct tws_softc *)cam_sim_softc(sim); TWS_TRACE_DEBUG(sc, "entry", 0, 0); tws_intr((void *) sc); }
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); }
void tws_intr(void *arg) { struct tws_softc *sc = (struct tws_softc *)arg; u_int32_t histat=0, db=0; KASSERT(sc, ("null softc")); 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); } }
int tws_bus_scan(struct tws_softc *sc) { struct cam_path *path; union ccb *ccb; TWS_TRACE_DEBUG(sc, "entry", sc, 0); KASSERT(sc->sim, ("sim not allocated")); KKASSERT(lockstatus(&sc->sim_lock, curthread) != 0); ccb = sc->scan_ccb; if (xpt_create_path(&path, xpt_periph, cam_sim_path(sc->sim), CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { /* lockmgr(&sc->sim_lock, LK_RELEASE); */ return(EIO); } xpt_setup_ccb(&ccb->ccb_h, path, 5); ccb->ccb_h.func_code = XPT_SCAN_BUS; ccb->ccb_h.cbfcnp = tws_bus_scan_cb; ccb->crcn.flags = CAM_FLAG_NONE; xpt_action(ccb); return(0); }
void tws_aen_synctime_with_host(struct tws_softc *sc) { int error; long int sync_time; TWS_TRACE_DEBUG(sc, "entry", sc, 0); sync_time = (TWS_LOCAL_TIME - (3 * 86400)) % 604800; TWS_TRACE_DEBUG(sc, "sync_time,ts", sync_time, time_second); TWS_TRACE_DEBUG(sc, "utc_offset", utc_offset(), 0); error = tws_set_param(sc, TWS_PARAM_TIME_TABLE, TWS_PARAM_TIME_SCHED_TIME, 4, &sync_time); if ( error ) TWS_TRACE_DEBUG(sc, "set param failed", sync_time, error); }
static void tws_passthru_err_complete(struct tws_request *req, struct tws_command_header *hdr) { TWS_TRACE_DEBUG(req->sc, "entry", hdr, req->request_id); req->error_code = hdr->status_block.error; memcpy(&(req->cmd_pkt->hdr), hdr, sizeof(struct tws_command_header)); tws_passthru_complete(req); }
/* * Device suspend routine. */ static int tws_suspend(device_t dev) { struct tws_softc *sc = device_get_softc(dev); if ( sc ) TWS_TRACE_DEBUG(sc, "entry", 0, 0); return (0); }
int tws_write(struct cdev *dev, struct uio *uio, int ioflag) { struct tws_softc *sc = dev->si_drv1; if ( sc ) TWS_TRACE_DEBUG(sc, "entry", dev, ioflag); return (0); }
int tws_close(struct cdev *dev, int fflag, int devtype, d_thread_t *td) { struct tws_softc *sc = dev->si_drv1; if ( sc ) TWS_TRACE_DEBUG(sc, "entry", dev, fflag); return (0); }
int tws_open(struct cdev *dev, int oflags, int devtype, d_thread_t *td) { struct tws_softc *sc = dev->si_drv1; if ( sc ) TWS_TRACE_DEBUG(sc, "entry", dev, oflags); return (0); }
void tws_turn_off_interrupts(struct tws_softc *sc) { TWS_TRACE_DEBUG(sc, "entry", 0, 0); tws_write_reg(sc, TWS_I2O0_HIMASK, ~0, 4); }
void tws_turn_on_interrupts(struct tws_softc *sc) { TWS_TRACE_DEBUG(sc, "entry", 0, 0); /* turn on responce and db interrupt only */ tws_write_reg(sc, TWS_I2O0_HIMASK, TWS_BIT0, 4); }
int tws_write(struct dev_write_args *ap) { cdev_t dev = ap->a_head.a_dev; struct tws_softc *sc = dev->si_drv1; if ( sc ) TWS_TRACE_DEBUG(sc, "entry", dev, ioflag); return (0); }
void tws_assert_soft_reset(struct tws_softc *sc) { u_int32_t reg; reg = tws_read_reg(sc, TWS_I2O0_HIBDB, 4); TWS_TRACE_DEBUG(sc, "in bound door bell read ", reg, TWS_I2O0_HIBDB); tws_write_reg(sc, TWS_I2O0_HIBDB, reg | TWS_BIT8, 4); }
void tws_enable_db_intr(struct tws_softc *sc) { u_int32_t reg; TWS_TRACE_DEBUG(sc, "entry", 0, 0); reg = tws_read_reg(sc, TWS_I2O0_HIMASK, 4); reg = reg & ~TWS_BIT2; tws_write_reg(sc, TWS_I2O0_HIMASK, reg, 4); }
void tws_release_request(struct tws_request *req) { struct tws_softc *sc = req->sc; TWS_TRACE_DEBUG(sc, "entry", sc, 0); lockmgr(&sc->q_lock, LK_EXCLUSIVE); tws_q_insert_tail(sc, req, TWS_FREE_Q); lockmgr(&sc->q_lock, LK_RELEASE); }
void tws_release_request(struct tws_request *req) { struct tws_softc *sc = req->sc; TWS_TRACE_DEBUG(sc, "entry", sc, 0); mtx_lock(&sc->q_lock); tws_q_insert_tail(sc, req, TWS_FREE_Q); mtx_unlock(&sc->q_lock); }
u_int16_t tws_poll4_response(struct tws_softc *sc, u_int64_t *mfa) { u_int16_t req_id; time_t endt; endt = TWS_LOCAL_TIME + TWS_POLL_TIMEOUT; do { if(tws_get_response(sc, &req_id, mfa)) { if ( req_id == TWS_INVALID_REQID ) { TWS_TRACE_DEBUG(sc, "invalid req_id", 0, req_id); return(TWS_INVALID_REQID); } return(req_id); } } while (TWS_LOCAL_TIME <= endt); TWS_TRACE_DEBUG(sc, "poll timeout", 0, 0); return(TWS_INVALID_REQID); }