133190b70SSascha Wildner /*
233190b70SSascha Wildner * Copyright (c) 2010, LSI Corp.
333190b70SSascha Wildner * All rights reserved.
433190b70SSascha Wildner * Author : Manjunath Ranganathaiah
533190b70SSascha Wildner * Support: freebsdraid@lsi.com
633190b70SSascha Wildner *
733190b70SSascha Wildner * Redistribution and use in source and binary forms, with or without
833190b70SSascha Wildner * modification, are permitted provided that the following conditions
933190b70SSascha Wildner * are met:
1033190b70SSascha Wildner *
1133190b70SSascha Wildner * 1. Redistributions of source code must retain the above copyright
1233190b70SSascha Wildner * notice, this list of conditions and the following disclaimer.
1333190b70SSascha Wildner * 2. Redistributions in binary form must reproduce the above copyright
1433190b70SSascha Wildner * notice, this list of conditions and the following disclaimer in
1533190b70SSascha Wildner * the documentation and/or other materials provided with the
1633190b70SSascha Wildner * distribution.
1733190b70SSascha Wildner * 3. Neither the name of the <ORGANIZATION> nor the names of its
1833190b70SSascha Wildner * contributors may be used to endorse or promote products derived
1933190b70SSascha Wildner * from this software without specific prior written permission.
2033190b70SSascha Wildner *
2133190b70SSascha Wildner * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2233190b70SSascha Wildner * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2333190b70SSascha Wildner * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
2433190b70SSascha Wildner * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
2533190b70SSascha Wildner * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
2633190b70SSascha Wildner * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
2733190b70SSascha Wildner * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2833190b70SSascha Wildner * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
2933190b70SSascha Wildner * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3033190b70SSascha Wildner * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
3133190b70SSascha Wildner * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3233190b70SSascha Wildner * POSSIBILITY OF SUCH DAMAGE.
3333190b70SSascha Wildner *
3433190b70SSascha Wildner * $FreeBSD: src/sys/dev/tws/tws_cam.c,v 1.3 2007/05/09 04:16:32 mrangana Exp $
3533190b70SSascha Wildner */
3633190b70SSascha Wildner
3733190b70SSascha Wildner #include <dev/raid/tws/tws.h>
3833190b70SSascha Wildner #include <dev/raid/tws/tws_services.h>
3933190b70SSascha Wildner #include <dev/raid/tws/tws_hdm.h>
4033190b70SSascha Wildner #include <dev/raid/tws/tws_user.h>
4133190b70SSascha Wildner #include <bus/cam/cam.h>
4233190b70SSascha Wildner #include <bus/cam/cam_ccb.h>
4333190b70SSascha Wildner #include <bus/cam/cam_sim.h>
4433190b70SSascha Wildner #include <bus/cam/cam_xpt_sim.h>
4533190b70SSascha Wildner #include <bus/cam/cam_debug.h>
4633190b70SSascha Wildner #include <bus/cam/cam_periph.h>
4733190b70SSascha Wildner
4833190b70SSascha Wildner #include <bus/cam/scsi/scsi_all.h>
4933190b70SSascha Wildner #include <bus/cam/scsi/scsi_message.h>
5033190b70SSascha Wildner
5133190b70SSascha Wildner static int tws_cam_depth=(TWS_MAX_REQS - TWS_RESERVED_REQS);
5233190b70SSascha Wildner static char tws_sev_str[5][8]={"","ERROR","WARNING","INFO","DEBUG"};
5333190b70SSascha Wildner
5433190b70SSascha Wildner static void tws_action(struct cam_sim *sim, union ccb *ccb);
5533190b70SSascha Wildner static void tws_poll(struct cam_sim *sim);
5633190b70SSascha Wildner static void tws_bus_scan_cb(struct cam_periph *periph, union ccb *ccb);
5733190b70SSascha Wildner static void tws_scsi_complete(struct tws_request *req);
5833190b70SSascha Wildner
5933190b70SSascha Wildner
6033190b70SSascha Wildner
6133190b70SSascha Wildner void tws_unmap_request(struct tws_softc *sc, struct tws_request *req);
6233190b70SSascha Wildner int32_t tws_map_request(struct tws_softc *sc, struct tws_request *req);
6333190b70SSascha Wildner int tws_bus_scan(struct tws_softc *sc);
6433190b70SSascha Wildner int tws_cam_attach(struct tws_softc *sc);
6533190b70SSascha Wildner void tws_cam_detach(struct tws_softc *sc);
6633190b70SSascha Wildner void tws_reset(void *arg);
6733190b70SSascha Wildner
6833190b70SSascha Wildner static void tws_reset_cb(void *arg);
6933190b70SSascha Wildner static void tws_reinit(void *arg);
7033190b70SSascha Wildner static int32_t tws_execute_scsi(struct tws_softc *sc, union ccb *ccb);
7133190b70SSascha Wildner static void tws_freeze_simq(struct tws_softc *sc);
7233190b70SSascha Wildner static void tws_release_simq(struct tws_softc *sc);
7333190b70SSascha Wildner static void tws_dmamap_data_load_cbfn(void *arg, bus_dma_segment_t *segs,
7433190b70SSascha Wildner int nseg, int error);
7533190b70SSascha Wildner static void tws_fill_sg_list(struct tws_softc *sc, void *sgl_src,
7633190b70SSascha Wildner void *sgl_dest, u_int16_t num_sgl_entries);
7733190b70SSascha Wildner static void tws_err_complete(struct tws_softc *sc, u_int64_t mfa);
7833190b70SSascha Wildner static void tws_scsi_err_complete(struct tws_request *req,
7933190b70SSascha Wildner struct tws_command_header *hdr);
8033190b70SSascha Wildner static void tws_passthru_err_complete(struct tws_request *req,
8133190b70SSascha Wildner struct tws_command_header *hdr);
8233190b70SSascha Wildner
8333190b70SSascha Wildner
8433190b70SSascha Wildner static void tws_timeout(void *arg);
8533190b70SSascha Wildner static void tws_intr_attn_aen(struct tws_softc *sc);
8633190b70SSascha Wildner static void tws_intr_attn_error(struct tws_softc *sc);
8733190b70SSascha Wildner static void tws_intr_resp(struct tws_softc *sc);
8833190b70SSascha Wildner void tws_intr(void *arg);
8933190b70SSascha Wildner void tws_cmd_complete(struct tws_request *req);
9033190b70SSascha Wildner void tws_aen_complete(struct tws_request *req);
9133190b70SSascha Wildner int tws_send_scsi_cmd(struct tws_softc *sc, int cmd);
9233190b70SSascha Wildner void tws_getset_param_complete(struct tws_request *req);
9333190b70SSascha Wildner int tws_set_param(struct tws_softc *sc, u_int32_t table_id, u_int32_t param_id,
9433190b70SSascha Wildner u_int32_t param_size, void *data);
9533190b70SSascha Wildner int tws_get_param(struct tws_softc *sc, u_int32_t table_id, u_int32_t param_id,
9633190b70SSascha Wildner u_int32_t param_size, void *data);
9733190b70SSascha Wildner
9833190b70SSascha Wildner
9933190b70SSascha Wildner extern struct tws_request *tws_get_request(struct tws_softc *sc,
10033190b70SSascha Wildner u_int16_t type);
10133190b70SSascha Wildner extern void *tws_release_request(struct tws_request *req);
10233190b70SSascha Wildner extern int tws_submit_command(struct tws_softc *sc, struct tws_request *req);
10333190b70SSascha Wildner extern boolean tws_get_response(struct tws_softc *sc,
10433190b70SSascha Wildner u_int16_t *req_id, u_int64_t *mfa);
10533190b70SSascha Wildner extern void tws_q_insert_tail(struct tws_softc *sc, struct tws_request *req,
10633190b70SSascha Wildner u_int8_t q_type );
10733190b70SSascha Wildner extern struct tws_request * tws_q_remove_request(struct tws_softc *sc,
10833190b70SSascha Wildner struct tws_request *req, u_int8_t q_type );
10933190b70SSascha Wildner extern void tws_send_event(struct tws_softc *sc, u_int8_t event);
11033190b70SSascha Wildner
11133190b70SSascha Wildner extern struct tws_sense *
11233190b70SSascha Wildner tws_find_sense_from_mfa(struct tws_softc *sc, u_int64_t mfa);
11333190b70SSascha Wildner
11433190b70SSascha Wildner extern void tws_fetch_aen(void *arg);
11533190b70SSascha Wildner extern void tws_disable_db_intr(struct tws_softc *sc);
11633190b70SSascha Wildner extern void tws_enable_db_intr(struct tws_softc *sc);
11733190b70SSascha Wildner extern void tws_passthru_complete(struct tws_request *req);
11833190b70SSascha Wildner extern void tws_aen_synctime_with_host(struct tws_softc *sc);
11933190b70SSascha Wildner extern void tws_circular_aenq_insert(struct tws_softc *sc,
12033190b70SSascha Wildner struct tws_circular_q *cq, struct tws_event_packet *aen);
12133190b70SSascha Wildner extern int tws_use_32bit_sgls;
12233190b70SSascha Wildner extern boolean tws_ctlr_reset(struct tws_softc *sc);
12333190b70SSascha Wildner extern struct tws_request * tws_q_remove_tail(struct tws_softc *sc,
12433190b70SSascha Wildner u_int8_t q_type );
12533190b70SSascha Wildner extern void tws_turn_off_interrupts(struct tws_softc *sc);
12633190b70SSascha Wildner extern void tws_turn_on_interrupts(struct tws_softc *sc);
12733190b70SSascha Wildner extern int tws_init_connect(struct tws_softc *sc, u_int16_t mc);
12833190b70SSascha Wildner extern void tws_init_obfl_q(struct tws_softc *sc);
12933190b70SSascha Wildner extern uint8_t tws_get_state(struct tws_softc *sc);
13033190b70SSascha Wildner extern void tws_assert_soft_reset(struct tws_softc *sc);
13133190b70SSascha Wildner extern boolean tws_ctlr_ready(struct tws_softc *sc);
13233190b70SSascha Wildner extern u_int16_t tws_poll4_response(struct tws_softc *sc, u_int64_t *mfa);
13333190b70SSascha Wildner
13433190b70SSascha Wildner
13533190b70SSascha Wildner
13633190b70SSascha Wildner int
tws_cam_attach(struct tws_softc * sc)13733190b70SSascha Wildner tws_cam_attach(struct tws_softc *sc)
13833190b70SSascha Wildner {
13933190b70SSascha Wildner struct cam_devq *devq;
14033190b70SSascha Wildner int error;
14133190b70SSascha Wildner
14233190b70SSascha Wildner TWS_TRACE_DEBUG(sc, "entry", 0, sc);
14333190b70SSascha Wildner /* Create a device queue for sim */
14433190b70SSascha Wildner
14533190b70SSascha Wildner /*
14633190b70SSascha Wildner * if the user sets cam depth to less than 1
14733190b70SSascha Wildner * cam may get confused
14833190b70SSascha Wildner */
14933190b70SSascha Wildner if ( tws_cam_depth < 1 )
15033190b70SSascha Wildner tws_cam_depth = 1;
15133190b70SSascha Wildner if ( tws_cam_depth > (tws_queue_depth - TWS_RESERVED_REQS) )
15233190b70SSascha Wildner tws_cam_depth = tws_queue_depth - TWS_RESERVED_REQS;
15333190b70SSascha Wildner
15433190b70SSascha Wildner TWS_TRACE_DEBUG(sc, "depths,ctlr,cam", tws_queue_depth, tws_cam_depth);
15533190b70SSascha Wildner
15633190b70SSascha Wildner if ((devq = cam_simq_alloc(tws_cam_depth)) == NULL) {
15733190b70SSascha Wildner tws_log(sc, CAM_SIMQ_ALLOC);
15833190b70SSascha Wildner return(ENOMEM);
15933190b70SSascha Wildner }
16033190b70SSascha Wildner
16133190b70SSascha Wildner /*
16233190b70SSascha Wildner * Create a SIM entry. Though we can support tws_cam_depth
16333190b70SSascha Wildner * simultaneous requests, we claim to be able to handle only
16433190b70SSascha Wildner * (tws_cam_depth), so that we always have reserved requests
16533190b70SSascha Wildner * packet available to service ioctls and internal commands.
16633190b70SSascha Wildner */
16733190b70SSascha Wildner sc->sim = cam_sim_alloc(tws_action, tws_poll, "tws", sc,
16833190b70SSascha Wildner device_get_unit(sc->tws_dev),
16933190b70SSascha Wildner &sc->sim_lock,
17033190b70SSascha Wildner tws_cam_depth, 1, devq);
17133190b70SSascha Wildner /* 1, 1, devq); */
17233190b70SSascha Wildner cam_simq_release(devq);
17333190b70SSascha Wildner if (sc->sim == NULL) {
17433190b70SSascha Wildner tws_log(sc, CAM_SIM_ALLOC);
17533190b70SSascha Wildner }
17633190b70SSascha Wildner /* Register the bus. */
17733190b70SSascha Wildner lockmgr(&sc->sim_lock, LK_EXCLUSIVE);
17833190b70SSascha Wildner if (xpt_bus_register(sc->sim, 0) != CAM_SUCCESS) {
17933190b70SSascha Wildner cam_sim_free(sc->sim);
18033190b70SSascha Wildner sc->sim = NULL; /* so cam_detach will not try to free it */
18133190b70SSascha Wildner lockmgr(&sc->sim_lock, LK_RELEASE);
18233190b70SSascha Wildner tws_log(sc, TWS_XPT_BUS_REGISTER);
18333190b70SSascha Wildner return(ENXIO);
18433190b70SSascha Wildner }
18533190b70SSascha Wildner if (xpt_create_path(&sc->path, NULL, cam_sim_path(sc->sim),
18633190b70SSascha Wildner CAM_TARGET_WILDCARD,
18733190b70SSascha Wildner CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
18833190b70SSascha Wildner xpt_bus_deregister(cam_sim_path(sc->sim));
18933190b70SSascha Wildner cam_sim_free(sc->sim);
19033190b70SSascha Wildner tws_log(sc, TWS_XPT_CREATE_PATH);
19133190b70SSascha Wildner lockmgr(&sc->sim_lock, LK_RELEASE);
19233190b70SSascha Wildner return(ENXIO);
19333190b70SSascha Wildner }
19433190b70SSascha Wildner if ((error = tws_bus_scan(sc))) {
19533190b70SSascha Wildner tws_log(sc, TWS_BUS_SCAN_REQ);
19633190b70SSascha Wildner lockmgr(&sc->sim_lock, LK_RELEASE);
19733190b70SSascha Wildner return(error);
19833190b70SSascha Wildner }
19933190b70SSascha Wildner lockmgr(&sc->sim_lock, LK_RELEASE);
20033190b70SSascha Wildner
20133190b70SSascha Wildner return(0);
20233190b70SSascha Wildner }
20333190b70SSascha Wildner
20433190b70SSascha Wildner void
tws_cam_detach(struct tws_softc * sc)20533190b70SSascha Wildner tws_cam_detach(struct tws_softc *sc)
20633190b70SSascha Wildner {
20733190b70SSascha Wildner TWS_TRACE_DEBUG(sc, "entry", 0, 0);
20833190b70SSascha Wildner lockmgr(&sc->sim_lock, LK_EXCLUSIVE);
20933190b70SSascha Wildner if (sc->path)
21033190b70SSascha Wildner xpt_free_path(sc->path);
21133190b70SSascha Wildner if (sc->sim) {
21233190b70SSascha Wildner xpt_bus_deregister(cam_sim_path(sc->sim));
21333190b70SSascha Wildner cam_sim_free(sc->sim);
21433190b70SSascha Wildner }
21533190b70SSascha Wildner lockmgr(&sc->sim_lock, LK_RELEASE);
21633190b70SSascha Wildner }
21733190b70SSascha Wildner
21833190b70SSascha Wildner int
tws_bus_scan(struct tws_softc * sc)21933190b70SSascha Wildner tws_bus_scan(struct tws_softc *sc)
22033190b70SSascha Wildner {
22133190b70SSascha Wildner struct cam_path *path;
22233190b70SSascha Wildner union ccb *ccb;
22333190b70SSascha Wildner
22433190b70SSascha Wildner TWS_TRACE_DEBUG(sc, "entry", sc, 0);
22533190b70SSascha Wildner KASSERT(sc->sim, ("sim not allocated"));
22633190b70SSascha Wildner KKASSERT(lockstatus(&sc->sim_lock, curthread) != 0);
22733190b70SSascha Wildner
22833190b70SSascha Wildner ccb = sc->scan_ccb;
22933190b70SSascha Wildner
23033190b70SSascha Wildner if (xpt_create_path(&path, xpt_periph, cam_sim_path(sc->sim),
23133190b70SSascha Wildner CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
23233190b70SSascha Wildner /* lockmgr(&sc->sim_lock, LK_RELEASE); */
23333190b70SSascha Wildner return(EIO);
23433190b70SSascha Wildner }
23533190b70SSascha Wildner xpt_setup_ccb(&ccb->ccb_h, path, 5);
23633190b70SSascha Wildner ccb->ccb_h.func_code = XPT_SCAN_BUS;
23733190b70SSascha Wildner ccb->ccb_h.cbfcnp = tws_bus_scan_cb;
23833190b70SSascha Wildner ccb->crcn.flags = CAM_FLAG_NONE;
23933190b70SSascha Wildner xpt_action(ccb);
24033190b70SSascha Wildner
24133190b70SSascha Wildner return(0);
24233190b70SSascha Wildner }
24333190b70SSascha Wildner
24433190b70SSascha Wildner static void
tws_bus_scan_cb(struct cam_periph * periph,union ccb * ccb)24533190b70SSascha Wildner tws_bus_scan_cb(struct cam_periph *periph, union ccb *ccb)
24633190b70SSascha Wildner {
24733190b70SSascha Wildner struct tws_softc *sc = periph->softc;
24833190b70SSascha Wildner
24933190b70SSascha Wildner /* calling trace results in non-sleepable lock head panic
25033190b70SSascha Wildner using printf to debug */
25133190b70SSascha Wildner
25233190b70SSascha Wildner if (ccb->ccb_h.status != CAM_REQ_CMP) {
25333190b70SSascha Wildner kprintf("cam_scan failure\n");
25433190b70SSascha Wildner
25533190b70SSascha Wildner lockmgr(&sc->gen_lock, LK_EXCLUSIVE);
25633190b70SSascha Wildner tws_send_event(sc, TWS_SCAN_FAILURE);
25733190b70SSascha Wildner lockmgr(&sc->gen_lock, LK_RELEASE);
25833190b70SSascha Wildner }
25933190b70SSascha Wildner
26033190b70SSascha Wildner xpt_free_path(ccb->ccb_h.path);
26133190b70SSascha Wildner }
26233190b70SSascha Wildner
26333190b70SSascha Wildner static void
tws_action(struct cam_sim * sim,union ccb * ccb)26433190b70SSascha Wildner tws_action(struct cam_sim *sim, union ccb *ccb)
26533190b70SSascha Wildner {
26633190b70SSascha Wildner struct tws_softc *sc = (struct tws_softc *)cam_sim_softc(sim);
26733190b70SSascha Wildner
26833190b70SSascha Wildner switch( ccb->ccb_h.func_code ) {
26933190b70SSascha Wildner case XPT_SCSI_IO:
27033190b70SSascha Wildner {
27133190b70SSascha Wildner if ( tws_execute_scsi(sc, ccb) )
27233190b70SSascha Wildner TWS_TRACE_DEBUG(sc, "execute scsi failed", 0, 0);
27333190b70SSascha Wildner break;
27433190b70SSascha Wildner }
27533190b70SSascha Wildner case XPT_ABORT:
27633190b70SSascha Wildner {
27733190b70SSascha Wildner TWS_TRACE_DEBUG(sc, "abort i/o", 0, 0);
27833190b70SSascha Wildner ccb->ccb_h.status = CAM_UA_ABORT;
27933190b70SSascha Wildner xpt_done(ccb);
28033190b70SSascha Wildner break;
28133190b70SSascha Wildner }
28233190b70SSascha Wildner case XPT_RESET_BUS:
28333190b70SSascha Wildner {
28433190b70SSascha Wildner TWS_TRACE_DEBUG(sc, "reset bus", sim, ccb);
28533190b70SSascha Wildner break;
28633190b70SSascha Wildner }
28733190b70SSascha Wildner case XPT_SET_TRAN_SETTINGS:
28833190b70SSascha Wildner {
28933190b70SSascha Wildner TWS_TRACE_DEBUG(sc, "set tran settings", sim, ccb);
29033190b70SSascha Wildner ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
29133190b70SSascha Wildner xpt_done(ccb);
29233190b70SSascha Wildner
29333190b70SSascha Wildner break;
29433190b70SSascha Wildner }
29533190b70SSascha Wildner case XPT_GET_TRAN_SETTINGS:
29633190b70SSascha Wildner {
29733190b70SSascha Wildner TWS_TRACE_DEBUG(sc, "get tran settings", sim, ccb);
29833190b70SSascha Wildner
29933190b70SSascha Wildner ccb->cts.protocol = PROTO_SCSI;
30033190b70SSascha Wildner ccb->cts.protocol_version = SCSI_REV_2;
30133190b70SSascha Wildner ccb->cts.transport = XPORT_SPI;
30233190b70SSascha Wildner ccb->cts.transport_version = 2;
30333190b70SSascha Wildner
30433190b70SSascha Wildner ccb->cts.xport_specific.spi.valid = CTS_SPI_VALID_DISC;
30533190b70SSascha Wildner ccb->cts.xport_specific.spi.flags = CTS_SPI_FLAGS_DISC_ENB;
30633190b70SSascha Wildner ccb->cts.proto_specific.scsi.valid = CTS_SCSI_VALID_TQ;
30733190b70SSascha Wildner ccb->cts.proto_specific.scsi.flags = CTS_SCSI_FLAGS_TAG_ENB;
30833190b70SSascha Wildner ccb->ccb_h.status = CAM_REQ_CMP;
30933190b70SSascha Wildner xpt_done(ccb);
31033190b70SSascha Wildner
31133190b70SSascha Wildner break;
31233190b70SSascha Wildner }
31333190b70SSascha Wildner case XPT_CALC_GEOMETRY:
31433190b70SSascha Wildner {
31533190b70SSascha Wildner TWS_TRACE_DEBUG(sc, "calc geometry(ccb,block-size)", ccb,
31633190b70SSascha Wildner ccb->ccg.block_size);
31733190b70SSascha Wildner cam_calc_geometry(&ccb->ccg, 1/* extended */);
31833190b70SSascha Wildner xpt_done(ccb);
31933190b70SSascha Wildner
32033190b70SSascha Wildner break;
32133190b70SSascha Wildner }
32233190b70SSascha Wildner case XPT_PATH_INQ:
32333190b70SSascha Wildner {
32433190b70SSascha Wildner TWS_TRACE_DEBUG(sc, "path inquiry", sim, ccb);
32533190b70SSascha Wildner ccb->cpi.version_num = 1;
32633190b70SSascha Wildner ccb->cpi.hba_inquiry = 0;
32733190b70SSascha Wildner ccb->cpi.target_sprt = 0;
32833190b70SSascha Wildner ccb->cpi.hba_misc = 0;
32933190b70SSascha Wildner ccb->cpi.hba_eng_cnt = 0;
33033190b70SSascha Wildner ccb->cpi.max_target = TWS_MAX_NUM_UNITS;
33133190b70SSascha Wildner ccb->cpi.max_lun = TWS_MAX_NUM_LUNS - 1;
33233190b70SSascha Wildner ccb->cpi.unit_number = cam_sim_unit(sim);
33333190b70SSascha Wildner ccb->cpi.bus_id = cam_sim_bus(sim);
33433190b70SSascha Wildner ccb->cpi.initiator_id = TWS_SCSI_INITIATOR_ID;
33533190b70SSascha Wildner ccb->cpi.base_transfer_speed = 300000;
33633190b70SSascha Wildner strncpy(ccb->cpi.sim_vid, "FreeBSD", SIM_IDLEN);
33733190b70SSascha Wildner strncpy(ccb->cpi.hba_vid, "3ware", HBA_IDLEN);
33833190b70SSascha Wildner strncpy(ccb->cpi.dev_name, cam_sim_name(sim), DEV_IDLEN);
33933190b70SSascha Wildner ccb->cpi.transport = XPORT_SPI;
34033190b70SSascha Wildner ccb->cpi.transport_version = 2;
34133190b70SSascha Wildner ccb->cpi.protocol = PROTO_SCSI;
34233190b70SSascha Wildner ccb->cpi.protocol_version = SCSI_REV_2;
34333190b70SSascha Wildner ccb->ccb_h.status = CAM_REQ_CMP;
34433190b70SSascha Wildner xpt_done(ccb);
34533190b70SSascha Wildner
34633190b70SSascha Wildner break;
34733190b70SSascha Wildner }
34833190b70SSascha Wildner default:
34933190b70SSascha Wildner TWS_TRACE_DEBUG(sc, "default", sim, ccb);
35033190b70SSascha Wildner ccb->ccb_h.status = CAM_REQ_INVALID;
35133190b70SSascha Wildner xpt_done(ccb);
35233190b70SSascha Wildner break;
35333190b70SSascha Wildner }
35433190b70SSascha Wildner }
35533190b70SSascha Wildner
35633190b70SSascha Wildner static void
tws_scsi_complete(struct tws_request * req)35733190b70SSascha Wildner tws_scsi_complete(struct tws_request *req)
35833190b70SSascha Wildner {
35933190b70SSascha Wildner struct tws_softc *sc = req->sc;
36033190b70SSascha Wildner
36133190b70SSascha Wildner lockmgr(&sc->q_lock, LK_EXCLUSIVE);
36233190b70SSascha Wildner tws_q_remove_request(sc, req, TWS_BUSY_Q);
36333190b70SSascha Wildner lockmgr(&sc->q_lock, LK_RELEASE);
36433190b70SSascha Wildner
365*cec957e9SMatthew Dillon callout_stop(req->ccb_ptr->ccb_h.timeout_ch);
36633190b70SSascha Wildner tws_unmap_request(req->sc, req);
36733190b70SSascha Wildner
36833190b70SSascha Wildner
36933190b70SSascha Wildner lockmgr(&sc->sim_lock, LK_EXCLUSIVE);
37033190b70SSascha Wildner req->ccb_ptr->ccb_h.status = CAM_REQ_CMP;
37133190b70SSascha Wildner xpt_done(req->ccb_ptr);
37233190b70SSascha Wildner lockmgr(&sc->sim_lock, LK_RELEASE);
37333190b70SSascha Wildner
37433190b70SSascha Wildner lockmgr(&sc->q_lock, LK_EXCLUSIVE);
37533190b70SSascha Wildner tws_q_insert_tail(sc, req, TWS_FREE_Q);
37633190b70SSascha Wildner lockmgr(&sc->q_lock, LK_RELEASE);
37733190b70SSascha Wildner
37833190b70SSascha Wildner }
37933190b70SSascha Wildner
38033190b70SSascha Wildner void
tws_getset_param_complete(struct tws_request * req)38133190b70SSascha Wildner tws_getset_param_complete(struct tws_request *req)
38233190b70SSascha Wildner {
38333190b70SSascha Wildner struct tws_softc *sc = req->sc;
38433190b70SSascha Wildner
38533190b70SSascha Wildner TWS_TRACE_DEBUG(sc, "getset complete", req, req->request_id);
38633190b70SSascha Wildner
38733190b70SSascha Wildner callout_stop(&req->thandle);
38833190b70SSascha Wildner tws_unmap_request(sc, req);
38933190b70SSascha Wildner
39033190b70SSascha Wildner kfree(req->data, M_TWS);
39133190b70SSascha Wildner
39233190b70SSascha Wildner lockmgr(&sc->gen_lock, LK_EXCLUSIVE);
39333190b70SSascha Wildner req->state = TWS_REQ_STATE_FREE;
39433190b70SSascha Wildner lockmgr(&sc->gen_lock, LK_RELEASE);
39533190b70SSascha Wildner
39633190b70SSascha Wildner }
39733190b70SSascha Wildner
39833190b70SSascha Wildner void
tws_aen_complete(struct tws_request * req)39933190b70SSascha Wildner tws_aen_complete(struct tws_request *req)
40033190b70SSascha Wildner {
40133190b70SSascha Wildner struct tws_softc *sc = req->sc;
40233190b70SSascha Wildner struct tws_command_header *sense;
40333190b70SSascha Wildner struct tws_event_packet event;
40433190b70SSascha Wildner u_int16_t aen_code=0;
40533190b70SSascha Wildner
40633190b70SSascha Wildner TWS_TRACE_DEBUG(sc, "aen complete", 0, req->request_id);
40733190b70SSascha Wildner
40833190b70SSascha Wildner callout_stop(&req->thandle);
40933190b70SSascha Wildner tws_unmap_request(sc, req);
41033190b70SSascha Wildner
41133190b70SSascha Wildner sense = (struct tws_command_header *)req->data;
41233190b70SSascha Wildner
41333190b70SSascha Wildner TWS_TRACE_DEBUG(sc,"sense code, key",sense->sense_data[0],
41433190b70SSascha Wildner sense->sense_data[2]);
41533190b70SSascha Wildner TWS_TRACE_DEBUG(sc,"sense rid, seve",sense->header_desc.request_id,
41633190b70SSascha Wildner sense->status_block.res__severity);
41733190b70SSascha Wildner TWS_TRACE_DEBUG(sc,"sense srcnum, error",sense->status_block.srcnum,
41833190b70SSascha Wildner sense->status_block.error);
41933190b70SSascha Wildner TWS_TRACE_DEBUG(sc,"sense shdr, ssense",sense->header_desc.size_header,
42033190b70SSascha Wildner sense->header_desc.size_sense);
42133190b70SSascha Wildner
42233190b70SSascha Wildner aen_code = sense->status_block.error;
42333190b70SSascha Wildner
42433190b70SSascha Wildner switch ( aen_code ) {
42533190b70SSascha Wildner case TWS_AEN_SYNC_TIME_WITH_HOST :
42633190b70SSascha Wildner tws_aen_synctime_with_host(sc);
42733190b70SSascha Wildner break;
42833190b70SSascha Wildner case TWS_AEN_QUEUE_EMPTY :
42933190b70SSascha Wildner break;
43033190b70SSascha Wildner default :
43133190b70SSascha Wildner bzero(&event, sizeof(struct tws_event_packet));
43233190b70SSascha Wildner event.sequence_id = sc->seq_id;
43333190b70SSascha Wildner event.time_stamp_sec = (u_int32_t)TWS_LOCAL_TIME;
43433190b70SSascha Wildner event.aen_code = sense->status_block.error;
43533190b70SSascha Wildner event.severity = sense->status_block.res__severity & 0x7;
43633190b70SSascha Wildner event.event_src = TWS_SRC_CTRL_EVENT;
43733190b70SSascha Wildner strcpy(event.severity_str, tws_sev_str[event.severity]);
43833190b70SSascha Wildner event.retrieved = TWS_AEN_NOT_RETRIEVED;
43933190b70SSascha Wildner
44033190b70SSascha Wildner bcopy(sense->err_specific_desc, event.parameter_data,
44133190b70SSascha Wildner TWS_ERROR_SPECIFIC_DESC_LEN);
44233190b70SSascha Wildner event.parameter_data[TWS_ERROR_SPECIFIC_DESC_LEN - 1] = '\0';
44333190b70SSascha Wildner event.parameter_len = (u_int8_t)strlen(event.parameter_data)+1;
44433190b70SSascha Wildner
44533190b70SSascha Wildner if ( event.parameter_len < TWS_ERROR_SPECIFIC_DESC_LEN ) {
44633190b70SSascha Wildner event.parameter_len += ((u_int8_t)strlen(event.parameter_data +
44733190b70SSascha Wildner event.parameter_len) + 1);
44833190b70SSascha Wildner }
44933190b70SSascha Wildner
45033190b70SSascha Wildner device_printf(sc->tws_dev, "%s: (0x%02X: 0x%04X): %s: %s\n",
45133190b70SSascha Wildner event.severity_str,
45233190b70SSascha Wildner event.event_src,
45333190b70SSascha Wildner event.aen_code,
45433190b70SSascha Wildner event.parameter_data +
45533190b70SSascha Wildner (strlen(event.parameter_data) + 1),
45633190b70SSascha Wildner event.parameter_data);
45733190b70SSascha Wildner
45833190b70SSascha Wildner lockmgr(&sc->gen_lock, LK_EXCLUSIVE);
45933190b70SSascha Wildner tws_circular_aenq_insert(sc, &sc->aen_q, &event);
46033190b70SSascha Wildner sc->seq_id++;
46133190b70SSascha Wildner lockmgr(&sc->gen_lock, LK_RELEASE);
46233190b70SSascha Wildner break;
46333190b70SSascha Wildner
46433190b70SSascha Wildner }
46533190b70SSascha Wildner
46633190b70SSascha Wildner kfree(req->data, M_TWS);
46733190b70SSascha Wildner
46833190b70SSascha Wildner lockmgr(&sc->gen_lock, LK_EXCLUSIVE);
46933190b70SSascha Wildner req->state = TWS_REQ_STATE_FREE;
47033190b70SSascha Wildner lockmgr(&sc->gen_lock, LK_RELEASE);
47133190b70SSascha Wildner
47233190b70SSascha Wildner if ( aen_code != TWS_AEN_QUEUE_EMPTY ) {
47333190b70SSascha Wildner /* timeout(tws_fetch_aen, sc, 1);*/
47433190b70SSascha Wildner sc->stats.num_aens++;
4754e1af74fSSascha Wildner tws_fetch_aen(sc);
47633190b70SSascha Wildner }
47733190b70SSascha Wildner
47833190b70SSascha Wildner }
47933190b70SSascha Wildner
48033190b70SSascha Wildner void
tws_cmd_complete(struct tws_request * req)48133190b70SSascha Wildner tws_cmd_complete(struct tws_request *req)
48233190b70SSascha Wildner {
48333190b70SSascha Wildner struct tws_softc *sc = req->sc;
48433190b70SSascha Wildner
485*cec957e9SMatthew Dillon callout_stop(req->ccb_ptr->ccb_h.timeout_ch);
48633190b70SSascha Wildner tws_unmap_request(sc, req);
48733190b70SSascha Wildner
48833190b70SSascha Wildner }
48933190b70SSascha Wildner
49033190b70SSascha Wildner static void
tws_err_complete(struct tws_softc * sc,u_int64_t mfa)49133190b70SSascha Wildner tws_err_complete(struct tws_softc *sc, u_int64_t mfa)
49233190b70SSascha Wildner {
49333190b70SSascha Wildner
49433190b70SSascha Wildner struct tws_command_header *hdr;
49533190b70SSascha Wildner struct tws_sense *sen;
49633190b70SSascha Wildner struct tws_request *req;
49733190b70SSascha Wildner u_int16_t req_id;
49833190b70SSascha Wildner u_int32_t reg, status;
49933190b70SSascha Wildner
50033190b70SSascha Wildner if ( !mfa ) {
50133190b70SSascha Wildner TWS_TRACE_DEBUG(sc, "null mfa", 0, mfa);
50233190b70SSascha Wildner return;
50333190b70SSascha Wildner } else {
50433190b70SSascha Wildner /* lookup the sense */
50533190b70SSascha Wildner sen = tws_find_sense_from_mfa(sc, mfa);
50633190b70SSascha Wildner if ( sen == NULL ) {
50733190b70SSascha Wildner TWS_TRACE_DEBUG(sc, "found null req", 0, mfa);
50833190b70SSascha Wildner return;
50933190b70SSascha Wildner }
51033190b70SSascha Wildner hdr = sen->hdr;
51133190b70SSascha Wildner TWS_TRACE_DEBUG(sc, "sen, hdr", sen, hdr);
51233190b70SSascha Wildner req_id = hdr->header_desc.request_id;
51333190b70SSascha Wildner req = &sc->reqs[req_id];
51433190b70SSascha Wildner TWS_TRACE_DEBUG(sc, "req, id", req, req_id);
51533190b70SSascha Wildner if ( req->error_code != TWS_REQ_SUBMIT_SUCCESS )
51633190b70SSascha Wildner TWS_TRACE_DEBUG(sc, "submit failure?", 0, req->error_code);
51733190b70SSascha Wildner }
51833190b70SSascha Wildner
51933190b70SSascha Wildner switch (req->type) {
52033190b70SSascha Wildner case TWS_PASSTHRU_REQ :
52133190b70SSascha Wildner tws_passthru_err_complete(req, hdr);
52233190b70SSascha Wildner break;
52333190b70SSascha Wildner case TWS_GETSET_PARAM_REQ :
52433190b70SSascha Wildner tws_getset_param_complete(req);
52533190b70SSascha Wildner break;
52633190b70SSascha Wildner case TWS_SCSI_IO_REQ :
52733190b70SSascha Wildner tws_scsi_err_complete(req, hdr);
52833190b70SSascha Wildner break;
52933190b70SSascha Wildner
53033190b70SSascha Wildner }
53133190b70SSascha Wildner
53233190b70SSascha Wildner lockmgr(&sc->io_lock, LK_EXCLUSIVE);
53333190b70SSascha Wildner hdr->header_desc.size_header = 128;
53433190b70SSascha Wildner reg = (u_int32_t)( mfa>>32);
53533190b70SSascha Wildner tws_write_reg(sc, TWS_I2O0_HOBQPH, reg, 4);
53633190b70SSascha Wildner reg = (u_int32_t)(mfa);
53733190b70SSascha Wildner tws_write_reg(sc, TWS_I2O0_HOBQPL, reg, 4);
53833190b70SSascha Wildner
53933190b70SSascha Wildner status = tws_read_reg(sc, TWS_I2O0_STATUS, 4);
54033190b70SSascha Wildner if ( status & TWS_BIT13 ) {
54133190b70SSascha Wildner TWS_TRACE_DEBUG(sc, "OBFL Overrun", status, TWS_I2O0_STATUS);
54233190b70SSascha Wildner sc->obfl_q_overrun = true;
54333190b70SSascha Wildner sen->posted = false;
54433190b70SSascha Wildner }
54533190b70SSascha Wildner lockmgr(&sc->io_lock, LK_RELEASE);
54633190b70SSascha Wildner
54733190b70SSascha Wildner }
54833190b70SSascha Wildner
54933190b70SSascha Wildner static void
tws_scsi_err_complete(struct tws_request * req,struct tws_command_header * hdr)55033190b70SSascha Wildner tws_scsi_err_complete(struct tws_request *req, struct tws_command_header *hdr)
55133190b70SSascha Wildner {
55233190b70SSascha Wildner u_int8_t *sense_data;
55333190b70SSascha Wildner struct tws_softc *sc = req->sc;
55433190b70SSascha Wildner union ccb *ccb = req->ccb_ptr;
55533190b70SSascha Wildner
55633190b70SSascha Wildner TWS_TRACE_DEBUG(sc, "sbe, cmd_status", hdr->status_block.error,
55733190b70SSascha Wildner req->cmd_pkt->cmd.pkt_a.status);
55833190b70SSascha Wildner if ( hdr->status_block.error == TWS_ERROR_LOGICAL_UNIT_NOT_SUPPORTED ||
55933190b70SSascha Wildner hdr->status_block.error == TWS_ERROR_UNIT_OFFLINE ) {
56033190b70SSascha Wildner
56133190b70SSascha Wildner if ( ccb->ccb_h.target_lun ) {
56233190b70SSascha Wildner TWS_TRACE_DEBUG(sc, "invalid lun error",0,0);
56333190b70SSascha Wildner ccb->ccb_h.status |= CAM_LUN_INVALID;
56433190b70SSascha Wildner } else {
56533190b70SSascha Wildner TWS_TRACE_DEBUG(sc, "invalid target error",0,0);
56633190b70SSascha Wildner ccb->ccb_h.status |= CAM_TID_INVALID;
56733190b70SSascha Wildner }
56833190b70SSascha Wildner
56933190b70SSascha Wildner } else {
57033190b70SSascha Wildner TWS_TRACE_DEBUG(sc, "scsi status error",0,0);
57133190b70SSascha Wildner ccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR;
57233190b70SSascha Wildner if (((ccb->csio.cdb_io.cdb_bytes[0] == 0x1A) &&
57333190b70SSascha Wildner (hdr->status_block.error == TWS_ERROR_NOT_SUPPORTED))) {
57433190b70SSascha Wildner ccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR | CAM_AUTOSNS_VALID;
57533190b70SSascha Wildner TWS_TRACE_DEBUG(sc, "page mode not supported",0,0);
57633190b70SSascha Wildner }
57733190b70SSascha Wildner }
57833190b70SSascha Wildner
57933190b70SSascha Wildner /* if there were no error simply mark complete error */
58033190b70SSascha Wildner if (ccb->ccb_h.status == 0)
58133190b70SSascha Wildner ccb->ccb_h.status = CAM_REQ_CMP_ERR;
58233190b70SSascha Wildner
58333190b70SSascha Wildner sense_data = (u_int8_t *)&ccb->csio.sense_data;
58433190b70SSascha Wildner if (sense_data) {
58533190b70SSascha Wildner memcpy(sense_data, hdr->sense_data, TWS_SENSE_DATA_LENGTH );
58633190b70SSascha Wildner ccb->csio.sense_len = TWS_SENSE_DATA_LENGTH;
58733190b70SSascha Wildner ccb->ccb_h.status |= CAM_AUTOSNS_VALID;
58833190b70SSascha Wildner }
58933190b70SSascha Wildner ccb->csio.scsi_status = req->cmd_pkt->cmd.pkt_a.status;
59033190b70SSascha Wildner
59133190b70SSascha Wildner ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
59233190b70SSascha Wildner lockmgr(&sc->sim_lock, LK_EXCLUSIVE);
59333190b70SSascha Wildner xpt_done(ccb);
59433190b70SSascha Wildner lockmgr(&sc->sim_lock, LK_RELEASE);
59533190b70SSascha Wildner
596*cec957e9SMatthew Dillon callout_stop(req->ccb_ptr->ccb_h.timeout_ch);
59733190b70SSascha Wildner tws_unmap_request(req->sc, req);
59833190b70SSascha Wildner lockmgr(&sc->q_lock, LK_EXCLUSIVE);
59933190b70SSascha Wildner tws_q_remove_request(sc, req, TWS_BUSY_Q);
60033190b70SSascha Wildner tws_q_insert_tail(sc, req, TWS_FREE_Q);
60133190b70SSascha Wildner lockmgr(&sc->q_lock, LK_RELEASE);
60233190b70SSascha Wildner
60333190b70SSascha Wildner }
60433190b70SSascha Wildner
60533190b70SSascha Wildner static void
tws_passthru_err_complete(struct tws_request * req,struct tws_command_header * hdr)60633190b70SSascha Wildner tws_passthru_err_complete(struct tws_request *req,
60733190b70SSascha Wildner struct tws_command_header *hdr)
60833190b70SSascha Wildner {
60933190b70SSascha Wildner
61033190b70SSascha Wildner TWS_TRACE_DEBUG(req->sc, "entry", hdr, req->request_id);
61133190b70SSascha Wildner req->error_code = hdr->status_block.error;
61233190b70SSascha Wildner memcpy(&(req->cmd_pkt->hdr), hdr, sizeof(struct tws_command_header));
61333190b70SSascha Wildner tws_passthru_complete(req);
61433190b70SSascha Wildner }
61533190b70SSascha Wildner
61633190b70SSascha Wildner static void
tws_drain_busy_queue(struct tws_softc * sc)61733190b70SSascha Wildner tws_drain_busy_queue(struct tws_softc *sc)
61833190b70SSascha Wildner {
61933190b70SSascha Wildner
62033190b70SSascha Wildner struct tws_request *req;
62133190b70SSascha Wildner TWS_TRACE_DEBUG(sc, "entry", 0, 0);
62233190b70SSascha Wildner
62333190b70SSascha Wildner lockmgr(&sc->q_lock, LK_EXCLUSIVE);
62433190b70SSascha Wildner req = tws_q_remove_tail(sc, TWS_BUSY_Q);
62533190b70SSascha Wildner lockmgr(&sc->q_lock, LK_RELEASE);
62633190b70SSascha Wildner while ( req ) {
627*cec957e9SMatthew Dillon callout_stop(req->ccb_ptr->ccb_h.timeout_ch);
62833190b70SSascha Wildner tws_unmap_request(req->sc, req);
62933190b70SSascha Wildner
63033190b70SSascha Wildner TWS_TRACE_DEBUG(sc, "drained", 0, req->request_id);
63133190b70SSascha Wildner
63233190b70SSascha Wildner lockmgr(&sc->sim_lock, LK_EXCLUSIVE);
63333190b70SSascha Wildner req->ccb_ptr->ccb_h.status = CAM_REQUEUE_REQ;
63433190b70SSascha Wildner xpt_done(req->ccb_ptr);
63533190b70SSascha Wildner lockmgr(&sc->sim_lock, LK_RELEASE);
63633190b70SSascha Wildner
63733190b70SSascha Wildner lockmgr(&sc->q_lock, LK_EXCLUSIVE);
63833190b70SSascha Wildner tws_q_insert_tail(sc, req, TWS_FREE_Q);
63933190b70SSascha Wildner req = tws_q_remove_tail(sc, TWS_BUSY_Q);
64033190b70SSascha Wildner lockmgr(&sc->q_lock, LK_RELEASE);
64133190b70SSascha Wildner }
64233190b70SSascha Wildner
64333190b70SSascha Wildner }
64433190b70SSascha Wildner
64533190b70SSascha Wildner static void
tws_drain_reserved_reqs(struct tws_softc * sc)64633190b70SSascha Wildner tws_drain_reserved_reqs(struct tws_softc *sc)
64733190b70SSascha Wildner {
64833190b70SSascha Wildner
64933190b70SSascha Wildner struct tws_request *r;
65033190b70SSascha Wildner
65133190b70SSascha Wildner r = &sc->reqs[1];
65233190b70SSascha Wildner if ( r->state != TWS_REQ_STATE_FREE ) {
65333190b70SSascha Wildner TWS_TRACE_DEBUG(sc, "drained aen req", 0, 0);
65433190b70SSascha Wildner callout_stop(&r->thandle);
65533190b70SSascha Wildner tws_unmap_request(sc, r);
65633190b70SSascha Wildner kfree(r->data, M_TWS);
65733190b70SSascha Wildner lockmgr(&sc->gen_lock, LK_EXCLUSIVE);
65833190b70SSascha Wildner r->state = TWS_REQ_STATE_FREE;
65933190b70SSascha Wildner lockmgr(&sc->gen_lock, LK_RELEASE);
66033190b70SSascha Wildner }
66133190b70SSascha Wildner r = &sc->reqs[2];
66233190b70SSascha Wildner if ( r->state != TWS_REQ_STATE_FREE ) {
66333190b70SSascha Wildner TWS_TRACE_DEBUG(sc, "drained passthru req", 0, 0);
66433190b70SSascha Wildner r->error_code = TWS_REQ_REQUEUE;
66533190b70SSascha Wildner tws_passthru_complete(r);
66633190b70SSascha Wildner }
66733190b70SSascha Wildner r = &sc->reqs[3];
66833190b70SSascha Wildner if ( r->state != TWS_REQ_STATE_FREE ) {
66933190b70SSascha Wildner TWS_TRACE_DEBUG(sc, "drained set param req", 0, 0);
67033190b70SSascha Wildner tws_getset_param_complete(r);
67133190b70SSascha Wildner }
67233190b70SSascha Wildner
67333190b70SSascha Wildner }
67433190b70SSascha Wildner
67533190b70SSascha Wildner static void
tws_drain_response_queue(struct tws_softc * sc)67633190b70SSascha Wildner tws_drain_response_queue(struct tws_softc *sc)
67733190b70SSascha Wildner {
67833190b70SSascha Wildner tws_intr_resp(sc);
67933190b70SSascha Wildner }
68033190b70SSascha Wildner
68133190b70SSascha Wildner
68233190b70SSascha Wildner static int32_t
tws_execute_scsi(struct tws_softc * sc,union ccb * ccb)68333190b70SSascha Wildner tws_execute_scsi(struct tws_softc *sc, union ccb *ccb)
68433190b70SSascha Wildner {
68533190b70SSascha Wildner struct tws_command_packet *cmd_pkt;
68633190b70SSascha Wildner struct tws_request *req;
68733190b70SSascha Wildner struct ccb_hdr *ccb_h = &(ccb->ccb_h);
68833190b70SSascha Wildner struct ccb_scsiio *csio = &(ccb->csio);
68933190b70SSascha Wildner int error;
69033190b70SSascha Wildner u_int16_t lun;
69133190b70SSascha Wildner
69233190b70SSascha Wildner KKASSERT(lockstatus(&sc->sim_lock, curthread) != 0);
69333190b70SSascha Wildner if (ccb_h->target_id >= TWS_MAX_NUM_UNITS) {
69433190b70SSascha Wildner TWS_TRACE_DEBUG(sc, "traget id too big", ccb_h->target_id, ccb_h->target_lun);
69533190b70SSascha Wildner ccb_h->status |= CAM_TID_INVALID;
69633190b70SSascha Wildner xpt_done(ccb);
69733190b70SSascha Wildner return(0);
69833190b70SSascha Wildner }
69933190b70SSascha Wildner if (ccb_h->target_lun >= TWS_MAX_NUM_LUNS) {
70033190b70SSascha Wildner TWS_TRACE_DEBUG(sc, "target lun 2 big", ccb_h->target_id, ccb_h->target_lun);
70133190b70SSascha Wildner ccb_h->status |= CAM_LUN_INVALID;
70233190b70SSascha Wildner xpt_done(ccb);
70333190b70SSascha Wildner return(0);
70433190b70SSascha Wildner }
70533190b70SSascha Wildner
70633190b70SSascha Wildner if(ccb_h->flags & CAM_CDB_PHYS) {
70733190b70SSascha Wildner TWS_TRACE_DEBUG(sc, "cdb phy", ccb_h->target_id, ccb_h->target_lun);
70833190b70SSascha Wildner ccb_h->status = CAM_REQ_CMP_ERR;
70933190b70SSascha Wildner xpt_done(ccb);
71033190b70SSascha Wildner return(0);
71133190b70SSascha Wildner }
71233190b70SSascha Wildner
71333190b70SSascha Wildner /*
71433190b70SSascha Wildner * We are going to work on this request. Mark it as enqueued (though
71533190b70SSascha Wildner * we don't actually queue it...)
71633190b70SSascha Wildner */
71733190b70SSascha Wildner ccb_h->status |= CAM_SIM_QUEUED;
71833190b70SSascha Wildner
71933190b70SSascha Wildner req = tws_get_request(sc, TWS_SCSI_IO_REQ);
72033190b70SSascha Wildner if ( !req ) {
72133190b70SSascha Wildner TWS_TRACE_DEBUG(sc, "no reqs", ccb_h->target_id, ccb_h->target_lun);
72233190b70SSascha Wildner /* tws_freeze_simq(sc); */
72333190b70SSascha Wildner ccb_h->status |= CAM_REQUEUE_REQ;
72433190b70SSascha Wildner xpt_done(ccb);
72533190b70SSascha Wildner return(0);
72633190b70SSascha Wildner }
72733190b70SSascha Wildner
72833190b70SSascha Wildner if((ccb_h->flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
72933190b70SSascha Wildner if(ccb_h->flags & CAM_DIR_IN)
73033190b70SSascha Wildner req->flags = TWS_DIR_IN;
73133190b70SSascha Wildner else
73233190b70SSascha Wildner req->flags = TWS_DIR_OUT;
73333190b70SSascha Wildner } else {
73433190b70SSascha Wildner req->flags = TWS_DIR_NONE; /* no data */
73533190b70SSascha Wildner }
73633190b70SSascha Wildner
73733190b70SSascha Wildner req->type = TWS_SCSI_IO_REQ;
73833190b70SSascha Wildner req->cb = tws_scsi_complete;
73933190b70SSascha Wildner
74033190b70SSascha Wildner cmd_pkt = req->cmd_pkt;
74133190b70SSascha Wildner /* cmd_pkt->hdr.header_desc.size_header = 128; */
74233190b70SSascha Wildner cmd_pkt->cmd.pkt_a.res__opcode = TWS_FW_CMD_EXECUTE_SCSI;
74333190b70SSascha Wildner cmd_pkt->cmd.pkt_a.unit = ccb_h->target_id;
74433190b70SSascha Wildner cmd_pkt->cmd.pkt_a.status = 0;
74533190b70SSascha Wildner cmd_pkt->cmd.pkt_a.sgl_offset = 16;
74633190b70SSascha Wildner
74733190b70SSascha Wildner /* lower nibble */
74833190b70SSascha Wildner lun = ccb_h->target_lun & 0XF;
74933190b70SSascha Wildner lun = lun << 12;
75033190b70SSascha Wildner cmd_pkt->cmd.pkt_a.lun_l4__req_id = lun | req->request_id;
75133190b70SSascha Wildner /* upper nibble */
75233190b70SSascha Wildner lun = ccb_h->target_lun & 0XF0;
75333190b70SSascha Wildner lun = lun << 8;
75433190b70SSascha Wildner cmd_pkt->cmd.pkt_a.lun_h4__sgl_entries = lun;
75533190b70SSascha Wildner
75633190b70SSascha Wildner #ifdef TWS_DEBUG
75733190b70SSascha Wildner if ( csio->cdb_len > 16 )
75833190b70SSascha Wildner TWS_TRACE(sc, "cdb len too big", ccb_h->target_id, csio->cdb_len);
75933190b70SSascha Wildner #endif
76033190b70SSascha Wildner
76133190b70SSascha Wildner if(ccb_h->flags & CAM_CDB_POINTER)
76233190b70SSascha Wildner bcopy(csio->cdb_io.cdb_ptr, cmd_pkt->cmd.pkt_a.cdb, csio->cdb_len);
76333190b70SSascha Wildner else
76433190b70SSascha Wildner bcopy(csio->cdb_io.cdb_bytes, cmd_pkt->cmd.pkt_a.cdb, csio->cdb_len);
76533190b70SSascha Wildner
76633190b70SSascha Wildner if (!(ccb_h->flags & CAM_DATA_PHYS)) {
76733190b70SSascha Wildner /* Virtual data addresses. Need to convert them... */
76833190b70SSascha Wildner if (!(ccb_h->flags & CAM_SCATTER_VALID)) {
76933190b70SSascha Wildner if (csio->dxfer_len > TWS_MAX_IO_SIZE) {
77033190b70SSascha Wildner TWS_TRACE(sc, "I/O is big", csio->dxfer_len, 0);
77133190b70SSascha Wildner tws_release_request(req);
77233190b70SSascha Wildner ccb_h->status = CAM_REQ_TOO_BIG;
77333190b70SSascha Wildner xpt_done(ccb);
77433190b70SSascha Wildner return(0);
77533190b70SSascha Wildner }
77633190b70SSascha Wildner
77733190b70SSascha Wildner req->length = csio->dxfer_len;
77833190b70SSascha Wildner if (req->length) {
77933190b70SSascha Wildner req->data = csio->data_ptr;
78033190b70SSascha Wildner /* there is 1 sgl_entrie */
78133190b70SSascha Wildner /* cmd_pkt->cmd.pkt_a.lun_h4__sgl_entries |= 1; */
78233190b70SSascha Wildner }
78333190b70SSascha Wildner } else {
78433190b70SSascha Wildner TWS_TRACE_DEBUG(sc, "got sglist", ccb_h->target_id, ccb_h->target_lun);
78533190b70SSascha Wildner tws_release_request(req);
78633190b70SSascha Wildner ccb_h->status = CAM_REQ_CMP_ERR;
78733190b70SSascha Wildner xpt_done(ccb);
78833190b70SSascha Wildner return(0);
78933190b70SSascha Wildner }
79033190b70SSascha Wildner } else {
79133190b70SSascha Wildner /* Data addresses are physical. */
79233190b70SSascha Wildner TWS_TRACE_DEBUG(sc, "Phy data addr", ccb_h->target_id, ccb_h->target_lun);
79333190b70SSascha Wildner tws_release_request(req);
79433190b70SSascha Wildner ccb_h->status = CAM_REQ_CMP_ERR;
79533190b70SSascha Wildner ccb_h->status |= CAM_RELEASE_SIMQ;
79633190b70SSascha Wildner ccb_h->status &= ~CAM_SIM_QUEUED;
79733190b70SSascha Wildner xpt_done(ccb);
79833190b70SSascha Wildner return(0);
79933190b70SSascha Wildner }
80033190b70SSascha Wildner /* save ccb ptr */
80133190b70SSascha Wildner req->ccb_ptr = ccb;
80233190b70SSascha Wildner /*
80333190b70SSascha Wildner * tws_map_load_data_callback will fill in the SGL,
80433190b70SSascha Wildner * and submit the I/O.
80533190b70SSascha Wildner */
80633190b70SSascha Wildner sc->stats.scsi_ios++;
807*cec957e9SMatthew Dillon callout_reset(ccb_h->timeout_ch, (ccb_h->timeout * hz)/1000,
808*cec957e9SMatthew Dillon tws_timeout, req);
80933190b70SSascha Wildner error = tws_map_request(sc, req);
81033190b70SSascha Wildner return(error);
81133190b70SSascha Wildner }
81233190b70SSascha Wildner
81333190b70SSascha Wildner
81433190b70SSascha Wildner int
tws_send_scsi_cmd(struct tws_softc * sc,int cmd)81533190b70SSascha Wildner tws_send_scsi_cmd(struct tws_softc *sc, int cmd)
81633190b70SSascha Wildner {
81733190b70SSascha Wildner
81833190b70SSascha Wildner struct tws_request *req;
81933190b70SSascha Wildner struct tws_command_packet *cmd_pkt;
82033190b70SSascha Wildner int error;
82133190b70SSascha Wildner
82233190b70SSascha Wildner TWS_TRACE_DEBUG(sc, "entry",sc, cmd);
82333190b70SSascha Wildner req = tws_get_request(sc, TWS_AEN_FETCH_REQ);
82433190b70SSascha Wildner
82533190b70SSascha Wildner if ( req == NULL )
82633190b70SSascha Wildner return(ENOMEM);
82733190b70SSascha Wildner
82833190b70SSascha Wildner req->type = TWS_AEN_FETCH_REQ;
82933190b70SSascha Wildner req->cb = tws_aen_complete;
83033190b70SSascha Wildner
83133190b70SSascha Wildner cmd_pkt = req->cmd_pkt;
83233190b70SSascha Wildner cmd_pkt->cmd.pkt_a.res__opcode = TWS_FW_CMD_EXECUTE_SCSI;
83333190b70SSascha Wildner cmd_pkt->cmd.pkt_a.status = 0;
83433190b70SSascha Wildner cmd_pkt->cmd.pkt_a.unit = 0;
83533190b70SSascha Wildner cmd_pkt->cmd.pkt_a.sgl_offset = 16;
83633190b70SSascha Wildner cmd_pkt->cmd.pkt_a.lun_l4__req_id = req->request_id;
83733190b70SSascha Wildner
83833190b70SSascha Wildner cmd_pkt->cmd.pkt_a.cdb[0] = (u_int8_t)cmd;
83933190b70SSascha Wildner cmd_pkt->cmd.pkt_a.cdb[4] = 128;
84033190b70SSascha Wildner
84133190b70SSascha Wildner req->length = TWS_SECTOR_SIZE;
8420c374e73SSascha Wildner req->data = kmalloc(TWS_SECTOR_SIZE, M_TWS, M_NOWAIT | M_ZERO);
84333190b70SSascha Wildner if ( req->data == NULL )
84433190b70SSascha Wildner return(ENOMEM);
84533190b70SSascha Wildner req->flags = TWS_DIR_IN;
84633190b70SSascha Wildner
84733190b70SSascha Wildner callout_reset(&req->thandle, (TWS_IO_TIMEOUT * hz), tws_timeout, req);
84833190b70SSascha Wildner error = tws_map_request(sc, req);
84933190b70SSascha Wildner return(error);
85033190b70SSascha Wildner
85133190b70SSascha Wildner }
85233190b70SSascha Wildner
85333190b70SSascha Wildner int
tws_set_param(struct tws_softc * sc,u_int32_t table_id,u_int32_t param_id,u_int32_t param_size,void * data)85433190b70SSascha Wildner tws_set_param(struct tws_softc *sc, u_int32_t table_id, u_int32_t param_id,
85533190b70SSascha Wildner u_int32_t param_size, void *data)
85633190b70SSascha Wildner {
85733190b70SSascha Wildner struct tws_request *req;
85833190b70SSascha Wildner struct tws_command_packet *cmd_pkt;
85933190b70SSascha Wildner union tws_command_giga *cmd;
86033190b70SSascha Wildner struct tws_getset_param *param;
86133190b70SSascha Wildner int error;
86233190b70SSascha Wildner
86333190b70SSascha Wildner req = tws_get_request(sc, TWS_GETSET_PARAM_REQ);
86433190b70SSascha Wildner if ( req == NULL ) {
86533190b70SSascha Wildner TWS_TRACE_DEBUG(sc, "null req", 0, 0);
86633190b70SSascha Wildner return(ENOMEM);
86733190b70SSascha Wildner }
86833190b70SSascha Wildner
86933190b70SSascha Wildner req->length = TWS_SECTOR_SIZE;
8700c374e73SSascha Wildner req->data = kmalloc(TWS_SECTOR_SIZE, M_TWS, M_NOWAIT | M_ZERO);
87133190b70SSascha Wildner if ( req->data == NULL )
87233190b70SSascha Wildner return(ENOMEM);
87333190b70SSascha Wildner param = (struct tws_getset_param *)req->data;
87433190b70SSascha Wildner
87533190b70SSascha Wildner req->cb = tws_getset_param_complete;
87633190b70SSascha Wildner req->flags = TWS_DIR_OUT;
87733190b70SSascha Wildner cmd_pkt = req->cmd_pkt;
87833190b70SSascha Wildner
87933190b70SSascha Wildner cmd = &cmd_pkt->cmd.pkt_g;
88033190b70SSascha Wildner cmd->param.sgl_off__opcode =
88133190b70SSascha Wildner BUILD_SGL_OFF__OPCODE(2, TWS_FW_CMD_SET_PARAM);
88233190b70SSascha Wildner cmd->param.request_id = (u_int8_t)req->request_id;
88333190b70SSascha Wildner cmd->param.host_id__unit = 0;
88433190b70SSascha Wildner cmd->param.param_count = 1;
88533190b70SSascha Wildner cmd->param.size = 2; /* map routine will add sgls */
88633190b70SSascha Wildner
88733190b70SSascha Wildner /* Specify which parameter we want to set. */
88833190b70SSascha Wildner param->table_id = (table_id | TWS_9K_PARAM_DESCRIPTOR);
88933190b70SSascha Wildner param->parameter_id = (u_int8_t)(param_id);
89033190b70SSascha Wildner param->parameter_size_bytes = (u_int16_t)param_size;
89133190b70SSascha Wildner memcpy(param->data, data, param_size);
89233190b70SSascha Wildner
89333190b70SSascha Wildner callout_reset(&req->thandle, (TWS_IO_TIMEOUT * hz), tws_timeout, req);
89433190b70SSascha Wildner error = tws_map_request(sc, req);
89533190b70SSascha Wildner return(error);
89633190b70SSascha Wildner
89733190b70SSascha Wildner }
89833190b70SSascha Wildner
89933190b70SSascha Wildner 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)90033190b70SSascha Wildner tws_get_param(struct tws_softc *sc, u_int32_t table_id, u_int32_t param_id,
90133190b70SSascha Wildner u_int32_t param_size, void *data)
90233190b70SSascha Wildner {
90333190b70SSascha Wildner struct tws_request *req;
90433190b70SSascha Wildner struct tws_command_packet *cmd_pkt;
90533190b70SSascha Wildner union tws_command_giga *cmd;
90633190b70SSascha Wildner struct tws_getset_param *param;
90733190b70SSascha Wildner u_int16_t reqid;
90833190b70SSascha Wildner u_int64_t mfa;
90933190b70SSascha Wildner int error = SUCCESS;
91033190b70SSascha Wildner
91133190b70SSascha Wildner
91233190b70SSascha Wildner req = tws_get_request(sc, TWS_GETSET_PARAM_REQ);
91333190b70SSascha Wildner if ( req == NULL ) {
91433190b70SSascha Wildner TWS_TRACE_DEBUG(sc, "null req", 0, 0);
91533190b70SSascha Wildner return(FAILURE);
91633190b70SSascha Wildner }
91733190b70SSascha Wildner
91833190b70SSascha Wildner req->length = TWS_SECTOR_SIZE;
9190c374e73SSascha Wildner req->data = kmalloc(TWS_SECTOR_SIZE, M_TWS, M_NOWAIT | M_ZERO);
92033190b70SSascha Wildner if ( req->data == NULL )
92133190b70SSascha Wildner return(FAILURE);
92233190b70SSascha Wildner param = (struct tws_getset_param *)req->data;
92333190b70SSascha Wildner
92433190b70SSascha Wildner req->cb = NULL;
92533190b70SSascha Wildner req->flags = TWS_DIR_IN;
92633190b70SSascha Wildner cmd_pkt = req->cmd_pkt;
92733190b70SSascha Wildner
92833190b70SSascha Wildner cmd = &cmd_pkt->cmd.pkt_g;
92933190b70SSascha Wildner cmd->param.sgl_off__opcode =
93033190b70SSascha Wildner BUILD_SGL_OFF__OPCODE(2, TWS_FW_CMD_GET_PARAM);
93133190b70SSascha Wildner cmd->param.request_id = (u_int8_t)req->request_id;
93233190b70SSascha Wildner cmd->param.host_id__unit = 0;
93333190b70SSascha Wildner cmd->param.param_count = 1;
93433190b70SSascha Wildner cmd->param.size = 2; /* map routine will add sgls */
93533190b70SSascha Wildner
93633190b70SSascha Wildner /* Specify which parameter we want to set. */
93733190b70SSascha Wildner param->table_id = (table_id | TWS_9K_PARAM_DESCRIPTOR);
93833190b70SSascha Wildner param->parameter_id = (u_int8_t)(param_id);
93933190b70SSascha Wildner param->parameter_size_bytes = (u_int16_t)param_size;
94033190b70SSascha Wildner
94133190b70SSascha Wildner tws_map_request(sc, req);
94233190b70SSascha Wildner reqid = tws_poll4_response(sc, &mfa);
94333190b70SSascha Wildner tws_unmap_request(sc, req);
94433190b70SSascha Wildner
94533190b70SSascha Wildner if ( reqid == TWS_GETSET_PARAM_REQ ) {
94633190b70SSascha Wildner memcpy(data, param->data, param_size);
94733190b70SSascha Wildner } else {
94833190b70SSascha Wildner error = FAILURE;
94933190b70SSascha Wildner
95033190b70SSascha Wildner }
95133190b70SSascha Wildner
95233190b70SSascha Wildner kfree(req->data, M_TWS);
95333190b70SSascha Wildner lockmgr(&sc->gen_lock, LK_EXCLUSIVE);
95433190b70SSascha Wildner req->state = TWS_REQ_STATE_FREE;
95533190b70SSascha Wildner lockmgr(&sc->gen_lock, LK_RELEASE);
95633190b70SSascha Wildner return(error);
95733190b70SSascha Wildner
95833190b70SSascha Wildner }
95933190b70SSascha Wildner
96033190b70SSascha Wildner void
tws_unmap_request(struct tws_softc * sc,struct tws_request * req)96133190b70SSascha Wildner tws_unmap_request(struct tws_softc *sc, struct tws_request *req)
96233190b70SSascha Wildner {
96333190b70SSascha Wildner
96433190b70SSascha Wildner if (req->data != NULL) {
96533190b70SSascha Wildner if ( req->flags & TWS_DIR_IN )
96633190b70SSascha Wildner bus_dmamap_sync(sc->data_tag, req->dma_map,
96733190b70SSascha Wildner BUS_DMASYNC_POSTREAD);
96833190b70SSascha Wildner if ( req->flags & TWS_DIR_OUT )
96933190b70SSascha Wildner bus_dmamap_sync(sc->data_tag, req->dma_map,
97033190b70SSascha Wildner BUS_DMASYNC_POSTWRITE);
97133190b70SSascha Wildner lockmgr(&sc->io_lock, LK_EXCLUSIVE);
97233190b70SSascha Wildner bus_dmamap_unload(sc->data_tag, req->dma_map);
97333190b70SSascha Wildner lockmgr(&sc->io_lock, LK_RELEASE);
97433190b70SSascha Wildner }
97533190b70SSascha Wildner }
97633190b70SSascha Wildner
97733190b70SSascha Wildner int32_t
tws_map_request(struct tws_softc * sc,struct tws_request * req)97833190b70SSascha Wildner tws_map_request(struct tws_softc *sc, struct tws_request *req)
97933190b70SSascha Wildner {
98033190b70SSascha Wildner int32_t error = 0;
98133190b70SSascha Wildner
98233190b70SSascha Wildner
98333190b70SSascha Wildner /* If the command involves data, map that too. */
98433190b70SSascha Wildner if (req->data != NULL) {
98533190b70SSascha Wildner /*
98633190b70SSascha Wildner * Map the data buffer into bus space and build the SG list.
98733190b70SSascha Wildner */
98833190b70SSascha Wildner lockmgr(&sc->io_lock, LK_EXCLUSIVE);
98933190b70SSascha Wildner error = bus_dmamap_load(sc->data_tag, req->dma_map,
99033190b70SSascha Wildner req->data, req->length,
99133190b70SSascha Wildner tws_dmamap_data_load_cbfn, req,
99233190b70SSascha Wildner BUS_DMA_WAITOK);
99333190b70SSascha Wildner lockmgr(&sc->io_lock, LK_RELEASE);
99433190b70SSascha Wildner
99533190b70SSascha Wildner if (error == EINPROGRESS) {
99633190b70SSascha Wildner TWS_TRACE(sc, "in progress", 0, error);
99733190b70SSascha Wildner /* tws_freeze_simq(sc); */
99833190b70SSascha Wildner error = TWS_REQ_ERR_INPROGRESS;
99933190b70SSascha Wildner }
100033190b70SSascha Wildner } else { /* no data involved */
100133190b70SSascha Wildner error = tws_submit_command(sc, req);
100233190b70SSascha Wildner }
100333190b70SSascha Wildner req->error_code = error;
100433190b70SSascha Wildner return(error);
100533190b70SSascha Wildner }
100633190b70SSascha Wildner
100733190b70SSascha Wildner
100833190b70SSascha Wildner static void
tws_dmamap_data_load_cbfn(void * arg,bus_dma_segment_t * segs,int nseg,int error)100933190b70SSascha Wildner tws_dmamap_data_load_cbfn(void *arg, bus_dma_segment_t *segs,
101033190b70SSascha Wildner int nseg, int error)
101133190b70SSascha Wildner {
101233190b70SSascha Wildner
101333190b70SSascha Wildner struct tws_request *req = (struct tws_request *)arg;
101433190b70SSascha Wildner struct tws_softc *sc = req->sc;
101533190b70SSascha Wildner u_int16_t sgls = nseg;
101633190b70SSascha Wildner void *sgl_ptr;
101733190b70SSascha Wildner struct tws_cmd_generic *gcmd;
101833190b70SSascha Wildner
101933190b70SSascha Wildner if ( error == EFBIG )
102033190b70SSascha Wildner TWS_TRACE(sc, "not enough data segs", 0, nseg);
102133190b70SSascha Wildner
102233190b70SSascha Wildner
102333190b70SSascha Wildner if ( req->flags & TWS_DIR_IN )
102433190b70SSascha Wildner bus_dmamap_sync(req->sc->data_tag, req->dma_map,
102533190b70SSascha Wildner BUS_DMASYNC_PREREAD);
102633190b70SSascha Wildner if ( req->flags & TWS_DIR_OUT )
102733190b70SSascha Wildner bus_dmamap_sync(req->sc->data_tag, req->dma_map,
102833190b70SSascha Wildner BUS_DMASYNC_PREWRITE);
102933190b70SSascha Wildner if ( segs ) {
103033190b70SSascha Wildner if ( (req->type == TWS_PASSTHRU_REQ &&
103133190b70SSascha Wildner GET_OPCODE(req->cmd_pkt->cmd.pkt_a.res__opcode) !=
103233190b70SSascha Wildner TWS_FW_CMD_EXECUTE_SCSI) ||
103333190b70SSascha Wildner req->type == TWS_GETSET_PARAM_REQ) {
103433190b70SSascha Wildner gcmd = &req->cmd_pkt->cmd.pkt_g.generic;
103533190b70SSascha Wildner sgl_ptr = (u_int32_t *)(gcmd) + gcmd->size;
103633190b70SSascha Wildner gcmd->size += sgls *
103733190b70SSascha Wildner ((req->sc->is64bit && !tws_use_32bit_sgls) ? 4 :2 );
10384e1af74fSSascha Wildner tws_fill_sg_list(req->sc, segs, sgl_ptr, sgls);
103933190b70SSascha Wildner
104033190b70SSascha Wildner } else {
10414e1af74fSSascha Wildner tws_fill_sg_list(req->sc, segs,
104233190b70SSascha Wildner (void *)req->cmd_pkt->cmd.pkt_a.sg_list, sgls);
104333190b70SSascha Wildner req->cmd_pkt->cmd.pkt_a.lun_h4__sgl_entries |= sgls ;
104433190b70SSascha Wildner }
104533190b70SSascha Wildner }
104633190b70SSascha Wildner
104733190b70SSascha Wildner
104833190b70SSascha Wildner req->error_code = tws_submit_command(req->sc, req);
104933190b70SSascha Wildner
105033190b70SSascha Wildner }
105133190b70SSascha Wildner
105233190b70SSascha Wildner
105333190b70SSascha Wildner static void
tws_fill_sg_list(struct tws_softc * sc,void * sgl_src,void * sgl_dest,u_int16_t num_sgl_entries)105433190b70SSascha Wildner tws_fill_sg_list(struct tws_softc *sc, void *sgl_src, void *sgl_dest,
105533190b70SSascha Wildner u_int16_t num_sgl_entries)
105633190b70SSascha Wildner {
105733190b70SSascha Wildner int i;
105833190b70SSascha Wildner
105933190b70SSascha Wildner if ( sc->is64bit ) {
106033190b70SSascha Wildner struct tws_sg_desc64 *sgl_s = (struct tws_sg_desc64 *)sgl_src;
106133190b70SSascha Wildner
106233190b70SSascha Wildner if ( !tws_use_32bit_sgls ) {
106333190b70SSascha Wildner struct tws_sg_desc64 *sgl_d = (struct tws_sg_desc64 *)sgl_dest;
106433190b70SSascha Wildner if ( num_sgl_entries > TWS_MAX_64BIT_SG_ELEMENTS )
106533190b70SSascha Wildner TWS_TRACE(sc, "64bit sg overflow", num_sgl_entries, 0);
106633190b70SSascha Wildner for (i = 0; i < num_sgl_entries; i++) {
106733190b70SSascha Wildner sgl_d[i].address = sgl_s->address;
106833190b70SSascha Wildner sgl_d[i].length = sgl_s->length;
106933190b70SSascha Wildner sgl_d[i].flag = 0;
107033190b70SSascha Wildner sgl_d[i].reserved = 0;
107133190b70SSascha Wildner sgl_s = (struct tws_sg_desc64 *) (((u_int8_t *)sgl_s) +
107233190b70SSascha Wildner sizeof(bus_dma_segment_t));
107333190b70SSascha Wildner }
107433190b70SSascha Wildner } else {
107533190b70SSascha Wildner struct tws_sg_desc32 *sgl_d = (struct tws_sg_desc32 *)sgl_dest;
107633190b70SSascha Wildner if ( num_sgl_entries > TWS_MAX_32BIT_SG_ELEMENTS )
107733190b70SSascha Wildner TWS_TRACE(sc, "32bit sg overflow", num_sgl_entries, 0);
107833190b70SSascha Wildner for (i = 0; i < num_sgl_entries; i++) {
107933190b70SSascha Wildner sgl_d[i].address = sgl_s->address;
108033190b70SSascha Wildner sgl_d[i].length = sgl_s->length;
108133190b70SSascha Wildner sgl_d[i].flag = 0;
108233190b70SSascha Wildner sgl_s = (struct tws_sg_desc64 *) (((u_int8_t *)sgl_s) +
108333190b70SSascha Wildner sizeof(bus_dma_segment_t));
108433190b70SSascha Wildner }
108533190b70SSascha Wildner }
108633190b70SSascha Wildner } else {
108733190b70SSascha Wildner struct tws_sg_desc32 *sgl_s = (struct tws_sg_desc32 *)sgl_src;
108833190b70SSascha Wildner struct tws_sg_desc32 *sgl_d = (struct tws_sg_desc32 *)sgl_dest;
108933190b70SSascha Wildner
109033190b70SSascha Wildner if ( num_sgl_entries > TWS_MAX_32BIT_SG_ELEMENTS )
109133190b70SSascha Wildner TWS_TRACE(sc, "32bit sg overflow", num_sgl_entries, 0);
109233190b70SSascha Wildner
109333190b70SSascha Wildner
109433190b70SSascha Wildner for (i = 0; i < num_sgl_entries; i++) {
109533190b70SSascha Wildner sgl_d[i].address = sgl_s[i].address;
109633190b70SSascha Wildner sgl_d[i].length = sgl_s[i].length;
109733190b70SSascha Wildner sgl_d[i].flag = 0;
109833190b70SSascha Wildner }
109933190b70SSascha Wildner }
110033190b70SSascha Wildner }
110133190b70SSascha Wildner
110233190b70SSascha Wildner
110333190b70SSascha Wildner void
tws_intr(void * arg)110433190b70SSascha Wildner tws_intr(void *arg)
110533190b70SSascha Wildner {
110633190b70SSascha Wildner struct tws_softc *sc = (struct tws_softc *)arg;
110733190b70SSascha Wildner u_int32_t histat=0, db=0;
110833190b70SSascha Wildner
110933190b70SSascha Wildner KASSERT(sc, ("null softc"));
111033190b70SSascha Wildner
111133190b70SSascha Wildner sc->stats.num_intrs++;
111233190b70SSascha Wildner histat = tws_read_reg(sc, TWS_I2O0_HISTAT, 4);
111333190b70SSascha Wildner if ( histat & TWS_BIT2 ) {
111433190b70SSascha Wildner TWS_TRACE_DEBUG(sc, "door bell :)", histat, TWS_I2O0_HISTAT);
111533190b70SSascha Wildner db = tws_read_reg(sc, TWS_I2O0_IOBDB, 4);
111633190b70SSascha Wildner if ( db & TWS_BIT21 ) {
111733190b70SSascha Wildner tws_intr_attn_error(sc);
111833190b70SSascha Wildner return;
111933190b70SSascha Wildner }
112033190b70SSascha Wildner if ( db & TWS_BIT18 ) {
112133190b70SSascha Wildner tws_intr_attn_aen(sc);
112233190b70SSascha Wildner }
112333190b70SSascha Wildner }
112433190b70SSascha Wildner
112533190b70SSascha Wildner if ( histat & TWS_BIT3 ) {
112633190b70SSascha Wildner tws_intr_resp(sc);
112733190b70SSascha Wildner }
112833190b70SSascha Wildner }
112933190b70SSascha Wildner
113033190b70SSascha Wildner static void
tws_intr_attn_aen(struct tws_softc * sc)113133190b70SSascha Wildner tws_intr_attn_aen(struct tws_softc *sc)
113233190b70SSascha Wildner {
113333190b70SSascha Wildner u_int32_t db=0;
113433190b70SSascha Wildner
113533190b70SSascha Wildner /* maskoff db intrs untill all the aens are fetched */
113633190b70SSascha Wildner /* tws_disable_db_intr(sc); */
11374e1af74fSSascha Wildner tws_fetch_aen(sc);
113833190b70SSascha Wildner tws_write_reg(sc, TWS_I2O0_HOBDBC, TWS_BIT18, 4);
113933190b70SSascha Wildner db = tws_read_reg(sc, TWS_I2O0_IOBDB, 4);
114033190b70SSascha Wildner
114133190b70SSascha Wildner }
114233190b70SSascha Wildner
114333190b70SSascha Wildner static void
tws_intr_attn_error(struct tws_softc * sc)114433190b70SSascha Wildner tws_intr_attn_error(struct tws_softc *sc)
114533190b70SSascha Wildner {
114633190b70SSascha Wildner u_int32_t db=0;
114733190b70SSascha Wildner
114833190b70SSascha Wildner TWS_TRACE(sc, "attn error", 0, 0);
114933190b70SSascha Wildner tws_write_reg(sc, TWS_I2O0_HOBDBC, ~0, 4);
115033190b70SSascha Wildner db = tws_read_reg(sc, TWS_I2O0_IOBDB, 4);
115133190b70SSascha Wildner device_printf(sc->tws_dev, "Micro controller error.\n");
115233190b70SSascha Wildner tws_reset(sc);
115333190b70SSascha Wildner }
115433190b70SSascha Wildner
115533190b70SSascha Wildner static void
tws_intr_resp(struct tws_softc * sc)115633190b70SSascha Wildner tws_intr_resp(struct tws_softc *sc)
115733190b70SSascha Wildner {
115833190b70SSascha Wildner u_int16_t req_id;
115933190b70SSascha Wildner u_int64_t mfa;
116033190b70SSascha Wildner
116133190b70SSascha Wildner while ( tws_get_response(sc, &req_id, &mfa) ) {
116233190b70SSascha Wildner sc->stats.reqs_out++;
116333190b70SSascha Wildner if ( req_id == TWS_INVALID_REQID ) {
116433190b70SSascha Wildner TWS_TRACE_DEBUG(sc, "invalid req_id", mfa, req_id);
116533190b70SSascha Wildner sc->stats.reqs_errored++;
116633190b70SSascha Wildner tws_err_complete(sc, mfa);
116733190b70SSascha Wildner continue;
116833190b70SSascha Wildner }
116933190b70SSascha Wildner
117033190b70SSascha Wildner sc->reqs[req_id].cb(&sc->reqs[req_id]);
117133190b70SSascha Wildner }
117233190b70SSascha Wildner
117333190b70SSascha Wildner }
117433190b70SSascha Wildner
117533190b70SSascha Wildner
117633190b70SSascha Wildner static void
tws_poll(struct cam_sim * sim)117733190b70SSascha Wildner tws_poll(struct cam_sim *sim)
117833190b70SSascha Wildner {
117933190b70SSascha Wildner struct tws_softc *sc = (struct tws_softc *)cam_sim_softc(sim);
118033190b70SSascha Wildner TWS_TRACE_DEBUG(sc, "entry", 0, 0);
11814e1af74fSSascha Wildner tws_intr(sc);
118233190b70SSascha Wildner }
118333190b70SSascha Wildner
11848406cf70SSascha Wildner static void
tws_timeout(void * arg)118533190b70SSascha Wildner tws_timeout(void *arg)
118633190b70SSascha Wildner {
118733190b70SSascha Wildner struct tws_request *req = (struct tws_request *)arg;
118833190b70SSascha Wildner struct tws_softc *sc = req->sc;
118933190b70SSascha Wildner
119033190b70SSascha Wildner
119133190b70SSascha Wildner if ( tws_get_state(sc) != TWS_RESET ) {
119233190b70SSascha Wildner device_printf(sc->tws_dev, "Request timed out.\n");
11934e1af74fSSascha Wildner tws_reset(sc);
119433190b70SSascha Wildner }
119533190b70SSascha Wildner }
119633190b70SSascha Wildner
119733190b70SSascha Wildner void
tws_reset(void * arg)119833190b70SSascha Wildner tws_reset(void *arg)
119933190b70SSascha Wildner {
120033190b70SSascha Wildner
120133190b70SSascha Wildner struct tws_softc *sc = (struct tws_softc *)arg;
120233190b70SSascha Wildner
120333190b70SSascha Wildner if ( tws_get_state(sc) == TWS_RESET ) {
120433190b70SSascha Wildner return;
120533190b70SSascha Wildner }
120633190b70SSascha Wildner device_printf(sc->tws_dev, "Resetting controller\n");
120733190b70SSascha Wildner lockmgr(&sc->gen_lock, LK_EXCLUSIVE);
120833190b70SSascha Wildner tws_send_event(sc, TWS_RESET_START);
120933190b70SSascha Wildner lockmgr(&sc->gen_lock, LK_RELEASE);
121033190b70SSascha Wildner
121133190b70SSascha Wildner tws_turn_off_interrupts(sc);
121233190b70SSascha Wildner lockmgr(&sc->sim_lock, LK_EXCLUSIVE);
121333190b70SSascha Wildner tws_freeze_simq(sc);
121433190b70SSascha Wildner lockmgr(&sc->sim_lock, LK_RELEASE);
121533190b70SSascha Wildner
121633190b70SSascha Wildner tws_assert_soft_reset(sc);
121733190b70SSascha Wildner callout_reset(&sc->reset_cb_handle, hz/10, tws_reset_cb, sc);
121833190b70SSascha Wildner }
121933190b70SSascha Wildner
122033190b70SSascha Wildner static void
tws_reset_cb(void * arg)122133190b70SSascha Wildner tws_reset_cb(void *arg)
122233190b70SSascha Wildner {
122333190b70SSascha Wildner
122433190b70SSascha Wildner struct tws_softc *sc = (struct tws_softc *)arg;
122533190b70SSascha Wildner u_int32_t reg;
122633190b70SSascha Wildner
122733190b70SSascha Wildner if ( tws_get_state(sc) != TWS_RESET ) {
122833190b70SSascha Wildner return;
122933190b70SSascha Wildner }
123033190b70SSascha Wildner reg = tws_read_reg(sc, TWS_I2O0_SCRPD3, 4);
123133190b70SSascha Wildner if (!( reg & TWS_BIT13 )) {
123233190b70SSascha Wildner callout_reset(&sc->reset_cb_handle, hz/10, tws_reset_cb, sc);
123333190b70SSascha Wildner return;
123433190b70SSascha Wildner }
123533190b70SSascha Wildner tws_drain_response_queue(sc);
123633190b70SSascha Wildner tws_drain_busy_queue(sc);
123733190b70SSascha Wildner tws_drain_reserved_reqs(sc);
123833190b70SSascha Wildner callout_reset(&sc->reinit_handle, 5*hz, tws_reinit, sc);
123933190b70SSascha Wildner }
124033190b70SSascha Wildner
124133190b70SSascha Wildner static void
tws_reinit(void * arg)124233190b70SSascha Wildner tws_reinit(void *arg)
124333190b70SSascha Wildner {
124433190b70SSascha Wildner
124533190b70SSascha Wildner struct tws_softc *sc = (struct tws_softc *)arg;
124633190b70SSascha Wildner static int timeout_val=0, try=2 ;
124733190b70SSascha Wildner
124833190b70SSascha Wildner if ( !tws_ctlr_ready(sc) ) {
124933190b70SSascha Wildner timeout_val += 5;
125033190b70SSascha Wildner if ( timeout_val >= TWS_RESET_TIMEOUT ) {
125133190b70SSascha Wildner timeout_val = 0;
125233190b70SSascha Wildner if ( try )
125333190b70SSascha Wildner tws_assert_soft_reset(sc);
125433190b70SSascha Wildner try--;
125533190b70SSascha Wildner }
125633190b70SSascha Wildner callout_reset(&sc->reinit_handle, 5*hz, tws_reinit, sc);
125733190b70SSascha Wildner return;
125833190b70SSascha Wildner }
125933190b70SSascha Wildner
126033190b70SSascha Wildner timeout_val=0;
126133190b70SSascha Wildner try = 2;
126233190b70SSascha Wildner sc->obfl_q_overrun = false;
126333190b70SSascha Wildner if ( tws_init_connect(sc, tws_queue_depth) ) {
126433190b70SSascha Wildner TWS_TRACE_DEBUG(sc, "initConnect failed", 0, sc->is64bit);
126533190b70SSascha Wildner }
126633190b70SSascha Wildner tws_init_obfl_q(sc);
126733190b70SSascha Wildner
126833190b70SSascha Wildner lockmgr(&sc->sim_lock, LK_EXCLUSIVE);
126933190b70SSascha Wildner tws_release_simq(sc);
127033190b70SSascha Wildner lockmgr(&sc->sim_lock, LK_RELEASE);
127133190b70SSascha Wildner tws_turn_on_interrupts(sc);
127233190b70SSascha Wildner
127333190b70SSascha Wildner lockmgr(&sc->gen_lock, LK_EXCLUSIVE);
127433190b70SSascha Wildner tws_send_event(sc, TWS_RESET_COMPLETE);
127533190b70SSascha Wildner lockmgr(&sc->gen_lock, LK_RELEASE);
127633190b70SSascha Wildner if ( sc->chan ) {
127733190b70SSascha Wildner sc->chan = 0;
127833190b70SSascha Wildner wakeup((void *)&sc->chan);
127933190b70SSascha Wildner }
128033190b70SSascha Wildner
128133190b70SSascha Wildner }
128233190b70SSascha Wildner
128333190b70SSascha Wildner
128433190b70SSascha Wildner static void
tws_freeze_simq(struct tws_softc * sc)128533190b70SSascha Wildner tws_freeze_simq(struct tws_softc *sc)
128633190b70SSascha Wildner {
128733190b70SSascha Wildner
128833190b70SSascha Wildner TWS_TRACE_DEBUG(sc, "freezeing", 0, 0);
128933190b70SSascha Wildner KKASSERT(lockstatus(&sc->sim_lock, curthread) != 0);
129033190b70SSascha Wildner xpt_freeze_simq(sc->sim, 1);
129133190b70SSascha Wildner
129233190b70SSascha Wildner }
129333190b70SSascha Wildner static void
tws_release_simq(struct tws_softc * sc)129433190b70SSascha Wildner tws_release_simq(struct tws_softc *sc)
129533190b70SSascha Wildner {
129633190b70SSascha Wildner
129733190b70SSascha Wildner TWS_TRACE_DEBUG(sc, "unfreezeing", 0, 0);
129833190b70SSascha Wildner KKASSERT(lockstatus(&sc->sim_lock, curthread) != 0);
129933190b70SSascha Wildner xpt_release_simq(sc->sim, 1);
130033190b70SSascha Wildner
130133190b70SSascha Wildner }
130233190b70SSascha Wildner
130333190b70SSascha Wildner
130433190b70SSascha Wildner TUNABLE_INT("hw.tws.cam_depth", &tws_cam_depth);
1305