1226026Sdelphij/*
2226026Sdelphij * Copyright (c) 2010 LSI Corp.
3226026Sdelphij * All rights reserved.
4226026Sdelphij * Author : Manjunath Ranganathaiah <manjunath.ranganathaiah@lsi.com>
5226026Sdelphij *
6226026Sdelphij * Redistribution and use in source and binary forms, with or without
7226026Sdelphij * modification, are permitted provided that the following conditions
8226026Sdelphij * are met:
9226026Sdelphij * 1. Redistributions of source code must retain the above copyright
10226026Sdelphij *    notice, this list of conditions and the following disclaimer.
11226026Sdelphij * 2. Redistributions in binary form must reproduce the above copyright
12226026Sdelphij *    notice, this list of conditions and the following disclaimer in the
13226026Sdelphij *    documentation and/or other materials provided with the distribution.
14226026Sdelphij *
15226026Sdelphij * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16226026Sdelphij * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17226026Sdelphij * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18226026Sdelphij * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19226026Sdelphij * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20226026Sdelphij * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21226026Sdelphij * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22226026Sdelphij * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23226026Sdelphij * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24226026Sdelphij * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25226026Sdelphij * SUCH DAMAGE.
26226026Sdelphij *
27226026Sdelphij * $FreeBSD: stable/10/sys/dev/tws/tws_cam.c 315813 2017-03-23 06:41:13Z mav $
28226026Sdelphij */
29226026Sdelphij
30226026Sdelphij#include <dev/tws/tws.h>
31226026Sdelphij#include <dev/tws/tws_services.h>
32226026Sdelphij#include <dev/tws/tws_hdm.h>
33226026Sdelphij#include <dev/tws/tws_user.h>
34226026Sdelphij#include <cam/cam.h>
35226026Sdelphij#include <cam/cam_ccb.h>
36226026Sdelphij#include <cam/cam_sim.h>
37226026Sdelphij#include <cam/cam_xpt_sim.h>
38226026Sdelphij#include <cam/cam_debug.h>
39226026Sdelphij#include <cam/cam_periph.h>
40226026Sdelphij
41226026Sdelphij#include <cam/scsi/scsi_all.h>
42226026Sdelphij#include <cam/scsi/scsi_message.h>
43226026Sdelphij
44226026Sdelphijstatic int tws_cam_depth=(TWS_MAX_REQS - TWS_RESERVED_REQS);
45226026Sdelphijstatic char tws_sev_str[5][8]={"","ERROR","WARNING","INFO","DEBUG"};
46226026Sdelphij
47226026Sdelphijstatic void  tws_action(struct cam_sim *sim, union ccb *ccb);
48226026Sdelphijstatic void  tws_poll(struct cam_sim *sim);
49226026Sdelphijstatic void tws_scsi_complete(struct tws_request *req);
50226026Sdelphij
51226026Sdelphij
52226026Sdelphij
53226026Sdelphijvoid tws_unmap_request(struct tws_softc *sc, struct tws_request *req);
54226026Sdelphijint32_t tws_map_request(struct tws_softc *sc, struct tws_request *req);
55226026Sdelphijint tws_bus_scan(struct tws_softc *sc);
56226026Sdelphijint tws_cam_attach(struct tws_softc *sc);
57226026Sdelphijvoid tws_cam_detach(struct tws_softc *sc);
58226026Sdelphijvoid tws_reset(void *arg);
59226026Sdelphij
60226026Sdelphijstatic void tws_reset_cb(void *arg);
61226026Sdelphijstatic void tws_reinit(void *arg);
62226026Sdelphijstatic int32_t tws_execute_scsi(struct tws_softc *sc, union ccb *ccb);
63226026Sdelphijstatic void tws_freeze_simq(struct tws_softc *sc, struct tws_request *req);
64226026Sdelphijstatic void tws_dmamap_data_load_cbfn(void *arg, bus_dma_segment_t *segs,
65226026Sdelphij                            int nseg, int error);
66226026Sdelphijstatic void tws_fill_sg_list(struct tws_softc *sc, void *sgl_src,
67226026Sdelphij                            void *sgl_dest, u_int16_t num_sgl_entries);
68226026Sdelphijstatic void tws_err_complete(struct tws_softc *sc, u_int64_t mfa);
69226026Sdelphijstatic void tws_scsi_err_complete(struct tws_request *req,
70226026Sdelphij                                               struct tws_command_header *hdr);
71226026Sdelphijstatic void tws_passthru_err_complete(struct tws_request *req,
72226026Sdelphij                                               struct tws_command_header *hdr);
73226026Sdelphij
74226026Sdelphij
75226026Sdelphijvoid tws_timeout(void *arg);
76226026Sdelphijstatic void tws_intr_attn_aen(struct tws_softc *sc);
77226026Sdelphijstatic void tws_intr_attn_error(struct tws_softc *sc);
78226026Sdelphijstatic void tws_intr_resp(struct tws_softc *sc);
79226026Sdelphijvoid tws_intr(void *arg);
80226026Sdelphijvoid tws_cmd_complete(struct tws_request *req);
81226026Sdelphijvoid tws_aen_complete(struct tws_request *req);
82226026Sdelphijint tws_send_scsi_cmd(struct tws_softc *sc, int cmd);
83226026Sdelphijvoid tws_getset_param_complete(struct tws_request *req);
84226026Sdelphijint tws_set_param(struct tws_softc *sc, u_int32_t table_id, u_int32_t param_id,
85226026Sdelphij              u_int32_t param_size, void *data);
86226026Sdelphijint tws_get_param(struct tws_softc *sc, u_int32_t table_id, u_int32_t param_id,
87226026Sdelphij              u_int32_t param_size, void *data);
88226026Sdelphij
89226026Sdelphij
90226026Sdelphijextern struct tws_request *tws_get_request(struct tws_softc *sc,
91226026Sdelphij                                            u_int16_t type);
92226026Sdelphijextern void *tws_release_request(struct tws_request *req);
93226026Sdelphijextern int tws_submit_command(struct tws_softc *sc, struct tws_request *req);
94226026Sdelphijextern boolean tws_get_response(struct tws_softc *sc,
95226026Sdelphij                                           u_int16_t *req_id, u_int64_t *mfa);
96226026Sdelphijextern void tws_q_insert_tail(struct tws_softc *sc, struct tws_request *req,
97226026Sdelphij                                u_int8_t q_type );
98226026Sdelphijextern struct tws_request * tws_q_remove_request(struct tws_softc *sc,
99226026Sdelphij                                   struct tws_request *req, u_int8_t q_type );
100226026Sdelphijextern void tws_send_event(struct tws_softc *sc, u_int8_t event);
101226026Sdelphij
102226026Sdelphijextern struct tws_sense *
103226026Sdelphijtws_find_sense_from_mfa(struct tws_softc *sc, u_int64_t mfa);
104226026Sdelphij
105226026Sdelphijextern void tws_fetch_aen(void *arg);
106226026Sdelphijextern void tws_disable_db_intr(struct tws_softc *sc);
107226026Sdelphijextern void tws_enable_db_intr(struct tws_softc *sc);
108226026Sdelphijextern void tws_passthru_complete(struct tws_request *req);
109226026Sdelphijextern void tws_aen_synctime_with_host(struct tws_softc *sc);
110226026Sdelphijextern void tws_circular_aenq_insert(struct tws_softc *sc,
111226026Sdelphij                    struct tws_circular_q *cq, struct tws_event_packet *aen);
112226026Sdelphijextern int tws_use_32bit_sgls;
113226026Sdelphijextern boolean tws_ctlr_reset(struct tws_softc *sc);
114226026Sdelphijextern struct tws_request * tws_q_remove_tail(struct tws_softc *sc,
115226026Sdelphij                                                           u_int8_t q_type );
116226026Sdelphijextern void tws_turn_off_interrupts(struct tws_softc *sc);
117226026Sdelphijextern void tws_turn_on_interrupts(struct tws_softc *sc);
118226026Sdelphijextern int tws_init_connect(struct tws_softc *sc, u_int16_t mc);
119226026Sdelphijextern void tws_init_obfl_q(struct tws_softc *sc);
120226026Sdelphijextern uint8_t tws_get_state(struct tws_softc *sc);
121226026Sdelphijextern void tws_assert_soft_reset(struct tws_softc *sc);
122226026Sdelphijextern boolean tws_ctlr_ready(struct tws_softc *sc);
123226026Sdelphijextern u_int16_t tws_poll4_response(struct tws_softc *sc, u_int64_t *mfa);
124226026Sdelphijextern int tws_setup_intr(struct tws_softc *sc, int irqs);
125226026Sdelphijextern int tws_teardown_intr(struct tws_softc *sc);
126226026Sdelphij
127226026Sdelphij
128226026Sdelphij
129226026Sdelphijint
130226026Sdelphijtws_cam_attach(struct tws_softc *sc)
131226026Sdelphij{
132226026Sdelphij    struct cam_devq *devq;
133226026Sdelphij
134226026Sdelphij    TWS_TRACE_DEBUG(sc, "entry", 0, sc);
135226026Sdelphij    /* Create a device queue for sim */
136226026Sdelphij
137226026Sdelphij    /*
138226026Sdelphij     * if the user sets cam depth to less than 1
139226026Sdelphij     * cam may get confused
140226026Sdelphij     */
141226026Sdelphij    if ( tws_cam_depth < 1 )
142226026Sdelphij        tws_cam_depth = 1;
143226026Sdelphij    if ( tws_cam_depth > (tws_queue_depth - TWS_RESERVED_REQS)  )
144226026Sdelphij        tws_cam_depth = tws_queue_depth - TWS_RESERVED_REQS;
145226026Sdelphij
146226026Sdelphij    TWS_TRACE_DEBUG(sc, "depths,ctlr,cam", tws_queue_depth, tws_cam_depth);
147226026Sdelphij
148226026Sdelphij    if ((devq = cam_simq_alloc(tws_cam_depth)) == NULL) {
149226026Sdelphij        tws_log(sc, CAM_SIMQ_ALLOC);
150226026Sdelphij        return(ENOMEM);
151226026Sdelphij    }
152226026Sdelphij
153226026Sdelphij   /*
154226026Sdelphij    * Create a SIM entry.  Though we can support tws_cam_depth
155226026Sdelphij    * simultaneous requests, we claim to be able to handle only
156226026Sdelphij    * (tws_cam_depth), so that we always have reserved  requests
157226026Sdelphij    * packet available to service ioctls and internal commands.
158226026Sdelphij    */
159226026Sdelphij    sc->sim = cam_sim_alloc(tws_action, tws_poll, "tws", sc,
160226026Sdelphij                      device_get_unit(sc->tws_dev),
161226026Sdelphij#if (__FreeBSD_version >= 700000)
162226026Sdelphij                      &sc->sim_lock,
163226026Sdelphij#endif
164226026Sdelphij                      tws_cam_depth, 1, devq);
165226026Sdelphij                      /* 1, 1, devq); */
166226026Sdelphij    if (sc->sim == NULL) {
167226026Sdelphij        cam_simq_free(devq);
168226026Sdelphij        tws_log(sc, CAM_SIM_ALLOC);
169226026Sdelphij    }
170226026Sdelphij    /* Register the bus. */
171226026Sdelphij    mtx_lock(&sc->sim_lock);
172226026Sdelphij    if (xpt_bus_register(sc->sim,
173226026Sdelphij#if (__FreeBSD_version >= 700000)
174226026Sdelphij                         sc->tws_dev,
175226026Sdelphij#endif
176226026Sdelphij                         0) != CAM_SUCCESS) {
177226026Sdelphij        cam_sim_free(sc->sim, TRUE); /* passing true will free the devq */
178226026Sdelphij        sc->sim = NULL; /* so cam_detach will not try to free it */
179226026Sdelphij        mtx_unlock(&sc->sim_lock);
180226026Sdelphij        tws_log(sc, TWS_XPT_BUS_REGISTER);
181226026Sdelphij        return(ENXIO);
182226026Sdelphij    }
183226026Sdelphij    if (xpt_create_path(&sc->path, NULL, cam_sim_path(sc->sim),
184226026Sdelphij                         CAM_TARGET_WILDCARD,
185226026Sdelphij                         CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
186226026Sdelphij        xpt_bus_deregister(cam_sim_path(sc->sim));
187226026Sdelphij        /* Passing TRUE to cam_sim_free will free the devq as well. */
188226026Sdelphij        cam_sim_free(sc->sim, TRUE);
189226026Sdelphij        tws_log(sc, TWS_XPT_CREATE_PATH);
190226026Sdelphij        mtx_unlock(&sc->sim_lock);
191226026Sdelphij        return(ENXIO);
192226026Sdelphij    }
193226026Sdelphij    mtx_unlock(&sc->sim_lock);
194226026Sdelphij
195226026Sdelphij    return(0);
196226026Sdelphij}
197226026Sdelphij
198226026Sdelphijvoid
199226026Sdelphijtws_cam_detach(struct tws_softc *sc)
200226026Sdelphij{
201226026Sdelphij    TWS_TRACE_DEBUG(sc, "entry", 0, 0);
202226026Sdelphij    mtx_lock(&sc->sim_lock);
203226026Sdelphij    if (sc->path)
204226026Sdelphij        xpt_free_path(sc->path);
205226026Sdelphij    if (sc->sim) {
206226026Sdelphij        xpt_bus_deregister(cam_sim_path(sc->sim));
207226026Sdelphij        cam_sim_free(sc->sim, TRUE);
208226026Sdelphij    }
209226026Sdelphij    mtx_unlock(&sc->sim_lock);
210226026Sdelphij}
211226026Sdelphij
212226026Sdelphijint
213226026Sdelphijtws_bus_scan(struct tws_softc *sc)
214226026Sdelphij{
215226026Sdelphij    union ccb       *ccb;
216226026Sdelphij
217226026Sdelphij    TWS_TRACE_DEBUG(sc, "entry", sc, 0);
218226026Sdelphij    if (!(sc->sim))
219226026Sdelphij        return(ENXIO);
220248973Smav    ccb = xpt_alloc_ccb();
221248973Smav    mtx_lock(&sc->sim_lock);
222249468Smav    if (xpt_create_path(&ccb->ccb_h.path, NULL, cam_sim_path(sc->sim),
223226026Sdelphij                  CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
224248973Smav	mtx_unlock(&sc->sim_lock);
225226026Sdelphij        xpt_free_ccb(ccb);
226226026Sdelphij        return(EIO);
227226026Sdelphij    }
228226026Sdelphij    xpt_rescan(ccb);
229248973Smav    mtx_unlock(&sc->sim_lock);
230226026Sdelphij    return(0);
231226026Sdelphij}
232226026Sdelphij
233226026Sdelphijstatic void
234226026Sdelphijtws_action(struct cam_sim *sim, union ccb *ccb)
235226026Sdelphij{
236226026Sdelphij    struct tws_softc *sc = (struct tws_softc *)cam_sim_softc(sim);
237226026Sdelphij
238226026Sdelphij
239226026Sdelphij    switch( ccb->ccb_h.func_code ) {
240226026Sdelphij        case XPT_SCSI_IO:
241226026Sdelphij        {
242226026Sdelphij            if ( tws_execute_scsi(sc, ccb) )
243226026Sdelphij                TWS_TRACE_DEBUG(sc, "execute scsi failed", 0, 0);
244226026Sdelphij            break;
245226026Sdelphij        }
246226026Sdelphij        case XPT_ABORT:
247226026Sdelphij        {
248226026Sdelphij            TWS_TRACE_DEBUG(sc, "abort i/o", 0, 0);
249226026Sdelphij            ccb->ccb_h.status = CAM_UA_ABORT;
250226026Sdelphij            xpt_done(ccb);
251226026Sdelphij            break;
252226026Sdelphij        }
253226026Sdelphij        case XPT_RESET_BUS:
254226026Sdelphij        {
255226026Sdelphij            TWS_TRACE_DEBUG(sc, "reset bus", sim, ccb);
256226026Sdelphij            break;
257226026Sdelphij        }
258226026Sdelphij        case XPT_SET_TRAN_SETTINGS:
259226026Sdelphij        {
260226026Sdelphij            TWS_TRACE_DEBUG(sc, "set tran settings", sim, ccb);
261226026Sdelphij            ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
262226026Sdelphij            xpt_done(ccb);
263226026Sdelphij
264226026Sdelphij            break;
265226026Sdelphij        }
266226026Sdelphij        case XPT_GET_TRAN_SETTINGS:
267226026Sdelphij        {
268226026Sdelphij            TWS_TRACE_DEBUG(sc, "get tran settings", sim, ccb);
269226026Sdelphij
270226026Sdelphij#if (__FreeBSD_version >= 700000 )
271226026Sdelphij            ccb->cts.protocol = PROTO_SCSI;
272226026Sdelphij            ccb->cts.protocol_version = SCSI_REV_2;
273226026Sdelphij            ccb->cts.transport = XPORT_SPI;
274226026Sdelphij            ccb->cts.transport_version = 2;
275226026Sdelphij
276226026Sdelphij            ccb->cts.xport_specific.spi.valid = CTS_SPI_VALID_DISC;
277226026Sdelphij            ccb->cts.xport_specific.spi.flags = CTS_SPI_FLAGS_DISC_ENB;
278226026Sdelphij            ccb->cts.proto_specific.scsi.valid = CTS_SCSI_VALID_TQ;
279226026Sdelphij            ccb->cts.proto_specific.scsi.flags = CTS_SCSI_FLAGS_TAG_ENB;
280226026Sdelphij#else
281226026Sdelphij            ccb->cts.valid = (CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID);
282226026Sdelphij            ccb->cts.flags &= ~(CCB_TRANS_DISC_ENB | CCB_TRANS_TAG_ENB);
283226026Sdelphij#endif
284226026Sdelphij            ccb->ccb_h.status = CAM_REQ_CMP;
285226026Sdelphij            xpt_done(ccb);
286226026Sdelphij
287226026Sdelphij            break;
288226026Sdelphij        }
289226026Sdelphij        case XPT_CALC_GEOMETRY:
290226026Sdelphij        {
291226026Sdelphij            TWS_TRACE_DEBUG(sc, "calc geometry(ccb,block-size)", ccb,
292226026Sdelphij                                          ccb->ccg.block_size);
293226026Sdelphij            cam_calc_geometry(&ccb->ccg, 1/* extended */);
294226026Sdelphij            xpt_done(ccb);
295226026Sdelphij
296226026Sdelphij            break;
297226026Sdelphij        }
298226026Sdelphij        case XPT_PATH_INQ:
299226026Sdelphij        {
300226026Sdelphij            TWS_TRACE_DEBUG(sc, "path inquiry", sim, ccb);
301226026Sdelphij            ccb->cpi.version_num = 1;
302226026Sdelphij            ccb->cpi.hba_inquiry = 0;
303226026Sdelphij            ccb->cpi.target_sprt = 0;
304226026Sdelphij            ccb->cpi.hba_misc = 0;
305226026Sdelphij            ccb->cpi.hba_eng_cnt = 0;
306226026Sdelphij            ccb->cpi.max_target = TWS_MAX_NUM_UNITS;
307226026Sdelphij            ccb->cpi.max_lun = TWS_MAX_NUM_LUNS - 1;
308226026Sdelphij            ccb->cpi.unit_number = cam_sim_unit(sim);
309226026Sdelphij            ccb->cpi.bus_id = cam_sim_bus(sim);
310226026Sdelphij            ccb->cpi.initiator_id = TWS_SCSI_INITIATOR_ID;
311226026Sdelphij            ccb->cpi.base_transfer_speed = 6000000;
312315813Smav            strlcpy(ccb->cpi.sim_vid, "FreeBSD", SIM_IDLEN);
313315813Smav            strlcpy(ccb->cpi.hba_vid, "3ware", HBA_IDLEN);
314315813Smav            strlcpy(ccb->cpi.dev_name, cam_sim_name(sim), DEV_IDLEN);
315226026Sdelphij#if (__FreeBSD_version >= 700000 )
316226026Sdelphij            ccb->cpi.transport = XPORT_SPI;
317226026Sdelphij            ccb->cpi.transport_version = 2;
318226026Sdelphij            ccb->cpi.protocol = PROTO_SCSI;
319226026Sdelphij            ccb->cpi.protocol_version = SCSI_REV_2;
320226026Sdelphij            ccb->cpi.maxio = TWS_MAX_IO_SIZE;
321226026Sdelphij#endif
322226026Sdelphij            ccb->ccb_h.status = CAM_REQ_CMP;
323226026Sdelphij            xpt_done(ccb);
324226026Sdelphij
325226026Sdelphij            break;
326226026Sdelphij        }
327226026Sdelphij        default:
328226026Sdelphij            TWS_TRACE_DEBUG(sc, "default", sim, ccb);
329226026Sdelphij            ccb->ccb_h.status = CAM_REQ_INVALID;
330226026Sdelphij            xpt_done(ccb);
331226026Sdelphij            break;
332226026Sdelphij    }
333226026Sdelphij}
334226026Sdelphij
335226026Sdelphijstatic void
336226026Sdelphijtws_scsi_complete(struct tws_request *req)
337226026Sdelphij{
338226026Sdelphij    struct tws_softc *sc = req->sc;
339226026Sdelphij
340226026Sdelphij    mtx_lock(&sc->q_lock);
341226026Sdelphij    tws_q_remove_request(sc, req, TWS_BUSY_Q);
342226026Sdelphij    mtx_unlock(&sc->q_lock);
343226026Sdelphij
344275977Ssmh    callout_stop(&req->timeout);
345226026Sdelphij    tws_unmap_request(req->sc, req);
346226026Sdelphij
347226026Sdelphij
348226026Sdelphij    req->ccb_ptr->ccb_h.status = CAM_REQ_CMP;
349226026Sdelphij    mtx_lock(&sc->sim_lock);
350226026Sdelphij    xpt_done(req->ccb_ptr);
351226026Sdelphij    mtx_unlock(&sc->sim_lock);
352226026Sdelphij
353226026Sdelphij    mtx_lock(&sc->q_lock);
354226026Sdelphij    tws_q_insert_tail(sc, req, TWS_FREE_Q);
355226026Sdelphij    mtx_unlock(&sc->q_lock);
356226026Sdelphij}
357226026Sdelphij
358226026Sdelphijvoid
359226026Sdelphijtws_getset_param_complete(struct tws_request *req)
360226026Sdelphij{
361226026Sdelphij    struct tws_softc *sc = req->sc;
362226026Sdelphij
363226026Sdelphij    TWS_TRACE_DEBUG(sc, "getset complete", req, req->request_id);
364226026Sdelphij
365275977Ssmh    callout_stop(&req->timeout);
366226026Sdelphij    tws_unmap_request(sc, req);
367226026Sdelphij
368226026Sdelphij    free(req->data, M_TWS);
369226026Sdelphij
370226026Sdelphij    req->state = TWS_REQ_STATE_FREE;
371226026Sdelphij}
372226026Sdelphij
373226026Sdelphijvoid
374226026Sdelphijtws_aen_complete(struct tws_request *req)
375226026Sdelphij{
376226026Sdelphij    struct tws_softc *sc = req->sc;
377226026Sdelphij    struct tws_command_header *sense;
378226026Sdelphij    struct tws_event_packet event;
379226026Sdelphij    u_int16_t aen_code=0;
380226026Sdelphij
381226026Sdelphij    TWS_TRACE_DEBUG(sc, "aen complete", 0, req->request_id);
382226026Sdelphij
383275977Ssmh    callout_stop(&req->timeout);
384226026Sdelphij    tws_unmap_request(sc, req);
385226026Sdelphij
386226026Sdelphij    sense = (struct tws_command_header *)req->data;
387226026Sdelphij
388226026Sdelphij    TWS_TRACE_DEBUG(sc,"sense code, key",sense->sense_data[0],
389226026Sdelphij                                   sense->sense_data[2]);
390226026Sdelphij    TWS_TRACE_DEBUG(sc,"sense rid, seve",sense->header_desc.request_id,
391226026Sdelphij                                   sense->status_block.res__severity);
392226026Sdelphij    TWS_TRACE_DEBUG(sc,"sense srcnum, error",sense->status_block.srcnum,
393226026Sdelphij                                   sense->status_block.error);
394226026Sdelphij    TWS_TRACE_DEBUG(sc,"sense shdr, ssense",sense->header_desc.size_header,
395226026Sdelphij                                   sense->header_desc.size_sense);
396226026Sdelphij
397226026Sdelphij    aen_code = sense->status_block.error;
398226026Sdelphij
399226026Sdelphij    switch ( aen_code ) {
400226026Sdelphij        case TWS_AEN_SYNC_TIME_WITH_HOST :
401226026Sdelphij            tws_aen_synctime_with_host(sc);
402226026Sdelphij            break;
403226026Sdelphij        case TWS_AEN_QUEUE_EMPTY :
404226026Sdelphij            break;
405226026Sdelphij        default :
406226026Sdelphij            bzero(&event, sizeof(struct tws_event_packet));
407226026Sdelphij            event.sequence_id = sc->seq_id;
408226026Sdelphij            event.time_stamp_sec = (u_int32_t)TWS_LOCAL_TIME;
409226026Sdelphij            event.aen_code = sense->status_block.error;
410226026Sdelphij            event.severity = sense->status_block.res__severity & 0x7;
411226026Sdelphij            event.event_src = TWS_SRC_CTRL_EVENT;
412226026Sdelphij            strcpy(event.severity_str, tws_sev_str[event.severity]);
413226026Sdelphij            event.retrieved = TWS_AEN_NOT_RETRIEVED;
414226026Sdelphij
415226026Sdelphij            bcopy(sense->err_specific_desc, event.parameter_data,
416226026Sdelphij                                    TWS_ERROR_SPECIFIC_DESC_LEN);
417226026Sdelphij            event.parameter_data[TWS_ERROR_SPECIFIC_DESC_LEN - 1] = '\0';
418226026Sdelphij            event.parameter_len = (u_int8_t)strlen(event.parameter_data)+1;
419226026Sdelphij
420226026Sdelphij            if ( event.parameter_len < TWS_ERROR_SPECIFIC_DESC_LEN ) {
421226026Sdelphij                event.parameter_len += ((u_int8_t)strlen(event.parameter_data +
422226026Sdelphij                                                event.parameter_len) + 1);
423226026Sdelphij            }
424226026Sdelphij
425226026Sdelphij            device_printf(sc->tws_dev, "%s: (0x%02X: 0x%04X): %s: %s\n",
426226026Sdelphij                event.severity_str,
427226026Sdelphij                event.event_src,
428226026Sdelphij                event.aen_code,
429226026Sdelphij                event.parameter_data +
430226026Sdelphij                     (strlen(event.parameter_data) + 1),
431226026Sdelphij                event.parameter_data);
432226026Sdelphij
433226026Sdelphij            mtx_lock(&sc->gen_lock);
434226026Sdelphij            tws_circular_aenq_insert(sc, &sc->aen_q, &event);
435226026Sdelphij            sc->seq_id++;
436226026Sdelphij            mtx_unlock(&sc->gen_lock);
437226026Sdelphij            break;
438226026Sdelphij
439226026Sdelphij    }
440226026Sdelphij
441226026Sdelphij    free(req->data, M_TWS);
442226026Sdelphij
443226026Sdelphij    req->state = TWS_REQ_STATE_FREE;
444226026Sdelphij
445226026Sdelphij    if ( aen_code != TWS_AEN_QUEUE_EMPTY ) {
446226026Sdelphij        /* timeout(tws_fetch_aen, sc, 1);*/
447226026Sdelphij        sc->stats.num_aens++;
448226026Sdelphij        tws_fetch_aen((void *)sc);
449226026Sdelphij    }
450226026Sdelphij}
451226026Sdelphij
452226026Sdelphijvoid
453226026Sdelphijtws_cmd_complete(struct tws_request *req)
454226026Sdelphij{
455226026Sdelphij    struct tws_softc *sc = req->sc;
456226026Sdelphij
457275977Ssmh    callout_stop(&req->timeout);
458226026Sdelphij    tws_unmap_request(sc, req);
459226026Sdelphij}
460226026Sdelphij
461226026Sdelphijstatic void
462226026Sdelphijtws_err_complete(struct tws_softc *sc, u_int64_t mfa)
463226026Sdelphij{
464226026Sdelphij    struct tws_command_header *hdr;
465226026Sdelphij    struct tws_sense *sen;
466226026Sdelphij    struct tws_request *req;
467226026Sdelphij    u_int16_t req_id;
468226026Sdelphij    u_int32_t reg, status;
469226026Sdelphij
470226026Sdelphij    if ( !mfa ) {
471226026Sdelphij        TWS_TRACE_DEBUG(sc, "null mfa", 0, mfa);
472226026Sdelphij        return;
473226026Sdelphij    } else {
474226026Sdelphij        /* lookup the sense */
475226026Sdelphij        sen = tws_find_sense_from_mfa(sc, mfa);
476226026Sdelphij        if ( sen == NULL ) {
477226026Sdelphij            TWS_TRACE_DEBUG(sc, "found null req", 0, mfa);
478226026Sdelphij            return;
479226026Sdelphij        }
480226026Sdelphij        hdr = sen->hdr;
481226026Sdelphij        TWS_TRACE_DEBUG(sc, "sen, hdr", sen, hdr);
482226026Sdelphij        req_id = hdr->header_desc.request_id;
483226026Sdelphij        req = &sc->reqs[req_id];
484226026Sdelphij        TWS_TRACE_DEBUG(sc, "req, id", req, req_id);
485226026Sdelphij        if ( req->error_code != TWS_REQ_RET_SUBMIT_SUCCESS )
486226026Sdelphij            TWS_TRACE_DEBUG(sc, "submit failure?", 0, req->error_code);
487226026Sdelphij    }
488226026Sdelphij
489226026Sdelphij    switch (req->type) {
490226026Sdelphij        case TWS_REQ_TYPE_PASSTHRU :
491226026Sdelphij            tws_passthru_err_complete(req, hdr);
492226026Sdelphij            break;
493226026Sdelphij        case TWS_REQ_TYPE_GETSET_PARAM :
494226026Sdelphij            tws_getset_param_complete(req);
495226026Sdelphij            break;
496226026Sdelphij        case TWS_REQ_TYPE_SCSI_IO :
497226026Sdelphij            tws_scsi_err_complete(req, hdr);
498226026Sdelphij            break;
499226026Sdelphij
500226026Sdelphij    }
501226026Sdelphij
502226026Sdelphij    mtx_lock(&sc->io_lock);
503226026Sdelphij    hdr->header_desc.size_header = 128;
504226026Sdelphij    reg = (u_int32_t)( mfa>>32);
505226026Sdelphij    tws_write_reg(sc, TWS_I2O0_HOBQPH, reg, 4);
506226026Sdelphij    reg = (u_int32_t)(mfa);
507226026Sdelphij    tws_write_reg(sc, TWS_I2O0_HOBQPL, reg, 4);
508226026Sdelphij
509226026Sdelphij    status = tws_read_reg(sc, TWS_I2O0_STATUS, 4);
510226026Sdelphij    if ( status & TWS_BIT13 ) {
511226026Sdelphij        device_printf(sc->tws_dev,  "OBFL Overrun\n");
512226026Sdelphij        sc->obfl_q_overrun = true;
513226026Sdelphij    }
514226026Sdelphij    mtx_unlock(&sc->io_lock);
515226026Sdelphij}
516226026Sdelphij
517226026Sdelphijstatic void
518226026Sdelphijtws_scsi_err_complete(struct tws_request *req, struct tws_command_header *hdr)
519226026Sdelphij{
520226026Sdelphij    u_int8_t *sense_data;
521226026Sdelphij    struct tws_softc *sc = req->sc;
522226026Sdelphij    union ccb *ccb = req->ccb_ptr;
523226026Sdelphij
524226026Sdelphij    TWS_TRACE_DEBUG(sc, "sbe, cmd_status", hdr->status_block.error,
525226026Sdelphij                                 req->cmd_pkt->cmd.pkt_a.status);
526226026Sdelphij    if ( hdr->status_block.error == TWS_ERROR_LOGICAL_UNIT_NOT_SUPPORTED ||
527226026Sdelphij         hdr->status_block.error == TWS_ERROR_UNIT_OFFLINE ) {
528226026Sdelphij
529226026Sdelphij        if ( ccb->ccb_h.target_lun ) {
530226026Sdelphij            TWS_TRACE_DEBUG(sc, "invalid lun error",0,0);
531240901Sjimharris            ccb->ccb_h.status |= CAM_DEV_NOT_THERE;
532226026Sdelphij        } else {
533226026Sdelphij            TWS_TRACE_DEBUG(sc, "invalid target error",0,0);
534240901Sjimharris            ccb->ccb_h.status |= CAM_SEL_TIMEOUT;
535226026Sdelphij        }
536226026Sdelphij
537226026Sdelphij    } else {
538226026Sdelphij        TWS_TRACE_DEBUG(sc, "scsi status  error",0,0);
539226026Sdelphij        ccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR;
540226026Sdelphij        if (((ccb->csio.cdb_io.cdb_bytes[0] == 0x1A) &&
541226026Sdelphij              (hdr->status_block.error == TWS_ERROR_NOT_SUPPORTED))) {
542226026Sdelphij            ccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR | CAM_AUTOSNS_VALID;
543226026Sdelphij            TWS_TRACE_DEBUG(sc, "page mode not supported",0,0);
544226026Sdelphij        }
545226026Sdelphij    }
546226026Sdelphij
547226026Sdelphij    /* if there were no error simply mark complete error */
548226026Sdelphij    if (ccb->ccb_h.status == 0)
549226026Sdelphij        ccb->ccb_h.status = CAM_REQ_CMP_ERR;
550226026Sdelphij
551226026Sdelphij    sense_data = (u_int8_t *)&ccb->csio.sense_data;
552226026Sdelphij    if (sense_data) {
553226026Sdelphij        memcpy(sense_data, hdr->sense_data, TWS_SENSE_DATA_LENGTH );
554226026Sdelphij        ccb->csio.sense_len = TWS_SENSE_DATA_LENGTH;
555226026Sdelphij        ccb->ccb_h.status |= CAM_AUTOSNS_VALID;
556226026Sdelphij    }
557226026Sdelphij    ccb->csio.scsi_status = req->cmd_pkt->cmd.pkt_a.status;
558226026Sdelphij
559226026Sdelphij    ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
560226026Sdelphij    mtx_lock(&sc->sim_lock);
561226026Sdelphij    xpt_done(ccb);
562226026Sdelphij    mtx_unlock(&sc->sim_lock);
563226026Sdelphij
564275977Ssmh    callout_stop(&req->timeout);
565226026Sdelphij    tws_unmap_request(req->sc, req);
566226026Sdelphij    mtx_lock(&sc->q_lock);
567226026Sdelphij    tws_q_remove_request(sc, req, TWS_BUSY_Q);
568226026Sdelphij    tws_q_insert_tail(sc, req, TWS_FREE_Q);
569226026Sdelphij    mtx_unlock(&sc->q_lock);
570226026Sdelphij}
571226026Sdelphij
572226026Sdelphijstatic void
573226026Sdelphijtws_passthru_err_complete(struct tws_request *req,
574226026Sdelphij                                          struct tws_command_header *hdr)
575226026Sdelphij{
576226026Sdelphij    TWS_TRACE_DEBUG(req->sc, "entry", hdr, req->request_id);
577226026Sdelphij    req->error_code = hdr->status_block.error;
578226026Sdelphij    memcpy(&(req->cmd_pkt->hdr), hdr, sizeof(struct tws_command_header));
579226026Sdelphij    tws_passthru_complete(req);
580226026Sdelphij}
581226026Sdelphij
582226026Sdelphijstatic void
583226026Sdelphijtws_drain_busy_queue(struct tws_softc *sc)
584226026Sdelphij{
585226026Sdelphij    struct tws_request *req;
586226026Sdelphij    union ccb          *ccb;
587226026Sdelphij    TWS_TRACE_DEBUG(sc, "entry", 0, 0);
588226026Sdelphij
589226026Sdelphij    mtx_lock(&sc->q_lock);
590226026Sdelphij    req = tws_q_remove_tail(sc, TWS_BUSY_Q);
591226026Sdelphij    mtx_unlock(&sc->q_lock);
592226026Sdelphij    while ( req ) {
593226026Sdelphij        TWS_TRACE_DEBUG(sc, "moved to TWS_COMPLETE_Q", 0, req->request_id);
594275977Ssmh	callout_stop(&req->timeout);
595226026Sdelphij
596226026Sdelphij        req->error_code = TWS_REQ_RET_RESET;
597226026Sdelphij        ccb = (union ccb *)(req->ccb_ptr);
598226026Sdelphij
599226026Sdelphij        ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
600226026Sdelphij        ccb->ccb_h.status |=  CAM_REQUEUE_REQ;
601226026Sdelphij        ccb->ccb_h.status |=  CAM_SCSI_BUS_RESET;
602226026Sdelphij
603226026Sdelphij        tws_unmap_request(req->sc, req);
604226026Sdelphij
605226026Sdelphij        mtx_lock(&sc->sim_lock);
606226026Sdelphij        xpt_done(req->ccb_ptr);
607226026Sdelphij        mtx_unlock(&sc->sim_lock);
608226026Sdelphij
609226026Sdelphij        mtx_lock(&sc->q_lock);
610226026Sdelphij        tws_q_insert_tail(sc, req, TWS_FREE_Q);
611226026Sdelphij        req = tws_q_remove_tail(sc, TWS_BUSY_Q);
612226026Sdelphij        mtx_unlock(&sc->q_lock);
613226026Sdelphij    }
614226026Sdelphij}
615226026Sdelphij
616226026Sdelphij
617226026Sdelphijstatic void
618226026Sdelphijtws_drain_reserved_reqs(struct tws_softc *sc)
619226026Sdelphij{
620226026Sdelphij    struct tws_request *r;
621226026Sdelphij
622226026Sdelphij    r = &sc->reqs[TWS_REQ_TYPE_AEN_FETCH];
623226026Sdelphij    if ( r->state != TWS_REQ_STATE_FREE ) {
624226026Sdelphij        TWS_TRACE_DEBUG(sc, "reset aen req", 0, 0);
625275977Ssmh	callout_stop(&r->timeout);
626226026Sdelphij        tws_unmap_request(sc, r);
627226026Sdelphij        free(r->data, M_TWS);
628226026Sdelphij        r->state = TWS_REQ_STATE_FREE;
629226026Sdelphij        r->error_code = TWS_REQ_RET_RESET;
630226026Sdelphij    }
631226026Sdelphij
632226026Sdelphij    r = &sc->reqs[TWS_REQ_TYPE_PASSTHRU];
633226026Sdelphij    if ( r->state == TWS_REQ_STATE_BUSY ) {
634226026Sdelphij        TWS_TRACE_DEBUG(sc, "reset passthru req", 0, 0);
635226026Sdelphij        r->error_code = TWS_REQ_RET_RESET;
636226026Sdelphij    }
637226026Sdelphij
638226026Sdelphij    r = &sc->reqs[TWS_REQ_TYPE_GETSET_PARAM];
639226026Sdelphij    if ( r->state != TWS_REQ_STATE_FREE ) {
640226026Sdelphij        TWS_TRACE_DEBUG(sc, "reset setparam req", 0, 0);
641275977Ssmh	callout_stop(&r->timeout);
642226026Sdelphij        tws_unmap_request(sc, r);
643226026Sdelphij        free(r->data, M_TWS);
644226026Sdelphij        r->state = TWS_REQ_STATE_FREE;
645226026Sdelphij        r->error_code = TWS_REQ_RET_RESET;
646226026Sdelphij    }
647226026Sdelphij}
648226026Sdelphij
649226026Sdelphijstatic void
650226026Sdelphijtws_drain_response_queue(struct tws_softc *sc)
651226026Sdelphij{
652226026Sdelphij    u_int16_t req_id;
653226026Sdelphij    u_int64_t mfa;
654226026Sdelphij    while ( tws_get_response(sc, &req_id, &mfa) );
655226026Sdelphij}
656226026Sdelphij
657226026Sdelphij
658226026Sdelphijstatic int32_t
659226026Sdelphijtws_execute_scsi(struct tws_softc *sc, union ccb *ccb)
660226026Sdelphij{
661226026Sdelphij    struct tws_command_packet *cmd_pkt;
662226026Sdelphij    struct tws_request *req;
663226026Sdelphij    struct ccb_hdr *ccb_h = &(ccb->ccb_h);
664226026Sdelphij    struct ccb_scsiio *csio = &(ccb->csio);
665226026Sdelphij    int error;
666226026Sdelphij    u_int16_t lun;
667226026Sdelphij
668226026Sdelphij    mtx_assert(&sc->sim_lock, MA_OWNED);
669226026Sdelphij    if (ccb_h->target_id >= TWS_MAX_NUM_UNITS) {
670226026Sdelphij        TWS_TRACE_DEBUG(sc, "traget id too big", ccb_h->target_id, ccb_h->target_lun);
671226026Sdelphij        ccb_h->status |= CAM_TID_INVALID;
672226026Sdelphij        xpt_done(ccb);
673226026Sdelphij        return(0);
674226026Sdelphij    }
675226026Sdelphij    if (ccb_h->target_lun >= TWS_MAX_NUM_LUNS) {
676226026Sdelphij        TWS_TRACE_DEBUG(sc, "target lun 2 big", ccb_h->target_id, ccb_h->target_lun);
677226026Sdelphij        ccb_h->status |= CAM_LUN_INVALID;
678226026Sdelphij        xpt_done(ccb);
679226026Sdelphij        return(0);
680226026Sdelphij    }
681226026Sdelphij
682226026Sdelphij    if(ccb_h->flags & CAM_CDB_PHYS) {
683226026Sdelphij        TWS_TRACE_DEBUG(sc, "cdb phy", ccb_h->target_id, ccb_h->target_lun);
684226026Sdelphij        ccb_h->status = CAM_REQ_INVALID;
685226026Sdelphij        xpt_done(ccb);
686226026Sdelphij        return(0);
687226026Sdelphij    }
688226026Sdelphij
689226026Sdelphij    /*
690226026Sdelphij     * We are going to work on this request.  Mark it as enqueued (though
691226026Sdelphij     * we don't actually queue it...)
692226026Sdelphij     */
693226026Sdelphij    ccb_h->status |= CAM_SIM_QUEUED;
694226026Sdelphij
695226026Sdelphij    req = tws_get_request(sc, TWS_REQ_TYPE_SCSI_IO);
696226026Sdelphij    if ( !req ) {
697226026Sdelphij        TWS_TRACE_DEBUG(sc, "no reqs", ccb_h->target_id, ccb_h->target_lun);
698226026Sdelphij        ccb_h->status |= CAM_REQUEUE_REQ;
699226026Sdelphij        xpt_done(ccb);
700226026Sdelphij        return(0);
701226026Sdelphij    }
702226026Sdelphij
703226026Sdelphij    if((ccb_h->flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
704226026Sdelphij        if(ccb_h->flags & CAM_DIR_IN)
705226026Sdelphij            req->flags |= TWS_DIR_IN;
706226026Sdelphij        if(ccb_h->flags & CAM_DIR_OUT)
707226026Sdelphij            req->flags |= TWS_DIR_OUT;
708226026Sdelphij    } else {
709226026Sdelphij        req->flags = TWS_DIR_NONE; /* no data */
710226026Sdelphij    }
711226026Sdelphij
712226026Sdelphij    req->type = TWS_REQ_TYPE_SCSI_IO;
713226026Sdelphij    req->cb = tws_scsi_complete;
714226026Sdelphij
715226026Sdelphij    cmd_pkt = req->cmd_pkt;
716226026Sdelphij    /* cmd_pkt->hdr.header_desc.size_header = 128; */
717226026Sdelphij    cmd_pkt->cmd.pkt_a.res__opcode = TWS_FW_CMD_EXECUTE_SCSI;
718226026Sdelphij    cmd_pkt->cmd.pkt_a.unit = ccb_h->target_id;
719226026Sdelphij    cmd_pkt->cmd.pkt_a.status = 0;
720226026Sdelphij    cmd_pkt->cmd.pkt_a.sgl_offset = 16;
721226026Sdelphij
722226026Sdelphij    /* lower nibble */
723226026Sdelphij    lun = ccb_h->target_lun & 0XF;
724226026Sdelphij    lun = lun << 12;
725226026Sdelphij    cmd_pkt->cmd.pkt_a.lun_l4__req_id = lun | req->request_id;
726226026Sdelphij    /* upper nibble */
727226026Sdelphij    lun = ccb_h->target_lun & 0XF0;
728226026Sdelphij    lun = lun << 8;
729226026Sdelphij    cmd_pkt->cmd.pkt_a.lun_h4__sgl_entries = lun;
730226026Sdelphij
731226026Sdelphij#ifdef TWS_DEBUG
732226026Sdelphij    if ( csio->cdb_len > 16 )
733226026Sdelphij         TWS_TRACE(sc, "cdb len too big", ccb_h->target_id, csio->cdb_len);
734226026Sdelphij#endif
735226026Sdelphij
736226026Sdelphij    if(ccb_h->flags & CAM_CDB_POINTER)
737226026Sdelphij        bcopy(csio->cdb_io.cdb_ptr, cmd_pkt->cmd.pkt_a.cdb, csio->cdb_len);
738226026Sdelphij    else
739226026Sdelphij        bcopy(csio->cdb_io.cdb_bytes, cmd_pkt->cmd.pkt_a.cdb, csio->cdb_len);
740226026Sdelphij
741246713Skib    req->data = ccb;
742246713Skib    req->flags |= TWS_DATA_CCB;
743226026Sdelphij    /* save ccb ptr */
744226026Sdelphij    req->ccb_ptr = ccb;
745226026Sdelphij    /*
746226026Sdelphij     * tws_map_load_data_callback will fill in the SGL,
747226026Sdelphij     * and submit the I/O.
748226026Sdelphij     */
749226026Sdelphij    sc->stats.scsi_ios++;
750275982Ssmh    callout_reset_sbt(&req->timeout, SBT_1MS * ccb->ccb_h.timeout, 0,
751275982Ssmh      tws_timeout, req, 0);
752226026Sdelphij    error = tws_map_request(sc, req);
753226026Sdelphij    return(error);
754226026Sdelphij}
755226026Sdelphij
756226026Sdelphij
757226026Sdelphijint
758226026Sdelphijtws_send_scsi_cmd(struct tws_softc *sc, int cmd)
759226026Sdelphij{
760226026Sdelphij    struct tws_request *req;
761226026Sdelphij    struct tws_command_packet *cmd_pkt;
762226026Sdelphij    int error;
763226026Sdelphij
764226026Sdelphij    TWS_TRACE_DEBUG(sc, "entry",sc, cmd);
765226026Sdelphij    req = tws_get_request(sc, TWS_REQ_TYPE_AEN_FETCH);
766226026Sdelphij
767226026Sdelphij    if ( req == NULL )
768226026Sdelphij        return(ENOMEM);
769226026Sdelphij
770226026Sdelphij    req->cb = tws_aen_complete;
771226026Sdelphij
772226026Sdelphij    cmd_pkt = req->cmd_pkt;
773226026Sdelphij    cmd_pkt->cmd.pkt_a.res__opcode = TWS_FW_CMD_EXECUTE_SCSI;
774226026Sdelphij    cmd_pkt->cmd.pkt_a.status = 0;
775226026Sdelphij    cmd_pkt->cmd.pkt_a.unit = 0;
776226026Sdelphij    cmd_pkt->cmd.pkt_a.sgl_offset = 16;
777226026Sdelphij    cmd_pkt->cmd.pkt_a.lun_l4__req_id = req->request_id;
778226026Sdelphij
779226026Sdelphij    cmd_pkt->cmd.pkt_a.cdb[0] = (u_int8_t)cmd;
780226026Sdelphij    cmd_pkt->cmd.pkt_a.cdb[4] = 128;
781226026Sdelphij
782226026Sdelphij    req->length = TWS_SECTOR_SIZE;
783226026Sdelphij    req->data = malloc(TWS_SECTOR_SIZE, M_TWS, M_NOWAIT);
784226026Sdelphij    if ( req->data == NULL )
785226026Sdelphij        return(ENOMEM);
786226026Sdelphij    bzero(req->data, TWS_SECTOR_SIZE);
787226026Sdelphij    req->flags = TWS_DIR_IN;
788226026Sdelphij
789275977Ssmh    callout_reset(&req->timeout, (TWS_IO_TIMEOUT * hz), tws_timeout, req);
790226026Sdelphij    error = tws_map_request(sc, req);
791226026Sdelphij    return(error);
792226026Sdelphij
793226026Sdelphij}
794226026Sdelphij
795226026Sdelphijint
796226026Sdelphijtws_set_param(struct tws_softc *sc, u_int32_t table_id, u_int32_t param_id,
797226026Sdelphij              u_int32_t param_size, void *data)
798226026Sdelphij{
799226026Sdelphij    struct tws_request *req;
800226026Sdelphij    struct tws_command_packet *cmd_pkt;
801226026Sdelphij    union tws_command_giga *cmd;
802226026Sdelphij    struct tws_getset_param *param;
803226026Sdelphij    int error;
804226026Sdelphij
805226026Sdelphij    req = tws_get_request(sc, TWS_REQ_TYPE_GETSET_PARAM);
806226026Sdelphij    if ( req == NULL ) {
807226026Sdelphij        TWS_TRACE_DEBUG(sc, "null req", 0, 0);
808226026Sdelphij        return(ENOMEM);
809226026Sdelphij    }
810226026Sdelphij
811226026Sdelphij    req->length = TWS_SECTOR_SIZE;
812226026Sdelphij    req->data = malloc(TWS_SECTOR_SIZE, M_TWS, M_NOWAIT);
813226026Sdelphij    if ( req->data == NULL )
814226026Sdelphij        return(ENOMEM);
815226026Sdelphij    bzero(req->data, TWS_SECTOR_SIZE);
816226026Sdelphij    param = (struct tws_getset_param *)req->data;
817226026Sdelphij
818226026Sdelphij    req->cb = tws_getset_param_complete;
819226026Sdelphij    req->flags = TWS_DIR_OUT;
820226026Sdelphij    cmd_pkt = req->cmd_pkt;
821226026Sdelphij
822226026Sdelphij    cmd = &cmd_pkt->cmd.pkt_g;
823226026Sdelphij    cmd->param.sgl_off__opcode =
824226026Sdelphij            BUILD_SGL_OFF__OPCODE(2, TWS_FW_CMD_SET_PARAM);
825226026Sdelphij    cmd->param.request_id = (u_int8_t)req->request_id;
826226026Sdelphij    cmd->param.host_id__unit = 0;
827226026Sdelphij    cmd->param.param_count = 1;
828226026Sdelphij    cmd->param.size = 2; /* map routine will add sgls */
829226026Sdelphij
830226026Sdelphij    /* Specify which parameter we want to set. */
831226026Sdelphij    param->table_id = (table_id | TWS_9K_PARAM_DESCRIPTOR);
832226026Sdelphij    param->parameter_id = (u_int8_t)(param_id);
833226026Sdelphij    param->parameter_size_bytes = (u_int16_t)param_size;
834226026Sdelphij    memcpy(param->data, data, param_size);
835226026Sdelphij
836275977Ssmh    callout_reset(&req->timeout, (TWS_IOCTL_TIMEOUT * hz), tws_timeout, req);
837226026Sdelphij    error = tws_map_request(sc, req);
838226026Sdelphij    return(error);
839226026Sdelphij
840226026Sdelphij}
841226026Sdelphij
842226026Sdelphijint
843226026Sdelphijtws_get_param(struct tws_softc *sc, u_int32_t table_id, u_int32_t param_id,
844226026Sdelphij              u_int32_t param_size, void *data)
845226026Sdelphij{
846226026Sdelphij    struct tws_request *req;
847226026Sdelphij    struct tws_command_packet *cmd_pkt;
848226026Sdelphij    union tws_command_giga *cmd;
849226026Sdelphij    struct tws_getset_param *param;
850226026Sdelphij    u_int16_t reqid;
851226026Sdelphij    u_int64_t mfa;
852226026Sdelphij    int error = SUCCESS;
853226026Sdelphij
854226026Sdelphij
855226026Sdelphij    req = tws_get_request(sc, TWS_REQ_TYPE_GETSET_PARAM);
856226026Sdelphij    if ( req == NULL ) {
857226026Sdelphij        TWS_TRACE_DEBUG(sc, "null req", 0, 0);
858226026Sdelphij        return(FAILURE);
859226026Sdelphij    }
860226026Sdelphij
861226026Sdelphij    req->length = TWS_SECTOR_SIZE;
862226026Sdelphij    req->data = malloc(TWS_SECTOR_SIZE, M_TWS, M_NOWAIT);
863226026Sdelphij    if ( req->data == NULL )
864226026Sdelphij        return(FAILURE);
865226026Sdelphij    bzero(req->data, TWS_SECTOR_SIZE);
866226026Sdelphij    param = (struct tws_getset_param *)req->data;
867226026Sdelphij
868226026Sdelphij    req->cb = NULL;
869226026Sdelphij    req->flags = TWS_DIR_IN;
870226026Sdelphij    cmd_pkt = req->cmd_pkt;
871226026Sdelphij
872226026Sdelphij    cmd = &cmd_pkt->cmd.pkt_g;
873226026Sdelphij    cmd->param.sgl_off__opcode =
874226026Sdelphij            BUILD_SGL_OFF__OPCODE(2, TWS_FW_CMD_GET_PARAM);
875226026Sdelphij    cmd->param.request_id = (u_int8_t)req->request_id;
876226026Sdelphij    cmd->param.host_id__unit = 0;
877226026Sdelphij    cmd->param.param_count = 1;
878226026Sdelphij    cmd->param.size = 2; /* map routine will add sgls */
879226026Sdelphij
880226026Sdelphij    /* Specify which parameter we want to set. */
881226026Sdelphij    param->table_id = (table_id | TWS_9K_PARAM_DESCRIPTOR);
882226026Sdelphij    param->parameter_id = (u_int8_t)(param_id);
883226026Sdelphij    param->parameter_size_bytes = (u_int16_t)param_size;
884226026Sdelphij
885226026Sdelphij    error = tws_map_request(sc, req);
886226026Sdelphij    if (!error) {
887226026Sdelphij        reqid = tws_poll4_response(sc, &mfa);
888226026Sdelphij        tws_unmap_request(sc, req);
889226026Sdelphij
890226026Sdelphij        if ( reqid == TWS_REQ_TYPE_GETSET_PARAM ) {
891226026Sdelphij            memcpy(data, param->data, param_size);
892226026Sdelphij        } else {
893226026Sdelphij            error = FAILURE;
894226026Sdelphij        }
895226026Sdelphij    }
896226026Sdelphij
897226026Sdelphij    free(req->data, M_TWS);
898226026Sdelphij    req->state = TWS_REQ_STATE_FREE;
899226026Sdelphij    return(error);
900226026Sdelphij
901226026Sdelphij}
902226026Sdelphij
903226026Sdelphijvoid
904226026Sdelphijtws_unmap_request(struct tws_softc *sc, struct tws_request *req)
905226026Sdelphij{
906226026Sdelphij    if (req->data != NULL) {
907226026Sdelphij        if ( req->flags & TWS_DIR_IN )
908226026Sdelphij            bus_dmamap_sync(sc->data_tag, req->dma_map,
909226026Sdelphij                                            BUS_DMASYNC_POSTREAD);
910226026Sdelphij        if ( req->flags & TWS_DIR_OUT )
911226026Sdelphij            bus_dmamap_sync(sc->data_tag, req->dma_map,
912226026Sdelphij                                            BUS_DMASYNC_POSTWRITE);
913226026Sdelphij        mtx_lock(&sc->io_lock);
914226026Sdelphij        bus_dmamap_unload(sc->data_tag, req->dma_map);
915226026Sdelphij        mtx_unlock(&sc->io_lock);
916226026Sdelphij    }
917226026Sdelphij}
918226026Sdelphij
919226026Sdelphijint32_t
920226026Sdelphijtws_map_request(struct tws_softc *sc, struct tws_request *req)
921226026Sdelphij{
922226026Sdelphij    int32_t error = 0;
923226026Sdelphij
924226026Sdelphij
925226026Sdelphij    /* If the command involves data, map that too. */
926226026Sdelphij    if (req->data != NULL) {
927226026Sdelphij        int my_flags = ((req->type == TWS_REQ_TYPE_SCSI_IO) ? BUS_DMA_WAITOK : BUS_DMA_NOWAIT);
928226026Sdelphij
929226026Sdelphij        /*
930226026Sdelphij         * Map the data buffer into bus space and build the SG list.
931226026Sdelphij         */
932226026Sdelphij        mtx_lock(&sc->io_lock);
933246713Skib	if (req->flags & TWS_DATA_CCB)
934246713Skib		error = bus_dmamap_load_ccb(sc->data_tag, req->dma_map,
935246713Skib					    req->data,
936246713Skib					    tws_dmamap_data_load_cbfn, req,
937246713Skib					    my_flags);
938246713Skib	else
939246713Skib		error = bus_dmamap_load(sc->data_tag, req->dma_map,
940246713Skib					req->data, req->length,
941246713Skib					tws_dmamap_data_load_cbfn, req,
942246713Skib					my_flags);
943226026Sdelphij        mtx_unlock(&sc->io_lock);
944226026Sdelphij
945226026Sdelphij        if (error == EINPROGRESS) {
946226026Sdelphij            TWS_TRACE(sc, "in progress", 0, error);
947226026Sdelphij            tws_freeze_simq(sc, req);
948241753Sdelphij            error = 0;  // EINPROGRESS is not a fatal error.
949226026Sdelphij        }
950226026Sdelphij    } else { /* no data involved */
951226026Sdelphij        error = tws_submit_command(sc, req);
952226026Sdelphij    }
953226026Sdelphij    return(error);
954226026Sdelphij}
955226026Sdelphij
956226026Sdelphij
957226026Sdelphijstatic void
958226026Sdelphijtws_dmamap_data_load_cbfn(void *arg, bus_dma_segment_t *segs,
959226026Sdelphij                            int nseg, int error)
960226026Sdelphij{
961226026Sdelphij    struct tws_request *req = (struct tws_request *)arg;
962226026Sdelphij    struct tws_softc *sc = req->sc;
963226026Sdelphij    u_int16_t sgls = nseg;
964226026Sdelphij    void *sgl_ptr;
965226026Sdelphij    struct tws_cmd_generic *gcmd;
966226026Sdelphij
967226026Sdelphij
968241753Sdelphij    if ( error ) {
969241753Sdelphij        TWS_TRACE(sc, "SOMETHING BAD HAPPENED! error = %d\n", error, 0);
970241753Sdelphij    }
971241753Sdelphij
972226026Sdelphij    if ( error == EFBIG ) {
973226026Sdelphij        TWS_TRACE(sc, "not enough data segs", 0, nseg);
974226026Sdelphij        req->error_code = error;
975226026Sdelphij        req->ccb_ptr->ccb_h.status = CAM_REQ_TOO_BIG;
976226026Sdelphij        return;
977226026Sdelphij    }
978226026Sdelphij
979226026Sdelphij    if ( req->flags & TWS_DIR_IN )
980226026Sdelphij        bus_dmamap_sync(req->sc->data_tag, req->dma_map,
981226026Sdelphij                                            BUS_DMASYNC_PREREAD);
982226026Sdelphij    if ( req->flags & TWS_DIR_OUT )
983226026Sdelphij        bus_dmamap_sync(req->sc->data_tag, req->dma_map,
984226026Sdelphij                                        BUS_DMASYNC_PREWRITE);
985226026Sdelphij    if ( segs ) {
986226026Sdelphij        if ( (req->type == TWS_REQ_TYPE_PASSTHRU &&
987226026Sdelphij             GET_OPCODE(req->cmd_pkt->cmd.pkt_a.res__opcode) !=
988226026Sdelphij                            TWS_FW_CMD_EXECUTE_SCSI) ||
989226026Sdelphij              req->type == TWS_REQ_TYPE_GETSET_PARAM) {
990226026Sdelphij            gcmd = &req->cmd_pkt->cmd.pkt_g.generic;
991226026Sdelphij            sgl_ptr = (u_int32_t *)(gcmd) + gcmd->size;
992226026Sdelphij            gcmd->size += sgls *
993241753Sdelphij                          ((req->sc->is64bit && !tws_use_32bit_sgls) ? 4 : 2 );
994226026Sdelphij            tws_fill_sg_list(req->sc, (void *)segs, sgl_ptr, sgls);
995226026Sdelphij
996226026Sdelphij        } else {
997226026Sdelphij            tws_fill_sg_list(req->sc, (void *)segs,
998241753Sdelphij                      (void *)&(req->cmd_pkt->cmd.pkt_a.sg_list), sgls);
999226026Sdelphij            req->cmd_pkt->cmd.pkt_a.lun_h4__sgl_entries |= sgls ;
1000226026Sdelphij        }
1001226026Sdelphij    }
1002226026Sdelphij
1003226026Sdelphij
1004226026Sdelphij    req->error_code = tws_submit_command(req->sc, req);
1005226026Sdelphij
1006226026Sdelphij}
1007226026Sdelphij
1008226026Sdelphij
1009226026Sdelphijstatic void
1010226026Sdelphijtws_fill_sg_list(struct tws_softc *sc, void *sgl_src, void *sgl_dest,
1011226026Sdelphij                          u_int16_t num_sgl_entries)
1012226026Sdelphij{
1013226026Sdelphij    int i;
1014226026Sdelphij
1015226026Sdelphij    if ( sc->is64bit ) {
1016226026Sdelphij        struct tws_sg_desc64 *sgl_s = (struct tws_sg_desc64 *)sgl_src;
1017226026Sdelphij
1018226026Sdelphij        if ( !tws_use_32bit_sgls ) {
1019226026Sdelphij            struct tws_sg_desc64 *sgl_d = (struct tws_sg_desc64 *)sgl_dest;
1020226026Sdelphij            if ( num_sgl_entries > TWS_MAX_64BIT_SG_ELEMENTS )
1021226026Sdelphij                TWS_TRACE(sc, "64bit sg overflow", num_sgl_entries, 0);
1022226026Sdelphij            for (i = 0; i < num_sgl_entries; i++) {
1023226026Sdelphij                sgl_d[i].address = sgl_s->address;
1024226026Sdelphij                sgl_d[i].length = sgl_s->length;
1025226026Sdelphij                sgl_d[i].flag = 0;
1026226026Sdelphij                sgl_d[i].reserved = 0;
1027226026Sdelphij                sgl_s = (struct tws_sg_desc64 *) (((u_int8_t *)sgl_s) +
1028226026Sdelphij                                               sizeof(bus_dma_segment_t));
1029226026Sdelphij            }
1030226026Sdelphij        } else {
1031226026Sdelphij            struct tws_sg_desc32 *sgl_d = (struct tws_sg_desc32 *)sgl_dest;
1032226026Sdelphij            if ( num_sgl_entries > TWS_MAX_32BIT_SG_ELEMENTS )
1033226026Sdelphij                TWS_TRACE(sc, "32bit sg overflow", num_sgl_entries, 0);
1034226026Sdelphij            for (i = 0; i < num_sgl_entries; i++) {
1035226026Sdelphij                sgl_d[i].address = sgl_s->address;
1036226026Sdelphij                sgl_d[i].length = sgl_s->length;
1037226026Sdelphij                sgl_d[i].flag = 0;
1038226026Sdelphij                sgl_s = (struct tws_sg_desc64 *) (((u_int8_t *)sgl_s) +
1039226026Sdelphij                                               sizeof(bus_dma_segment_t));
1040226026Sdelphij            }
1041226026Sdelphij        }
1042226026Sdelphij    } else {
1043226026Sdelphij        struct tws_sg_desc32 *sgl_s = (struct tws_sg_desc32 *)sgl_src;
1044226026Sdelphij        struct tws_sg_desc32 *sgl_d = (struct tws_sg_desc32 *)sgl_dest;
1045226026Sdelphij
1046226026Sdelphij        if ( num_sgl_entries > TWS_MAX_32BIT_SG_ELEMENTS )
1047226026Sdelphij            TWS_TRACE(sc, "32bit sg overflow", num_sgl_entries, 0);
1048226026Sdelphij
1049226026Sdelphij
1050226026Sdelphij        for (i = 0; i < num_sgl_entries; i++) {
1051226026Sdelphij            sgl_d[i].address = sgl_s[i].address;
1052226026Sdelphij            sgl_d[i].length = sgl_s[i].length;
1053226026Sdelphij            sgl_d[i].flag = 0;
1054226026Sdelphij        }
1055226026Sdelphij    }
1056226026Sdelphij}
1057226026Sdelphij
1058226026Sdelphij
1059226026Sdelphijvoid
1060226026Sdelphijtws_intr(void *arg)
1061226026Sdelphij{
1062226026Sdelphij    struct tws_softc *sc = (struct tws_softc *)arg;
1063226026Sdelphij    u_int32_t histat=0, db=0;
1064226026Sdelphij
1065226026Sdelphij    if (!(sc)) {
1066226026Sdelphij        device_printf(sc->tws_dev, "null softc!!!\n");
1067226026Sdelphij        return;
1068226026Sdelphij    }
1069226026Sdelphij
1070226026Sdelphij    if ( tws_get_state(sc) == TWS_RESET ) {
1071226026Sdelphij        return;
1072226026Sdelphij    }
1073226026Sdelphij
1074226026Sdelphij    if ( tws_get_state(sc) != TWS_ONLINE ) {
1075226026Sdelphij        return;
1076226026Sdelphij    }
1077226026Sdelphij
1078226026Sdelphij    sc->stats.num_intrs++;
1079226026Sdelphij    histat = tws_read_reg(sc, TWS_I2O0_HISTAT, 4);
1080226026Sdelphij    if ( histat & TWS_BIT2 ) {
1081226026Sdelphij        TWS_TRACE_DEBUG(sc, "door bell :)", histat, TWS_I2O0_HISTAT);
1082226026Sdelphij        db = tws_read_reg(sc, TWS_I2O0_IOBDB, 4);
1083226026Sdelphij        if ( db & TWS_BIT21 ) {
1084226026Sdelphij            tws_intr_attn_error(sc);
1085226026Sdelphij            return;
1086226026Sdelphij        }
1087226026Sdelphij        if ( db & TWS_BIT18 ) {
1088226026Sdelphij            tws_intr_attn_aen(sc);
1089226026Sdelphij        }
1090226026Sdelphij    }
1091226026Sdelphij
1092226026Sdelphij    if ( histat & TWS_BIT3 ) {
1093226026Sdelphij        tws_intr_resp(sc);
1094226026Sdelphij    }
1095226026Sdelphij}
1096226026Sdelphij
1097226026Sdelphijstatic void
1098226026Sdelphijtws_intr_attn_aen(struct tws_softc *sc)
1099226026Sdelphij{
1100226026Sdelphij    u_int32_t db=0;
1101226026Sdelphij
1102226026Sdelphij    /* maskoff db intrs untill all the aens are fetched */
1103226026Sdelphij    /* tws_disable_db_intr(sc); */
1104226026Sdelphij    tws_fetch_aen((void *)sc);
1105226026Sdelphij    tws_write_reg(sc, TWS_I2O0_HOBDBC, TWS_BIT18, 4);
1106226026Sdelphij    db = tws_read_reg(sc, TWS_I2O0_IOBDB, 4);
1107226026Sdelphij
1108226026Sdelphij}
1109226026Sdelphij
1110226026Sdelphijstatic void
1111226026Sdelphijtws_intr_attn_error(struct tws_softc *sc)
1112226026Sdelphij{
1113226026Sdelphij    u_int32_t db=0;
1114226026Sdelphij
1115226026Sdelphij    TWS_TRACE(sc, "attn error", 0, 0);
1116226026Sdelphij    tws_write_reg(sc, TWS_I2O0_HOBDBC, ~0, 4);
1117226026Sdelphij    db = tws_read_reg(sc, TWS_I2O0_IOBDB, 4);
1118226026Sdelphij    device_printf(sc->tws_dev, "Micro controller error.\n");
1119226026Sdelphij    tws_reset(sc);
1120226026Sdelphij}
1121226026Sdelphij
1122226026Sdelphijstatic void
1123226026Sdelphijtws_intr_resp(struct tws_softc *sc)
1124226026Sdelphij{
1125226026Sdelphij    u_int16_t req_id;
1126226026Sdelphij    u_int64_t mfa;
1127226026Sdelphij
1128226026Sdelphij    while ( tws_get_response(sc, &req_id, &mfa) ) {
1129226026Sdelphij        sc->stats.reqs_out++;
1130226026Sdelphij        if ( req_id == TWS_INVALID_REQID ) {
1131226026Sdelphij            TWS_TRACE_DEBUG(sc, "invalid req_id", mfa, req_id);
1132226026Sdelphij            sc->stats.reqs_errored++;
1133226026Sdelphij            tws_err_complete(sc, mfa);
1134226026Sdelphij            continue;
1135226026Sdelphij        }
1136226026Sdelphij        sc->reqs[req_id].cb(&sc->reqs[req_id]);
1137226026Sdelphij    }
1138226026Sdelphij
1139226026Sdelphij}
1140226026Sdelphij
1141226026Sdelphij
1142226026Sdelphijstatic void
1143226026Sdelphijtws_poll(struct cam_sim *sim)
1144226026Sdelphij{
1145226026Sdelphij    struct tws_softc *sc = (struct tws_softc *)cam_sim_softc(sim);
1146226026Sdelphij    TWS_TRACE_DEBUG(sc, "entry", 0, 0);
1147226026Sdelphij    tws_intr((void *) sc);
1148226026Sdelphij}
1149226026Sdelphij
1150226026Sdelphijvoid
1151226026Sdelphijtws_timeout(void *arg)
1152226026Sdelphij{
1153226026Sdelphij    struct tws_request *req = (struct tws_request *)arg;
1154226026Sdelphij    struct tws_softc *sc = req->sc;
1155226026Sdelphij
1156226026Sdelphij
1157226026Sdelphij    if ( req->error_code == TWS_REQ_RET_RESET ) {
1158226026Sdelphij        return;
1159226026Sdelphij    }
1160226026Sdelphij
1161226026Sdelphij    mtx_lock(&sc->gen_lock);
1162226026Sdelphij    if ( req->error_code == TWS_REQ_RET_RESET ) {
1163226026Sdelphij        mtx_unlock(&sc->gen_lock);
1164226026Sdelphij        return;
1165226026Sdelphij    }
1166226026Sdelphij
1167226026Sdelphij    if ( tws_get_state(sc) == TWS_RESET ) {
1168226026Sdelphij        mtx_unlock(&sc->gen_lock);
1169226026Sdelphij        return;
1170226026Sdelphij    }
1171226026Sdelphij
1172226026Sdelphij    xpt_freeze_simq(sc->sim, 1);
1173226026Sdelphij
1174226026Sdelphij    tws_send_event(sc, TWS_RESET_START);
1175226026Sdelphij
1176226026Sdelphij    if (req->type == TWS_REQ_TYPE_SCSI_IO) {
1177226026Sdelphij        device_printf(sc->tws_dev, "I/O Request timed out... Resetting controller\n");
1178226026Sdelphij    } else if (req->type == TWS_REQ_TYPE_PASSTHRU) {
1179226026Sdelphij        device_printf(sc->tws_dev, "IOCTL Request timed out... Resetting controller\n");
1180226026Sdelphij    } else {
1181226026Sdelphij        device_printf(sc->tws_dev, "Internal Request timed out... Resetting controller\n");
1182226026Sdelphij    }
1183226026Sdelphij
1184226026Sdelphij    tws_assert_soft_reset(sc);
1185226026Sdelphij    tws_turn_off_interrupts(sc);
1186226026Sdelphij    tws_reset_cb( (void*) sc );
1187226026Sdelphij    tws_reinit( (void*) sc );
1188226026Sdelphij
1189226026Sdelphij//  device_printf(sc->tws_dev,  "Controller Reset complete!\n");
1190226026Sdelphij    tws_send_event(sc, TWS_RESET_COMPLETE);
1191226026Sdelphij    mtx_unlock(&sc->gen_lock);
1192226026Sdelphij
1193226026Sdelphij    xpt_release_simq(sc->sim, 1);
1194226026Sdelphij}
1195226026Sdelphij
1196226026Sdelphijvoid
1197226026Sdelphijtws_reset(void *arg)
1198226026Sdelphij{
1199226026Sdelphij    struct tws_softc *sc = (struct tws_softc *)arg;
1200226026Sdelphij
1201226026Sdelphij    mtx_lock(&sc->gen_lock);
1202226026Sdelphij    if ( tws_get_state(sc) == TWS_RESET ) {
1203226026Sdelphij        mtx_unlock(&sc->gen_lock);
1204226026Sdelphij        return;
1205226026Sdelphij    }
1206226026Sdelphij
1207226026Sdelphij    xpt_freeze_simq(sc->sim, 1);
1208226026Sdelphij
1209226026Sdelphij    tws_send_event(sc, TWS_RESET_START);
1210226026Sdelphij
1211226026Sdelphij    device_printf(sc->tws_dev,  "Resetting controller\n");
1212226026Sdelphij
1213226026Sdelphij    tws_assert_soft_reset(sc);
1214226026Sdelphij    tws_turn_off_interrupts(sc);
1215226026Sdelphij    tws_reset_cb( (void*) sc );
1216226026Sdelphij    tws_reinit( (void*) sc );
1217226026Sdelphij
1218226026Sdelphij//  device_printf(sc->tws_dev,  "Controller Reset complete!\n");
1219226026Sdelphij    tws_send_event(sc, TWS_RESET_COMPLETE);
1220226026Sdelphij    mtx_unlock(&sc->gen_lock);
1221226026Sdelphij
1222226026Sdelphij    xpt_release_simq(sc->sim, 1);
1223226026Sdelphij}
1224226026Sdelphij
1225226026Sdelphijstatic void
1226226026Sdelphijtws_reset_cb(void *arg)
1227226026Sdelphij{
1228226026Sdelphij    struct tws_softc *sc = (struct tws_softc *)arg;
1229226026Sdelphij    time_t endt;
1230226026Sdelphij    int found = 0;
1231226026Sdelphij    u_int32_t reg;
1232226026Sdelphij
1233226026Sdelphij    if ( tws_get_state(sc) != TWS_RESET ) {
1234226026Sdelphij        return;
1235226026Sdelphij    }
1236226026Sdelphij
1237226026Sdelphij//  device_printf(sc->tws_dev,  "Draining Busy Queue\n");
1238226026Sdelphij    tws_drain_busy_queue(sc);
1239226026Sdelphij//  device_printf(sc->tws_dev,  "Draining Reserved Reqs\n");
1240226026Sdelphij    tws_drain_reserved_reqs(sc);
1241226026Sdelphij//  device_printf(sc->tws_dev,  "Draining Response Queue\n");
1242226026Sdelphij    tws_drain_response_queue(sc);
1243226026Sdelphij
1244226026Sdelphij//  device_printf(sc->tws_dev,  "Looking for controller ready flag...\n");
1245226026Sdelphij    endt = TWS_LOCAL_TIME + TWS_POLL_TIMEOUT;
1246226026Sdelphij    while ((TWS_LOCAL_TIME <= endt) && (!found)) {
1247226026Sdelphij        reg = tws_read_reg(sc, TWS_I2O0_SCRPD3, 4);
1248226026Sdelphij        if ( reg & TWS_BIT13 ) {
1249226026Sdelphij            found = 1;
1250226026Sdelphij//          device_printf(sc->tws_dev,  " ... Got it!\n");
1251226026Sdelphij        }
1252226026Sdelphij    }
1253226026Sdelphij    if ( !found )
1254226026Sdelphij            device_printf(sc->tws_dev,  " ... Controller ready flag NOT found!\n");
1255226026Sdelphij}
1256226026Sdelphij
1257226026Sdelphijstatic void
1258226026Sdelphijtws_reinit(void *arg)
1259226026Sdelphij{
1260226026Sdelphij    struct tws_softc *sc = (struct tws_softc *)arg;
1261226026Sdelphij    int timeout_val=0;
1262226026Sdelphij    int try=2;
1263226026Sdelphij    int done=0;
1264226026Sdelphij
1265226026Sdelphij
1266226026Sdelphij//  device_printf(sc->tws_dev,  "Waiting for Controller Ready\n");
1267226026Sdelphij    while ( !done && try ) {
1268226026Sdelphij        if ( tws_ctlr_ready(sc) ) {
1269226026Sdelphij            done = 1;
1270226026Sdelphij            break;
1271226026Sdelphij        } else {
1272226026Sdelphij            timeout_val += 5;
1273226026Sdelphij            if ( timeout_val >= TWS_RESET_TIMEOUT ) {
1274226026Sdelphij               timeout_val = 0;
1275226026Sdelphij               if ( try )
1276226026Sdelphij                   tws_assert_soft_reset(sc);
1277226026Sdelphij               try--;
1278226026Sdelphij            }
1279226026Sdelphij            mtx_sleep(sc, &sc->gen_lock, 0, "tws_reinit", 5*hz);
1280226026Sdelphij        }
1281226026Sdelphij    }
1282226026Sdelphij
1283226026Sdelphij    if (!done) {
1284226026Sdelphij        device_printf(sc->tws_dev,  "FAILED to get Controller Ready!\n");
1285226026Sdelphij        return;
1286226026Sdelphij    }
1287226026Sdelphij
1288226026Sdelphij    sc->obfl_q_overrun = false;
1289226026Sdelphij//  device_printf(sc->tws_dev,  "Sending initConnect\n");
1290226026Sdelphij    if ( tws_init_connect(sc, tws_queue_depth) ) {
1291226026Sdelphij        TWS_TRACE_DEBUG(sc, "initConnect failed", 0, sc->is64bit);
1292226026Sdelphij    }
1293226026Sdelphij    tws_init_obfl_q(sc);
1294226026Sdelphij
1295226026Sdelphij    tws_turn_on_interrupts(sc);
1296226026Sdelphij
1297263125Sdelphij    wakeup_one(sc);
1298226026Sdelphij}
1299226026Sdelphij
1300226026Sdelphij
1301226026Sdelphijstatic void
1302226026Sdelphijtws_freeze_simq(struct tws_softc *sc, struct tws_request *req)
1303226026Sdelphij{
1304226026Sdelphij    /* Only for IO commands */
1305226026Sdelphij    if (req->type == TWS_REQ_TYPE_SCSI_IO) {
1306226026Sdelphij        union ccb   *ccb = (union ccb *)(req->ccb_ptr);
1307226026Sdelphij
1308226026Sdelphij        xpt_freeze_simq(sc->sim, 1);
1309226026Sdelphij        ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
1310226026Sdelphij        ccb->ccb_h.status |= CAM_REQUEUE_REQ;
1311226026Sdelphij    }
1312226026Sdelphij}
1313226026Sdelphij
1314226026Sdelphij
1315226026SdelphijTUNABLE_INT("hw.tws.cam_depth", &tws_cam_depth);
1316