1144966Svkashyap/*
2169400Sscottl * Copyright (c) 2004-07 Applied Micro Circuits Corporation.
3144966Svkashyap * Copyright (c) 2004-05 Vinod Kashyap.
4144966Svkashyap * All rights reserved.
5144966Svkashyap *
6144966Svkashyap * Redistribution and use in source and binary forms, with or without
7144966Svkashyap * modification, are permitted provided that the following conditions
8144966Svkashyap * are met:
9144966Svkashyap * 1. Redistributions of source code must retain the above copyright
10144966Svkashyap *    notice, this list of conditions and the following disclaimer.
11144966Svkashyap * 2. Redistributions in binary form must reproduce the above copyright
12144966Svkashyap *    notice, this list of conditions and the following disclaimer in the
13144966Svkashyap *    documentation and/or other materials provided with the distribution.
14144966Svkashyap *
15144966Svkashyap * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16144966Svkashyap * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17144966Svkashyap * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18144966Svkashyap * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19144966Svkashyap * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20144966Svkashyap * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21144966Svkashyap * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22144966Svkashyap * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23144966Svkashyap * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24144966Svkashyap * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25144966Svkashyap * SUCH DAMAGE.
26144966Svkashyap *
27144966Svkashyap *	$FreeBSD$
28144966Svkashyap */
29144966Svkashyap
30144966Svkashyap/*
31144966Svkashyap * AMCC'S 3ware driver for 9000 series storage controllers.
32144966Svkashyap *
33144966Svkashyap * Author: Vinod Kashyap
34169400Sscottl * Modifications by: Adam Radford
35172496Sscottl * Modifications by: Manjunath Ranganathaiah
36144966Svkashyap */
37144966Svkashyap
38144966Svkashyap
39144966Svkashyap/*
40144966Svkashyap * FreeBSD CAM related functions.
41144966Svkashyap */
42144966Svkashyap
43144966Svkashyap
44149968Sobrien#include <dev/twa/tw_osl_includes.h>
45144966Svkashyap
46144966Svkashyap#include <cam/cam.h>
47144966Svkashyap#include <cam/cam_ccb.h>
48144966Svkashyap#include <cam/cam_sim.h>
49144966Svkashyap#include <cam/cam_xpt_sim.h>
50144966Svkashyap#include <cam/cam_debug.h>
51144966Svkashyap#include <cam/cam_periph.h>
52144966Svkashyap
53144966Svkashyap#include <cam/scsi/scsi_all.h>
54144966Svkashyap#include <cam/scsi/scsi_message.h>
55144966Svkashyap
56144966Svkashyapstatic TW_VOID	twa_action(struct cam_sim *sim, union ccb *ccb);
57144966Svkashyapstatic TW_VOID	twa_poll(struct cam_sim *sim);
58144966Svkashyap
59144966Svkashyapstatic TW_INT32	tw_osli_execute_scsi(struct tw_osli_req_context *req,
60144966Svkashyap	union ccb *ccb);
61144966Svkashyap
62144966Svkashyap
63144966Svkashyap
64144966Svkashyap/*
65144966Svkashyap * Function name:	tw_osli_cam_attach
66144966Svkashyap * Description:		Attaches the driver to CAM.
67144966Svkashyap *
68144966Svkashyap * Input:		sc	-- ptr to OSL internal ctlr context
69144966Svkashyap * Output:		None
70144966Svkashyap * Return value:	0	-- success
71144966Svkashyap *			non-zero-- failure
72144966Svkashyap */
73144966SvkashyapTW_INT32
74144966Svkashyaptw_osli_cam_attach(struct twa_softc *sc)
75144966Svkashyap{
76144966Svkashyap	struct cam_devq		*devq;
77144966Svkashyap
78144966Svkashyap	tw_osli_dbg_dprintf(3, sc, "entered");
79144966Svkashyap
80144966Svkashyap	/*
81144966Svkashyap	 * Create the device queue for our SIM.
82144966Svkashyap	 */
83212008Sdelphij	if ((devq = cam_simq_alloc(TW_OSLI_MAX_NUM_IOS)) == NULL) {
84144966Svkashyap		tw_osli_printf(sc, "error = %d",
85144966Svkashyap			TW_CL_SEVERITY_ERROR_STRING,
86144966Svkashyap			TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
87144966Svkashyap			0x2100,
88144966Svkashyap			"Failed to create SIM device queue",
89144966Svkashyap			ENOMEM);
90144966Svkashyap		return(ENOMEM);
91144966Svkashyap	}
92144966Svkashyap
93144966Svkashyap	/*
94208969Sdelphij	 * Create a SIM entry.  Though we can support TW_OSLI_MAX_NUM_REQUESTS
95144966Svkashyap	 * simultaneous requests, we claim to be able to handle only
96208969Sdelphij	 * TW_OSLI_MAX_NUM_IOS (two less), so that we always have a request
97208969Sdelphij	 * packet available to service ioctls and AENs.
98144966Svkashyap	 */
99144966Svkashyap	tw_osli_dbg_dprintf(3, sc, "Calling cam_sim_alloc");
100144966Svkashyap	sc->sim = cam_sim_alloc(twa_action, twa_poll, "twa", sc,
101172496Sscottl			device_get_unit(sc->bus_dev), sc->sim_lock,
102208969Sdelphij			TW_OSLI_MAX_NUM_IOS, 1, devq);
103144966Svkashyap	if (sc->sim == NULL) {
104144966Svkashyap		cam_simq_free(devq);
105144966Svkashyap		tw_osli_printf(sc, "error = %d",
106144966Svkashyap			TW_CL_SEVERITY_ERROR_STRING,
107144966Svkashyap			TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
108144966Svkashyap			0x2101,
109144966Svkashyap			"Failed to create a SIM entry",
110144966Svkashyap			ENOMEM);
111144966Svkashyap		return(ENOMEM);
112144966Svkashyap	}
113144966Svkashyap
114144966Svkashyap	/*
115144966Svkashyap	 * Register the bus.
116144966Svkashyap	 */
117144966Svkashyap	tw_osli_dbg_dprintf(3, sc, "Calling xpt_bus_register");
118172496Sscottl	mtx_lock(sc->sim_lock);
119170872Sscottl	if (xpt_bus_register(sc->sim, sc->bus_dev, 0) != CAM_SUCCESS) {
120144966Svkashyap		cam_sim_free(sc->sim, TRUE);
121144966Svkashyap		sc->sim = NULL; /* so cam_detach will not try to free it */
122144966Svkashyap		tw_osli_printf(sc, "error = %d",
123144966Svkashyap			TW_CL_SEVERITY_ERROR_STRING,
124144966Svkashyap			TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
125144966Svkashyap			0x2102,
126144966Svkashyap			"Failed to register the bus",
127144966Svkashyap			ENXIO);
128172496Sscottl		mtx_unlock(sc->sim_lock);
129144966Svkashyap		return(ENXIO);
130144966Svkashyap	}
131144966Svkashyap
132144966Svkashyap	tw_osli_dbg_dprintf(3, sc, "Calling xpt_create_path");
133144966Svkashyap	if (xpt_create_path(&sc->path, NULL,
134144966Svkashyap				cam_sim_path(sc->sim),
135144966Svkashyap				CAM_TARGET_WILDCARD,
136144966Svkashyap				CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
137144966Svkashyap		xpt_bus_deregister(cam_sim_path (sc->sim));
138144966Svkashyap		/* Passing TRUE to cam_sim_free will free the devq as well. */
139144966Svkashyap		cam_sim_free(sc->sim, TRUE);
140144966Svkashyap		tw_osli_printf(sc, "error = %d",
141144966Svkashyap			TW_CL_SEVERITY_ERROR_STRING,
142144966Svkashyap			TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
143144966Svkashyap			0x2103,
144144966Svkashyap			"Failed to create path",
145144966Svkashyap			ENXIO);
146172496Sscottl		mtx_unlock(sc->sim_lock);
147144966Svkashyap		return(ENXIO);
148144966Svkashyap	}
149172496Sscottl	mtx_unlock(sc->sim_lock);
150144966Svkashyap
151144966Svkashyap	tw_osli_dbg_dprintf(3, sc, "exiting");
152144966Svkashyap	return(0);
153144966Svkashyap}
154144966Svkashyap
155144966Svkashyap
156144966Svkashyap
157144966Svkashyap/*
158144966Svkashyap * Function name:	tw_osli_cam_detach
159144966Svkashyap * Description:		Detaches the driver from CAM.
160144966Svkashyap *
161144966Svkashyap * Input:		sc	-- ptr to OSL internal ctlr context
162144966Svkashyap * Output:		None
163144966Svkashyap * Return value:	None
164144966Svkashyap */
165144966SvkashyapTW_VOID
166144966Svkashyaptw_osli_cam_detach(struct twa_softc *sc)
167144966Svkashyap{
168144966Svkashyap	tw_osli_dbg_dprintf(3, sc, "entered");
169144966Svkashyap
170172496Sscottl	mtx_lock(sc->sim_lock);
171172496Sscottl
172144966Svkashyap	if (sc->path)
173144966Svkashyap		xpt_free_path(sc->path);
174144966Svkashyap	if (sc->sim) {
175144966Svkashyap		xpt_bus_deregister(cam_sim_path(sc->sim));
176144966Svkashyap		/* Passing TRUE to cam_sim_free will free the devq as well. */
177144966Svkashyap		cam_sim_free(sc->sim, TRUE);
178144966Svkashyap	}
179172496Sscottl	/* It's ok have 1 hold count while destroying the mutex */
180172496Sscottl	mtx_destroy(sc->sim_lock);
181144966Svkashyap}
182144966Svkashyap
183144966Svkashyap
184144966Svkashyap
185144966Svkashyap/*
186144966Svkashyap * Function name:	tw_osli_execute_scsi
187144966Svkashyap * Description:		Build a fw cmd, based on a CAM style ccb, and
188144966Svkashyap *			send it down.
189144966Svkashyap *
190144966Svkashyap * Input:		req	-- ptr to OSL internal request context
191144966Svkashyap *			ccb	-- ptr to CAM style ccb
192144966Svkashyap * Output:		None
193144966Svkashyap * Return value:	0	-- success
194144966Svkashyap *			non-zero-- failure
195144966Svkashyap */
196144966SvkashyapTW_INT32
197144966Svkashyaptw_osli_execute_scsi(struct tw_osli_req_context *req, union ccb *ccb)
198144966Svkashyap{
199144966Svkashyap	struct twa_softc		*sc = req->ctlr;
200144966Svkashyap	struct tw_cl_req_packet		*req_pkt;
201144966Svkashyap	struct tw_cl_scsi_req_packet	*scsi_req;
202144966Svkashyap	struct ccb_hdr			*ccb_h = &(ccb->ccb_h);
203144966Svkashyap	struct ccb_scsiio		*csio = &(ccb->csio);
204144966Svkashyap	TW_INT32			error;
205144966Svkashyap
206144966Svkashyap	tw_osli_dbg_dprintf(10, sc, "SCSI I/O request 0x%x",
207144966Svkashyap		csio->cdb_io.cdb_bytes[0]);
208144966Svkashyap
209144966Svkashyap	if (ccb_h->target_id >= TW_CL_MAX_NUM_UNITS) {
210144966Svkashyap		tw_osli_dbg_dprintf(3, sc, "Invalid target. PTL = %x %x %x",
211144966Svkashyap			ccb_h->path_id, ccb_h->target_id, ccb_h->target_lun);
212144966Svkashyap		ccb_h->status |= CAM_TID_INVALID;
213144966Svkashyap		xpt_done(ccb);
214144966Svkashyap		return(1);
215144966Svkashyap	}
216144966Svkashyap	if (ccb_h->target_lun >= TW_CL_MAX_NUM_LUNS) {
217144966Svkashyap		tw_osli_dbg_dprintf(3, sc, "Invalid lun. PTL = %x %x %x",
218144966Svkashyap			ccb_h->path_id, ccb_h->target_id, ccb_h->target_lun);
219144966Svkashyap		ccb_h->status |= CAM_LUN_INVALID;
220144966Svkashyap		xpt_done(ccb);
221144966Svkashyap		return(1);
222144966Svkashyap	}
223144966Svkashyap
224144966Svkashyap	if(ccb_h->flags & CAM_CDB_PHYS) {
225144966Svkashyap		tw_osli_printf(sc, "",
226144966Svkashyap			TW_CL_SEVERITY_ERROR_STRING,
227144966Svkashyap			TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
228144966Svkashyap			0x2105,
229144966Svkashyap			"Physical CDB address!");
230208969Sdelphij		ccb_h->status = CAM_REQ_INVALID;
231144966Svkashyap		xpt_done(ccb);
232144966Svkashyap		return(1);
233144966Svkashyap	}
234144966Svkashyap
235144966Svkashyap	/*
236144966Svkashyap	 * We are going to work on this request.  Mark it as enqueued (though
237144966Svkashyap	 * we don't actually queue it...)
238144966Svkashyap	 */
239144966Svkashyap	ccb_h->status |= CAM_SIM_QUEUED;
240144966Svkashyap
241144966Svkashyap	if((ccb_h->flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
242144966Svkashyap		if(ccb_h->flags & CAM_DIR_IN)
243144966Svkashyap			req->flags |= TW_OSLI_REQ_FLAGS_DATA_IN;
244144966Svkashyap		else
245144966Svkashyap			req->flags |= TW_OSLI_REQ_FLAGS_DATA_OUT;
246144966Svkashyap	}
247144966Svkashyap
248144966Svkashyap	/* Build the CL understood request packet for SCSI cmds. */
249144966Svkashyap	req_pkt = &req->req_pkt;
250144966Svkashyap	req_pkt->status = 0;
251144966Svkashyap	req_pkt->tw_osl_callback = tw_osl_complete_io;
252144966Svkashyap	scsi_req = &(req_pkt->gen_req_pkt.scsi_req);
253144966Svkashyap	scsi_req->unit = ccb_h->target_id;
254144966Svkashyap	scsi_req->lun = ccb_h->target_lun;
255144966Svkashyap	scsi_req->sense_len = 0;
256144966Svkashyap	scsi_req->sense_data = (TW_UINT8 *)(&csio->sense_data);
257144966Svkashyap	scsi_req->scsi_status = 0;
258144966Svkashyap	if(ccb_h->flags & CAM_CDB_POINTER)
259144966Svkashyap		scsi_req->cdb = csio->cdb_io.cdb_ptr;
260144966Svkashyap	else
261144966Svkashyap		scsi_req->cdb = csio->cdb_io.cdb_bytes;
262144966Svkashyap	scsi_req->cdb_len = csio->cdb_len;
263144966Svkashyap
264246713Skib	if (csio->dxfer_len > TW_CL_MAX_IO_SIZE) {
265246713Skib		tw_osli_printf(sc, "size = %d",
266144966Svkashyap			TW_CL_SEVERITY_ERROR_STRING,
267144966Svkashyap			TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
268246713Skib			0x2106,
269246713Skib			"I/O size too big",
270246713Skib			csio->dxfer_len);
271246713Skib		ccb_h->status = CAM_REQ_TOO_BIG;
272144966Svkashyap		ccb_h->status &= ~CAM_SIM_QUEUED;
273144966Svkashyap		xpt_done(ccb);
274144966Svkashyap		return(1);
275144966Svkashyap	}
276248583Skib	if ((ccb_h->flags & CAM_DATA_MASK) == CAM_DATA_VADDR) {
277248583Skib		if ((req->length = csio->dxfer_len) != 0) {
278248583Skib			req->data = csio->data_ptr;
279248583Skib			scsi_req->sgl_entries = 1;
280248583Skib		}
281248583Skib	} else
282248583Skib		req->flags |= TW_OSLI_REQ_FLAGS_CCB;
283212008Sdelphij	req->deadline = tw_osl_get_local_time() + (ccb_h->timeout / 1000);
284212008Sdelphij
285144966Svkashyap	/*
286144966Svkashyap	 * twa_map_load_data_callback will fill in the SGL,
287144966Svkashyap	 * and submit the I/O.
288144966Svkashyap	 */
289144966Svkashyap	error = tw_osli_map_request(req);
290212008Sdelphij	if ((error) && (req->flags & TW_OSLI_REQ_FLAGS_FAILED)) {
291212008Sdelphij		req->deadline = 0;
292212008Sdelphij		ccb_h->status = CAM_REQ_CMP_ERR;
293212008Sdelphij		ccb_h->status &= ~CAM_SIM_QUEUED;
294212008Sdelphij		xpt_done(ccb);
295212008Sdelphij	}
296144966Svkashyap	return(error);
297144966Svkashyap}
298144966Svkashyap
299144966Svkashyap
300144966Svkashyap
301144966Svkashyap/*
302144966Svkashyap * Function name:	twa_action
303144966Svkashyap * Description:		Driver entry point for CAM's use.
304144966Svkashyap *
305144966Svkashyap * Input:		sim	-- sim corresponding to the ctlr
306144966Svkashyap *			ccb	-- ptr to CAM request
307144966Svkashyap * Output:		None
308144966Svkashyap * Return value:	None
309144966Svkashyap */
310144966SvkashyapTW_VOID
311144966Svkashyaptwa_action(struct cam_sim *sim, union ccb *ccb)
312144966Svkashyap{
313144966Svkashyap	struct twa_softc	*sc = (struct twa_softc *)cam_sim_softc(sim);
314144966Svkashyap	struct ccb_hdr		*ccb_h = &(ccb->ccb_h);
315144966Svkashyap
316144966Svkashyap	switch (ccb_h->func_code) {
317144966Svkashyap	case XPT_SCSI_IO:	/* SCSI I/O */
318144966Svkashyap	{
319144966Svkashyap		struct tw_osli_req_context	*req;
320144966Svkashyap
321208969Sdelphij		req = tw_osli_get_request(sc);
322208969Sdelphij		if (req == NULL) {
323208969Sdelphij			tw_osli_dbg_dprintf(2, sc, "Cannot get request pkt.");
324144966Svkashyap			/*
325144966Svkashyap			 * Freeze the simq to maintain ccb ordering.  The next
326144966Svkashyap			 * ccb that gets completed will unfreeze the simq.
327144966Svkashyap			 */
328212008Sdelphij			ccb_h->status &= ~CAM_SIM_QUEUED;
329144966Svkashyap			ccb_h->status |= CAM_REQUEUE_REQ;
330144966Svkashyap			xpt_done(ccb);
331144966Svkashyap			break;
332144966Svkashyap		}
333212008Sdelphij
334212008Sdelphij		if ((tw_cl_is_reset_needed(&(req->ctlr->ctlr_handle)))) {
335212008Sdelphij			ccb_h->status &= ~CAM_SIM_QUEUED;
336212008Sdelphij			ccb_h->status |= CAM_REQUEUE_REQ;
337212008Sdelphij			xpt_done(ccb);
338212008Sdelphij			tw_osli_req_q_insert_tail(req, TW_OSLI_FREE_Q);
339212008Sdelphij			break;
340212008Sdelphij		}
341212008Sdelphij
342144966Svkashyap		req->req_handle.osl_req_ctxt = req;
343208969Sdelphij		req->req_handle.is_io = TW_CL_TRUE;
344144966Svkashyap		req->orig_req = ccb;
345144966Svkashyap		if (tw_osli_execute_scsi(req, ccb))
346144966Svkashyap			tw_osli_req_q_insert_tail(req, TW_OSLI_FREE_Q);
347144966Svkashyap		break;
348144966Svkashyap	}
349144966Svkashyap
350144966Svkashyap	case XPT_ABORT:
351144966Svkashyap		tw_osli_dbg_dprintf(2, sc, "Abort request.");
352144966Svkashyap		ccb_h->status = CAM_UA_ABORT;
353144966Svkashyap		xpt_done(ccb);
354144966Svkashyap		break;
355144966Svkashyap
356144966Svkashyap	case XPT_RESET_BUS:
357212008Sdelphij		tw_cl_create_event(&(sc->ctlr_handle), TW_CL_FALSE,
358144966Svkashyap			TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
359144966Svkashyap			0x2108, 0x3, TW_CL_SEVERITY_INFO_STRING,
360144966Svkashyap			"Received Reset Bus request from CAM",
361144966Svkashyap			" ");
362144966Svkashyap
363212008Sdelphij		tw_cl_set_reset_needed(&(sc->ctlr_handle));
364212008Sdelphij		ccb_h->status = CAM_REQ_CMP;
365144966Svkashyap		xpt_done(ccb);
366144966Svkashyap		break;
367144966Svkashyap
368144966Svkashyap	case XPT_SET_TRAN_SETTINGS:
369144966Svkashyap		tw_osli_dbg_dprintf(3, sc, "XPT_SET_TRAN_SETTINGS");
370144966Svkashyap
371144966Svkashyap		/*
372144966Svkashyap		 * This command is not supported, since it's very specific
373144966Svkashyap		 * to SCSI, and we are doing ATA.
374144966Svkashyap		 */
375144966Svkashyap  		ccb_h->status = CAM_FUNC_NOTAVAIL;
376144966Svkashyap  		xpt_done(ccb);
377144966Svkashyap  		break;
378144966Svkashyap
379144966Svkashyap	case XPT_GET_TRAN_SETTINGS:
380144966Svkashyap	{
381144966Svkashyap		struct ccb_trans_settings	*cts = &ccb->cts;
382163816Smjacob		struct ccb_trans_settings_scsi *scsi =
383163816Smjacob		    &cts->proto_specific.scsi;
384163816Smjacob		struct ccb_trans_settings_spi *spi =
385163816Smjacob		    &cts->xport_specific.spi;
386144966Svkashyap
387163816Smjacob		cts->protocol = PROTO_SCSI;
388163816Smjacob		cts->protocol_version = SCSI_REV_2;
389163816Smjacob		cts->transport = XPORT_SPI;
390163816Smjacob		cts->transport_version = 2;
391163816Smjacob
392163816Smjacob		spi->valid = CTS_SPI_VALID_DISC;
393163816Smjacob		spi->flags = CTS_SPI_FLAGS_DISC_ENB;
394163816Smjacob		scsi->valid = CTS_SCSI_VALID_TQ;
395163816Smjacob		scsi->flags = CTS_SCSI_FLAGS_TAG_ENB;
396163816Smjacob		tw_osli_dbg_dprintf(3, sc, "XPT_GET_TRAN_SETTINGS");
397144966Svkashyap		ccb_h->status = CAM_REQ_CMP;
398144966Svkashyap		xpt_done(ccb);
399144966Svkashyap		break;
400144966Svkashyap	}
401144966Svkashyap
402144966Svkashyap	case XPT_CALC_GEOMETRY:
403144966Svkashyap		tw_osli_dbg_dprintf(3, sc, "XPT_CALC_GEOMETRY");
404144966Svkashyap		cam_calc_geometry(&ccb->ccg, 1/* extended */);
405144966Svkashyap		xpt_done(ccb);
406144966Svkashyap		break;
407144966Svkashyap
408144966Svkashyap	case XPT_PATH_INQ:    /* Path inquiry -- get twa properties */
409144966Svkashyap	{
410144966Svkashyap		struct ccb_pathinq	*path_inq = &ccb->cpi;
411144966Svkashyap
412144966Svkashyap		tw_osli_dbg_dprintf(3, sc, "XPT_PATH_INQ request");
413144966Svkashyap
414144966Svkashyap		path_inq->version_num = 1;
415144966Svkashyap		path_inq->hba_inquiry = 0;
416144966Svkashyap		path_inq->target_sprt = 0;
417144966Svkashyap		path_inq->hba_misc = 0;
418144966Svkashyap		path_inq->hba_eng_cnt = 0;
419144966Svkashyap		path_inq->max_target = TW_CL_MAX_NUM_UNITS;
420144966Svkashyap		path_inq->max_lun = TW_CL_MAX_NUM_LUNS - 1;
421144966Svkashyap		path_inq->unit_number = cam_sim_unit(sim);
422144966Svkashyap		path_inq->bus_id = cam_sim_bus(sim);
423152213Svkashyap		path_inq->initiator_id = TW_CL_MAX_NUM_UNITS;
424144966Svkashyap		path_inq->base_transfer_speed = 100000;
425144966Svkashyap		strncpy(path_inq->sim_vid, "FreeBSD", SIM_IDLEN);
426144966Svkashyap		strncpy(path_inq->hba_vid, "3ware", HBA_IDLEN);
427144966Svkashyap		strncpy(path_inq->dev_name, cam_sim_name(sim), DEV_IDLEN);
428163816Smjacob                path_inq->transport = XPORT_SPI;
429163816Smjacob                path_inq->transport_version = 2;
430163816Smjacob                path_inq->protocol = PROTO_SCSI;
431163816Smjacob                path_inq->protocol_version = SCSI_REV_2;
432212008Sdelphij                path_inq->maxio = TW_CL_MAX_IO_SIZE;
433144966Svkashyap		ccb_h->status = CAM_REQ_CMP;
434144966Svkashyap		xpt_done(ccb);
435144966Svkashyap		break;
436144966Svkashyap	}
437144966Svkashyap
438144966Svkashyap	default:
439144966Svkashyap		tw_osli_dbg_dprintf(3, sc, "func_code = %x", ccb_h->func_code);
440144966Svkashyap		ccb_h->status = CAM_REQ_INVALID;
441144966Svkashyap		xpt_done(ccb);
442144966Svkashyap		break;
443144966Svkashyap	}
444144966Svkashyap}
445144966Svkashyap
446144966Svkashyap
447144966Svkashyap
448144966Svkashyap/*
449144966Svkashyap * Function name:	twa_poll
450144966Svkashyap * Description:		Driver entry point called when interrupts are not
451144966Svkashyap *			available.
452144966Svkashyap *
453144966Svkashyap * Input:		sim	-- sim corresponding to the controller
454144966Svkashyap * Output:		None
455144966Svkashyap * Return value:	None
456144966Svkashyap */
457144966SvkashyapTW_VOID
458144966Svkashyaptwa_poll(struct cam_sim *sim)
459144966Svkashyap{
460144966Svkashyap	struct twa_softc *sc = (struct twa_softc *)(cam_sim_softc(sim));
461144966Svkashyap
462144966Svkashyap	tw_osli_dbg_dprintf(3, sc, "entering; sc = %p", sc);
463145688Svkashyap	tw_cl_interrupt(&(sc->ctlr_handle));
464144966Svkashyap	tw_osli_dbg_dprintf(3, sc, "exiting; sc = %p", sc);
465144966Svkashyap}
466144966Svkashyap
467144966Svkashyap
468144966Svkashyap
469144966Svkashyap/*
470144966Svkashyap * Function name:	tw_osli_request_bus_scan
471144966Svkashyap * Description:		Requests CAM for a scan of the bus.
472144966Svkashyap *
473144966Svkashyap * Input:		sc	-- ptr to per ctlr structure
474144966Svkashyap * Output:		None
475144966Svkashyap * Return value:	0	-- success
476144966Svkashyap *			non-zero-- failure
477144966Svkashyap */
478144966SvkashyapTW_INT32
479144966Svkashyaptw_osli_request_bus_scan(struct twa_softc *sc)
480144966Svkashyap{
481144966Svkashyap	union ccb	*ccb;
482144966Svkashyap
483144966Svkashyap	tw_osli_dbg_dprintf(3, sc, "entering");
484144966Svkashyap
485152213Svkashyap	/* If we get here before sc->sim is initialized, return an error. */
486152213Svkashyap	if (!(sc->sim))
487152213Svkashyap		return(ENXIO);
488203108Smav	if ((ccb = xpt_alloc_ccb()) == NULL)
489144966Svkashyap		return(ENOMEM);
490172496Sscottl	mtx_lock(sc->sim_lock);
491249468Smav	if (xpt_create_path(&ccb->ccb_h.path, NULL, cam_sim_path(sc->sim),
492203108Smav	    CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
493203108Smav		xpt_free_ccb(ccb);
494172496Sscottl		mtx_unlock(sc->sim_lock);
495144966Svkashyap		return(EIO);
496169400Sscottl	}
497144966Svkashyap
498203108Smav	xpt_rescan(ccb);
499172496Sscottl	mtx_unlock(sc->sim_lock);
500144966Svkashyap	return(0);
501144966Svkashyap}
502144966Svkashyap
503144966Svkashyap
504144966Svkashyap
505144966Svkashyap/*
506144966Svkashyap * Function name:	tw_osli_disallow_new_requests
507144966Svkashyap * Description:		Calls the appropriate CAM function, so as to freeze
508144966Svkashyap *			the flow of new requests from CAM to this controller.
509144966Svkashyap *
510144966Svkashyap * Input:		sc	-- ptr to OSL internal ctlr context
511208969Sdelphij *			req_handle -- ptr to request handle sent by OSL.
512144966Svkashyap * Output:		None
513144966Svkashyap * Return value:	None
514144966Svkashyap */
515144966SvkashyapTW_VOID
516208969Sdelphijtw_osli_disallow_new_requests(struct twa_softc *sc,
517208969Sdelphij	struct tw_cl_req_handle *req_handle)
518144966Svkashyap{
519208969Sdelphij	/* Only freeze/release the simq for IOs */
520208969Sdelphij	if (req_handle->is_io) {
521208969Sdelphij		struct tw_osli_req_context	*req = req_handle->osl_req_ctxt;
522208969Sdelphij		union ccb			*ccb = (union ccb *)(req->orig_req);
523208969Sdelphij
524172496Sscottl		xpt_freeze_simq(sc->sim, 1);
525208969Sdelphij		ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
526172496Sscottl	}
527144966Svkashyap}
528144966Svkashyap
529144966Svkashyap
530144966Svkashyap
531144966Svkashyap/*
532212008Sdelphij * Function name:	tw_osl_timeout
533212008Sdelphij * Description:		Call to timeout().
534152213Svkashyap *
535212008Sdelphij * Input:		req_handle -- ptr to request handle sent by OSL.
536152213Svkashyap * Output:		None
537152213Svkashyap * Return value:	None
538152213Svkashyap */
539152213SvkashyapTW_VOID
540212008Sdelphijtw_osl_timeout(struct tw_cl_req_handle *req_handle)
541152213Svkashyap{
542212008Sdelphij	struct tw_osli_req_context	*req = req_handle->osl_req_ctxt;
543212008Sdelphij	union ccb			*ccb = (union ccb *)(req->orig_req);
544212008Sdelphij	struct ccb_hdr			*ccb_h = &(ccb->ccb_h);
545212008Sdelphij
546212008Sdelphij	req->deadline = tw_osl_get_local_time() + (ccb_h->timeout / 1000);
547152213Svkashyap}
548152213Svkashyap
549152213Svkashyap
550152213Svkashyap
551152213Svkashyap/*
552212008Sdelphij * Function name:	tw_osl_untimeout
553212008Sdelphij * Description:		Inverse of call to timeout().
554212008Sdelphij *
555212008Sdelphij * Input:		req_handle -- ptr to request handle sent by OSL.
556212008Sdelphij * Output:		None
557212008Sdelphij * Return value:	None
558212008Sdelphij */
559212008SdelphijTW_VOID
560212008Sdelphijtw_osl_untimeout(struct tw_cl_req_handle *req_handle)
561212008Sdelphij{
562212008Sdelphij	struct tw_osli_req_context	*req = req_handle->osl_req_ctxt;
563212008Sdelphij
564212008Sdelphij	req->deadline = 0;
565212008Sdelphij}
566212008Sdelphij
567212008Sdelphij
568212008Sdelphij
569212008Sdelphij/*
570144966Svkashyap * Function name:	tw_osl_scan_bus
571144966Svkashyap * Description:		CL calls this function to request for a bus scan.
572144966Svkashyap *
573144966Svkashyap * Input:		ctlr_handle	-- ptr to controller handle
574144966Svkashyap * Output:		None
575144966Svkashyap * Return value:	None
576144966Svkashyap */
577144966SvkashyapTW_VOID
578144966Svkashyaptw_osl_scan_bus(struct tw_cl_ctlr_handle *ctlr_handle)
579144966Svkashyap{
580144966Svkashyap	struct twa_softc	*sc = ctlr_handle->osl_ctlr_ctxt;
581144966Svkashyap	TW_INT32		error;
582144966Svkashyap
583144966Svkashyap	if ((error = tw_osli_request_bus_scan(sc)))
584144966Svkashyap		tw_osli_printf(sc, "error = %d",
585144966Svkashyap			TW_CL_SEVERITY_ERROR_STRING,
586144966Svkashyap			TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
587144966Svkashyap			0x2109,
588144966Svkashyap			"Bus scan request to CAM failed",
589144966Svkashyap			error);
590144966Svkashyap}
591144966Svkashyap
592144966Svkashyap
593144966Svkashyap
594144966Svkashyap/*
595144966Svkashyap * Function name:	tw_osl_complete_io
596144966Svkashyap * Description:		Called to complete CAM scsi requests.
597144966Svkashyap *
598144966Svkashyap * Input:		req_handle	-- ptr to request handle
599144966Svkashyap * Output:		None
600144966Svkashyap * Return value:	None
601144966Svkashyap */
602144966SvkashyapTW_VOID
603144966Svkashyaptw_osl_complete_io(struct tw_cl_req_handle *req_handle)
604144966Svkashyap{
605144966Svkashyap	struct tw_osli_req_context	*req = req_handle->osl_req_ctxt;
606144966Svkashyap	struct tw_cl_req_packet		*req_pkt =
607144966Svkashyap		(struct tw_cl_req_packet *)(&req->req_pkt);
608144966Svkashyap	struct tw_cl_scsi_req_packet	*scsi_req;
609144966Svkashyap	struct twa_softc		*sc = req->ctlr;
610144966Svkashyap	union ccb			*ccb = (union ccb *)(req->orig_req);
611144966Svkashyap
612144966Svkashyap	tw_osli_dbg_dprintf(10, sc, "entering");
613144966Svkashyap
614144966Svkashyap	if (req->state != TW_OSLI_REQ_STATE_BUSY)
615144966Svkashyap		tw_osli_printf(sc, "request = %p, status = %d",
616144966Svkashyap			TW_CL_SEVERITY_ERROR_STRING,
617144966Svkashyap			TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
618144966Svkashyap			0x210A,
619144966Svkashyap			"Unposted command completed!!",
620144966Svkashyap			req, req->state);
621144966Svkashyap
622144966Svkashyap	/*
623144966Svkashyap	 * Remove request from the busy queue.  Just mark it complete.
624144966Svkashyap	 * There's no need to move it into the complete queue as we are
625144966Svkashyap	 * going to be done with it right now.
626144966Svkashyap	 */
627144966Svkashyap	req->state = TW_OSLI_REQ_STATE_COMPLETE;
628144966Svkashyap	tw_osli_req_q_remove_item(req, TW_OSLI_BUSY_Q);
629144966Svkashyap
630144966Svkashyap	tw_osli_unmap_request(req);
631144966Svkashyap
632212008Sdelphij	req->deadline = 0;
633144966Svkashyap	if (req->error_code) {
634144966Svkashyap		/* This request never got submitted to the firmware. */
635144966Svkashyap		if (req->error_code == EBUSY) {
636144966Svkashyap			/*
637152213Svkashyap			 * Cmd queue is full, or the Common Layer is out of
638208969Sdelphij			 * resources.  The simq will already have been frozen.
639208969Sdelphij			 * When this ccb gets completed will unfreeze the simq.
640144966Svkashyap			 */
641144966Svkashyap			ccb->ccb_h.status |= CAM_REQUEUE_REQ;
642144966Svkashyap		}
643144966Svkashyap		else if (req->error_code == EFBIG)
644144966Svkashyap			ccb->ccb_h.status = CAM_REQ_TOO_BIG;
645144966Svkashyap		else
646144966Svkashyap			ccb->ccb_h.status = CAM_REQ_CMP_ERR;
647144966Svkashyap	} else {
648144966Svkashyap		scsi_req = &(req_pkt->gen_req_pkt.scsi_req);
649144966Svkashyap		if (req_pkt->status == TW_CL_ERR_REQ_SUCCESS)
650144966Svkashyap			ccb->ccb_h.status = CAM_REQ_CMP;
651144966Svkashyap		else {
652144966Svkashyap			if (req_pkt->status & TW_CL_ERR_REQ_INVALID_TARGET)
653237460Smav				ccb->ccb_h.status |= CAM_SEL_TIMEOUT;
654144966Svkashyap			else if (req_pkt->status & TW_CL_ERR_REQ_INVALID_LUN)
655237460Smav				ccb->ccb_h.status |= CAM_DEV_NOT_THERE;
656144966Svkashyap			else if (req_pkt->status & TW_CL_ERR_REQ_SCSI_ERROR)
657144966Svkashyap				ccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR;
658144966Svkashyap			else if (req_pkt->status & TW_CL_ERR_REQ_BUS_RESET)
659212008Sdelphij				ccb->ccb_h.status |= (CAM_REQUEUE_REQ | CAM_SCSI_BUS_RESET);
660144966Svkashyap			/*
661144966Svkashyap			 * If none of the above errors occurred, simply
662144966Svkashyap			 * mark completion error.
663144966Svkashyap			 */
664144966Svkashyap			if (ccb->ccb_h.status == 0)
665144966Svkashyap				ccb->ccb_h.status = CAM_REQ_CMP_ERR;
666144966Svkashyap
667144966Svkashyap			if (req_pkt->status & TW_CL_ERR_REQ_AUTO_SENSE_VALID) {
668144966Svkashyap				ccb->csio.sense_len = scsi_req->sense_len;
669144966Svkashyap				ccb->ccb_h.status |= CAM_AUTOSNS_VALID;
670144966Svkashyap			}
671144966Svkashyap		}
672144966Svkashyap
673144966Svkashyap		ccb->csio.scsi_status = scsi_req->scsi_status;
674144966Svkashyap	}
675144966Svkashyap
676144966Svkashyap	ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
677172496Sscottl	mtx_lock(sc->sim_lock);
678144966Svkashyap	xpt_done(ccb);
679172496Sscottl	mtx_unlock(sc->sim_lock);
680144966Svkashyap	if (! req->error_code)
681144966Svkashyap		 /* twa_action will free the request otherwise */
682144966Svkashyap		tw_osli_req_q_insert_tail(req, TW_OSLI_FREE_Q);
683144966Svkashyap}
684144966Svkashyap
685