1331722Seadler/*
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: stable/11/sys/dev/twa/tw_osl_cam.c 335138 2018-06-14 14:46:20Z mav $
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) {
210257381Snwhitehorn		tw_osli_dbg_dprintf(3, sc, "Invalid target. PTL = %x %x %jx",
211257381Snwhitehorn			ccb_h->path_id, ccb_h->target_id,
212257381Snwhitehorn			(uintmax_t)ccb_h->target_lun);
213144966Svkashyap		ccb_h->status |= CAM_TID_INVALID;
214144966Svkashyap		xpt_done(ccb);
215144966Svkashyap		return(1);
216144966Svkashyap	}
217144966Svkashyap	if (ccb_h->target_lun >= TW_CL_MAX_NUM_LUNS) {
218257381Snwhitehorn		tw_osli_dbg_dprintf(3, sc, "Invalid lun. PTL = %x %x %jx",
219257381Snwhitehorn			ccb_h->path_id, ccb_h->target_id,
220257381Snwhitehorn			(uintmax_t)ccb_h->target_lun);
221144966Svkashyap		ccb_h->status |= CAM_LUN_INVALID;
222144966Svkashyap		xpt_done(ccb);
223144966Svkashyap		return(1);
224144966Svkashyap	}
225144966Svkashyap
226144966Svkashyap	if(ccb_h->flags & CAM_CDB_PHYS) {
227144966Svkashyap		tw_osli_printf(sc, "",
228144966Svkashyap			TW_CL_SEVERITY_ERROR_STRING,
229144966Svkashyap			TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
230144966Svkashyap			0x2105,
231144966Svkashyap			"Physical CDB address!");
232208969Sdelphij		ccb_h->status = CAM_REQ_INVALID;
233144966Svkashyap		xpt_done(ccb);
234144966Svkashyap		return(1);
235144966Svkashyap	}
236144966Svkashyap
237144966Svkashyap	/*
238144966Svkashyap	 * We are going to work on this request.  Mark it as enqueued (though
239144966Svkashyap	 * we don't actually queue it...)
240144966Svkashyap	 */
241144966Svkashyap	ccb_h->status |= CAM_SIM_QUEUED;
242144966Svkashyap
243144966Svkashyap	if((ccb_h->flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
244144966Svkashyap		if(ccb_h->flags & CAM_DIR_IN)
245144966Svkashyap			req->flags |= TW_OSLI_REQ_FLAGS_DATA_IN;
246144966Svkashyap		else
247144966Svkashyap			req->flags |= TW_OSLI_REQ_FLAGS_DATA_OUT;
248144966Svkashyap	}
249144966Svkashyap
250144966Svkashyap	/* Build the CL understood request packet for SCSI cmds. */
251144966Svkashyap	req_pkt = &req->req_pkt;
252144966Svkashyap	req_pkt->status = 0;
253144966Svkashyap	req_pkt->tw_osl_callback = tw_osl_complete_io;
254144966Svkashyap	scsi_req = &(req_pkt->gen_req_pkt.scsi_req);
255144966Svkashyap	scsi_req->unit = ccb_h->target_id;
256144966Svkashyap	scsi_req->lun = ccb_h->target_lun;
257144966Svkashyap	scsi_req->sense_len = 0;
258144966Svkashyap	scsi_req->sense_data = (TW_UINT8 *)(&csio->sense_data);
259144966Svkashyap	scsi_req->scsi_status = 0;
260144966Svkashyap	if(ccb_h->flags & CAM_CDB_POINTER)
261144966Svkashyap		scsi_req->cdb = csio->cdb_io.cdb_ptr;
262144966Svkashyap	else
263144966Svkashyap		scsi_req->cdb = csio->cdb_io.cdb_bytes;
264144966Svkashyap	scsi_req->cdb_len = csio->cdb_len;
265144966Svkashyap
266246713Skib	if (csio->dxfer_len > TW_CL_MAX_IO_SIZE) {
267246713Skib		tw_osli_printf(sc, "size = %d",
268144966Svkashyap			TW_CL_SEVERITY_ERROR_STRING,
269144966Svkashyap			TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
270246713Skib			0x2106,
271246713Skib			"I/O size too big",
272246713Skib			csio->dxfer_len);
273246713Skib		ccb_h->status = CAM_REQ_TOO_BIG;
274144966Svkashyap		ccb_h->status &= ~CAM_SIM_QUEUED;
275144966Svkashyap		xpt_done(ccb);
276144966Svkashyap		return(1);
277144966Svkashyap	}
278248583Skib	if ((ccb_h->flags & CAM_DATA_MASK) == CAM_DATA_VADDR) {
279248583Skib		if ((req->length = csio->dxfer_len) != 0) {
280248583Skib			req->data = csio->data_ptr;
281248583Skib			scsi_req->sgl_entries = 1;
282248583Skib		}
283248583Skib	} else
284248583Skib		req->flags |= TW_OSLI_REQ_FLAGS_CCB;
285212008Sdelphij	req->deadline = tw_osl_get_local_time() + (ccb_h->timeout / 1000);
286212008Sdelphij
287144966Svkashyap	/*
288144966Svkashyap	 * twa_map_load_data_callback will fill in the SGL,
289144966Svkashyap	 * and submit the I/O.
290144966Svkashyap	 */
291144966Svkashyap	error = tw_osli_map_request(req);
292212008Sdelphij	if ((error) && (req->flags & TW_OSLI_REQ_FLAGS_FAILED)) {
293212008Sdelphij		req->deadline = 0;
294212008Sdelphij		ccb_h->status = CAM_REQ_CMP_ERR;
295212008Sdelphij		ccb_h->status &= ~CAM_SIM_QUEUED;
296212008Sdelphij		xpt_done(ccb);
297212008Sdelphij	}
298144966Svkashyap	return(error);
299144966Svkashyap}
300144966Svkashyap
301144966Svkashyap
302144966Svkashyap
303144966Svkashyap/*
304144966Svkashyap * Function name:	twa_action
305144966Svkashyap * Description:		Driver entry point for CAM's use.
306144966Svkashyap *
307144966Svkashyap * Input:		sim	-- sim corresponding to the ctlr
308144966Svkashyap *			ccb	-- ptr to CAM request
309144966Svkashyap * Output:		None
310144966Svkashyap * Return value:	None
311144966Svkashyap */
312144966SvkashyapTW_VOID
313144966Svkashyaptwa_action(struct cam_sim *sim, union ccb *ccb)
314144966Svkashyap{
315144966Svkashyap	struct twa_softc	*sc = (struct twa_softc *)cam_sim_softc(sim);
316144966Svkashyap	struct ccb_hdr		*ccb_h = &(ccb->ccb_h);
317144966Svkashyap
318144966Svkashyap	switch (ccb_h->func_code) {
319144966Svkashyap	case XPT_SCSI_IO:	/* SCSI I/O */
320144966Svkashyap	{
321144966Svkashyap		struct tw_osli_req_context	*req;
322144966Svkashyap
323208969Sdelphij		req = tw_osli_get_request(sc);
324208969Sdelphij		if (req == NULL) {
325208969Sdelphij			tw_osli_dbg_dprintf(2, sc, "Cannot get request pkt.");
326144966Svkashyap			/*
327144966Svkashyap			 * Freeze the simq to maintain ccb ordering.  The next
328144966Svkashyap			 * ccb that gets completed will unfreeze the simq.
329144966Svkashyap			 */
330212008Sdelphij			ccb_h->status &= ~CAM_SIM_QUEUED;
331144966Svkashyap			ccb_h->status |= CAM_REQUEUE_REQ;
332144966Svkashyap			xpt_done(ccb);
333144966Svkashyap			break;
334144966Svkashyap		}
335212008Sdelphij
336212008Sdelphij		if ((tw_cl_is_reset_needed(&(req->ctlr->ctlr_handle)))) {
337212008Sdelphij			ccb_h->status &= ~CAM_SIM_QUEUED;
338212008Sdelphij			ccb_h->status |= CAM_REQUEUE_REQ;
339212008Sdelphij			xpt_done(ccb);
340212008Sdelphij			tw_osli_req_q_insert_tail(req, TW_OSLI_FREE_Q);
341212008Sdelphij			break;
342212008Sdelphij		}
343212008Sdelphij
344144966Svkashyap		req->req_handle.osl_req_ctxt = req;
345208969Sdelphij		req->req_handle.is_io = TW_CL_TRUE;
346144966Svkashyap		req->orig_req = ccb;
347144966Svkashyap		if (tw_osli_execute_scsi(req, ccb))
348144966Svkashyap			tw_osli_req_q_insert_tail(req, TW_OSLI_FREE_Q);
349144966Svkashyap		break;
350144966Svkashyap	}
351144966Svkashyap
352144966Svkashyap	case XPT_ABORT:
353144966Svkashyap		tw_osli_dbg_dprintf(2, sc, "Abort request.");
354144966Svkashyap		ccb_h->status = CAM_UA_ABORT;
355144966Svkashyap		xpt_done(ccb);
356144966Svkashyap		break;
357144966Svkashyap
358144966Svkashyap	case XPT_RESET_BUS:
359212008Sdelphij		tw_cl_create_event(&(sc->ctlr_handle), TW_CL_FALSE,
360144966Svkashyap			TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
361144966Svkashyap			0x2108, 0x3, TW_CL_SEVERITY_INFO_STRING,
362144966Svkashyap			"Received Reset Bus request from CAM",
363144966Svkashyap			" ");
364144966Svkashyap
365212008Sdelphij		tw_cl_set_reset_needed(&(sc->ctlr_handle));
366212008Sdelphij		ccb_h->status = CAM_REQ_CMP;
367144966Svkashyap		xpt_done(ccb);
368144966Svkashyap		break;
369144966Svkashyap
370144966Svkashyap	case XPT_SET_TRAN_SETTINGS:
371144966Svkashyap		tw_osli_dbg_dprintf(3, sc, "XPT_SET_TRAN_SETTINGS");
372144966Svkashyap
373144966Svkashyap		/*
374144966Svkashyap		 * This command is not supported, since it's very specific
375144966Svkashyap		 * to SCSI, and we are doing ATA.
376144966Svkashyap		 */
377144966Svkashyap  		ccb_h->status = CAM_FUNC_NOTAVAIL;
378144966Svkashyap  		xpt_done(ccb);
379144966Svkashyap  		break;
380144966Svkashyap
381144966Svkashyap	case XPT_GET_TRAN_SETTINGS:
382144966Svkashyap	{
383144966Svkashyap		struct ccb_trans_settings	*cts = &ccb->cts;
384163816Smjacob		struct ccb_trans_settings_scsi *scsi =
385163816Smjacob		    &cts->proto_specific.scsi;
386163816Smjacob		struct ccb_trans_settings_spi *spi =
387163816Smjacob		    &cts->xport_specific.spi;
388144966Svkashyap
389163816Smjacob		cts->protocol = PROTO_SCSI;
390163816Smjacob		cts->protocol_version = SCSI_REV_2;
391163816Smjacob		cts->transport = XPORT_SPI;
392163816Smjacob		cts->transport_version = 2;
393163816Smjacob
394163816Smjacob		spi->valid = CTS_SPI_VALID_DISC;
395163816Smjacob		spi->flags = CTS_SPI_FLAGS_DISC_ENB;
396163816Smjacob		scsi->valid = CTS_SCSI_VALID_TQ;
397163816Smjacob		scsi->flags = CTS_SCSI_FLAGS_TAG_ENB;
398163816Smjacob		tw_osli_dbg_dprintf(3, sc, "XPT_GET_TRAN_SETTINGS");
399144966Svkashyap		ccb_h->status = CAM_REQ_CMP;
400144966Svkashyap		xpt_done(ccb);
401144966Svkashyap		break;
402144966Svkashyap	}
403144966Svkashyap
404144966Svkashyap	case XPT_CALC_GEOMETRY:
405144966Svkashyap		tw_osli_dbg_dprintf(3, sc, "XPT_CALC_GEOMETRY");
406144966Svkashyap		cam_calc_geometry(&ccb->ccg, 1/* extended */);
407144966Svkashyap		xpt_done(ccb);
408144966Svkashyap		break;
409144966Svkashyap
410144966Svkashyap	case XPT_PATH_INQ:    /* Path inquiry -- get twa properties */
411144966Svkashyap	{
412144966Svkashyap		struct ccb_pathinq	*path_inq = &ccb->cpi;
413144966Svkashyap
414144966Svkashyap		tw_osli_dbg_dprintf(3, sc, "XPT_PATH_INQ request");
415144966Svkashyap
416144966Svkashyap		path_inq->version_num = 1;
417144966Svkashyap		path_inq->hba_inquiry = 0;
418144966Svkashyap		path_inq->target_sprt = 0;
419144966Svkashyap		path_inq->hba_misc = 0;
420144966Svkashyap		path_inq->hba_eng_cnt = 0;
421144966Svkashyap		path_inq->max_target = TW_CL_MAX_NUM_UNITS;
422144966Svkashyap		path_inq->max_lun = TW_CL_MAX_NUM_LUNS - 1;
423144966Svkashyap		path_inq->unit_number = cam_sim_unit(sim);
424144966Svkashyap		path_inq->bus_id = cam_sim_bus(sim);
425152213Svkashyap		path_inq->initiator_id = TW_CL_MAX_NUM_UNITS;
426144966Svkashyap		path_inq->base_transfer_speed = 100000;
427315812Smav		strlcpy(path_inq->sim_vid, "FreeBSD", SIM_IDLEN);
428315812Smav		strlcpy(path_inq->hba_vid, "3ware", HBA_IDLEN);
429315812Smav		strlcpy(path_inq->dev_name, cam_sim_name(sim), DEV_IDLEN);
430335138Smav		path_inq->transport = XPORT_SPI;
431335138Smav		path_inq->transport_version = 2;
432335138Smav		path_inq->protocol = PROTO_SCSI;
433335138Smav		path_inq->protocol_version = SCSI_REV_2;
434335138Smav		path_inq->maxio = TW_CL_MAX_IO_SIZE;
435144966Svkashyap		ccb_h->status = CAM_REQ_CMP;
436144966Svkashyap		xpt_done(ccb);
437144966Svkashyap		break;
438144966Svkashyap	}
439144966Svkashyap
440144966Svkashyap	default:
441144966Svkashyap		tw_osli_dbg_dprintf(3, sc, "func_code = %x", ccb_h->func_code);
442144966Svkashyap		ccb_h->status = CAM_REQ_INVALID;
443144966Svkashyap		xpt_done(ccb);
444144966Svkashyap		break;
445144966Svkashyap	}
446144966Svkashyap}
447144966Svkashyap
448144966Svkashyap
449144966Svkashyap
450144966Svkashyap/*
451144966Svkashyap * Function name:	twa_poll
452144966Svkashyap * Description:		Driver entry point called when interrupts are not
453144966Svkashyap *			available.
454144966Svkashyap *
455144966Svkashyap * Input:		sim	-- sim corresponding to the controller
456144966Svkashyap * Output:		None
457144966Svkashyap * Return value:	None
458144966Svkashyap */
459144966SvkashyapTW_VOID
460144966Svkashyaptwa_poll(struct cam_sim *sim)
461144966Svkashyap{
462144966Svkashyap	struct twa_softc *sc = (struct twa_softc *)(cam_sim_softc(sim));
463144966Svkashyap
464144966Svkashyap	tw_osli_dbg_dprintf(3, sc, "entering; sc = %p", sc);
465145688Svkashyap	tw_cl_interrupt(&(sc->ctlr_handle));
466144966Svkashyap	tw_osli_dbg_dprintf(3, sc, "exiting; sc = %p", sc);
467144966Svkashyap}
468144966Svkashyap
469144966Svkashyap
470144966Svkashyap
471144966Svkashyap/*
472144966Svkashyap * Function name:	tw_osli_request_bus_scan
473144966Svkashyap * Description:		Requests CAM for a scan of the bus.
474144966Svkashyap *
475144966Svkashyap * Input:		sc	-- ptr to per ctlr structure
476144966Svkashyap * Output:		None
477144966Svkashyap * Return value:	0	-- success
478144966Svkashyap *			non-zero-- failure
479144966Svkashyap */
480144966SvkashyapTW_INT32
481144966Svkashyaptw_osli_request_bus_scan(struct twa_softc *sc)
482144966Svkashyap{
483144966Svkashyap	union ccb	*ccb;
484144966Svkashyap
485144966Svkashyap	tw_osli_dbg_dprintf(3, sc, "entering");
486144966Svkashyap
487152213Svkashyap	/* If we get here before sc->sim is initialized, return an error. */
488152213Svkashyap	if (!(sc->sim))
489152213Svkashyap		return(ENXIO);
490203108Smav	if ((ccb = xpt_alloc_ccb()) == NULL)
491144966Svkashyap		return(ENOMEM);
492172496Sscottl	mtx_lock(sc->sim_lock);
493249468Smav	if (xpt_create_path(&ccb->ccb_h.path, NULL, cam_sim_path(sc->sim),
494203108Smav	    CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
495203108Smav		xpt_free_ccb(ccb);
496172496Sscottl		mtx_unlock(sc->sim_lock);
497144966Svkashyap		return(EIO);
498169400Sscottl	}
499144966Svkashyap
500203108Smav	xpt_rescan(ccb);
501172496Sscottl	mtx_unlock(sc->sim_lock);
502144966Svkashyap	return(0);
503144966Svkashyap}
504144966Svkashyap
505144966Svkashyap
506144966Svkashyap
507144966Svkashyap/*
508144966Svkashyap * Function name:	tw_osli_disallow_new_requests
509144966Svkashyap * Description:		Calls the appropriate CAM function, so as to freeze
510144966Svkashyap *			the flow of new requests from CAM to this controller.
511144966Svkashyap *
512144966Svkashyap * Input:		sc	-- ptr to OSL internal ctlr context
513208969Sdelphij *			req_handle -- ptr to request handle sent by OSL.
514144966Svkashyap * Output:		None
515144966Svkashyap * Return value:	None
516144966Svkashyap */
517144966SvkashyapTW_VOID
518208969Sdelphijtw_osli_disallow_new_requests(struct twa_softc *sc,
519208969Sdelphij	struct tw_cl_req_handle *req_handle)
520144966Svkashyap{
521208969Sdelphij	/* Only freeze/release the simq for IOs */
522208969Sdelphij	if (req_handle->is_io) {
523208969Sdelphij		struct tw_osli_req_context	*req = req_handle->osl_req_ctxt;
524208969Sdelphij		union ccb			*ccb = (union ccb *)(req->orig_req);
525208969Sdelphij
526172496Sscottl		xpt_freeze_simq(sc->sim, 1);
527208969Sdelphij		ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
528172496Sscottl	}
529144966Svkashyap}
530144966Svkashyap
531144966Svkashyap
532144966Svkashyap
533144966Svkashyap/*
534212008Sdelphij * Function name:	tw_osl_timeout
535212008Sdelphij * Description:		Call to timeout().
536152213Svkashyap *
537212008Sdelphij * Input:		req_handle -- ptr to request handle sent by OSL.
538152213Svkashyap * Output:		None
539152213Svkashyap * Return value:	None
540152213Svkashyap */
541152213SvkashyapTW_VOID
542212008Sdelphijtw_osl_timeout(struct tw_cl_req_handle *req_handle)
543152213Svkashyap{
544212008Sdelphij	struct tw_osli_req_context	*req = req_handle->osl_req_ctxt;
545212008Sdelphij	union ccb			*ccb = (union ccb *)(req->orig_req);
546212008Sdelphij	struct ccb_hdr			*ccb_h = &(ccb->ccb_h);
547212008Sdelphij
548212008Sdelphij	req->deadline = tw_osl_get_local_time() + (ccb_h->timeout / 1000);
549152213Svkashyap}
550152213Svkashyap
551152213Svkashyap
552152213Svkashyap
553152213Svkashyap/*
554212008Sdelphij * Function name:	tw_osl_untimeout
555212008Sdelphij * Description:		Inverse of call to timeout().
556212008Sdelphij *
557212008Sdelphij * Input:		req_handle -- ptr to request handle sent by OSL.
558212008Sdelphij * Output:		None
559212008Sdelphij * Return value:	None
560212008Sdelphij */
561212008SdelphijTW_VOID
562212008Sdelphijtw_osl_untimeout(struct tw_cl_req_handle *req_handle)
563212008Sdelphij{
564212008Sdelphij	struct tw_osli_req_context	*req = req_handle->osl_req_ctxt;
565212008Sdelphij
566212008Sdelphij	req->deadline = 0;
567212008Sdelphij}
568212008Sdelphij
569212008Sdelphij
570212008Sdelphij
571212008Sdelphij/*
572144966Svkashyap * Function name:	tw_osl_scan_bus
573144966Svkashyap * Description:		CL calls this function to request for a bus scan.
574144966Svkashyap *
575144966Svkashyap * Input:		ctlr_handle	-- ptr to controller handle
576144966Svkashyap * Output:		None
577144966Svkashyap * Return value:	None
578144966Svkashyap */
579144966SvkashyapTW_VOID
580144966Svkashyaptw_osl_scan_bus(struct tw_cl_ctlr_handle *ctlr_handle)
581144966Svkashyap{
582144966Svkashyap	struct twa_softc	*sc = ctlr_handle->osl_ctlr_ctxt;
583144966Svkashyap	TW_INT32		error;
584144966Svkashyap
585144966Svkashyap	if ((error = tw_osli_request_bus_scan(sc)))
586144966Svkashyap		tw_osli_printf(sc, "error = %d",
587144966Svkashyap			TW_CL_SEVERITY_ERROR_STRING,
588144966Svkashyap			TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
589144966Svkashyap			0x2109,
590144966Svkashyap			"Bus scan request to CAM failed",
591144966Svkashyap			error);
592144966Svkashyap}
593144966Svkashyap
594144966Svkashyap
595144966Svkashyap
596144966Svkashyap/*
597144966Svkashyap * Function name:	tw_osl_complete_io
598144966Svkashyap * Description:		Called to complete CAM scsi requests.
599144966Svkashyap *
600144966Svkashyap * Input:		req_handle	-- ptr to request handle
601144966Svkashyap * Output:		None
602144966Svkashyap * Return value:	None
603144966Svkashyap */
604144966SvkashyapTW_VOID
605144966Svkashyaptw_osl_complete_io(struct tw_cl_req_handle *req_handle)
606144966Svkashyap{
607144966Svkashyap	struct tw_osli_req_context	*req = req_handle->osl_req_ctxt;
608144966Svkashyap	struct tw_cl_req_packet		*req_pkt =
609144966Svkashyap		(struct tw_cl_req_packet *)(&req->req_pkt);
610144966Svkashyap	struct tw_cl_scsi_req_packet	*scsi_req;
611144966Svkashyap	struct twa_softc		*sc = req->ctlr;
612144966Svkashyap	union ccb			*ccb = (union ccb *)(req->orig_req);
613144966Svkashyap
614144966Svkashyap	tw_osli_dbg_dprintf(10, sc, "entering");
615144966Svkashyap
616144966Svkashyap	if (req->state != TW_OSLI_REQ_STATE_BUSY)
617144966Svkashyap		tw_osli_printf(sc, "request = %p, status = %d",
618144966Svkashyap			TW_CL_SEVERITY_ERROR_STRING,
619144966Svkashyap			TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
620144966Svkashyap			0x210A,
621144966Svkashyap			"Unposted command completed!!",
622144966Svkashyap			req, req->state);
623144966Svkashyap
624144966Svkashyap	/*
625144966Svkashyap	 * Remove request from the busy queue.  Just mark it complete.
626144966Svkashyap	 * There's no need to move it into the complete queue as we are
627144966Svkashyap	 * going to be done with it right now.
628144966Svkashyap	 */
629144966Svkashyap	req->state = TW_OSLI_REQ_STATE_COMPLETE;
630144966Svkashyap	tw_osli_req_q_remove_item(req, TW_OSLI_BUSY_Q);
631144966Svkashyap
632144966Svkashyap	tw_osli_unmap_request(req);
633144966Svkashyap
634212008Sdelphij	req->deadline = 0;
635144966Svkashyap	if (req->error_code) {
636144966Svkashyap		/* This request never got submitted to the firmware. */
637144966Svkashyap		if (req->error_code == EBUSY) {
638144966Svkashyap			/*
639152213Svkashyap			 * Cmd queue is full, or the Common Layer is out of
640208969Sdelphij			 * resources.  The simq will already have been frozen.
641208969Sdelphij			 * When this ccb gets completed will unfreeze the simq.
642144966Svkashyap			 */
643144966Svkashyap			ccb->ccb_h.status |= CAM_REQUEUE_REQ;
644144966Svkashyap		}
645144966Svkashyap		else if (req->error_code == EFBIG)
646144966Svkashyap			ccb->ccb_h.status = CAM_REQ_TOO_BIG;
647144966Svkashyap		else
648144966Svkashyap			ccb->ccb_h.status = CAM_REQ_CMP_ERR;
649144966Svkashyap	} else {
650144966Svkashyap		scsi_req = &(req_pkt->gen_req_pkt.scsi_req);
651144966Svkashyap		if (req_pkt->status == TW_CL_ERR_REQ_SUCCESS)
652144966Svkashyap			ccb->ccb_h.status = CAM_REQ_CMP;
653144966Svkashyap		else {
654144966Svkashyap			if (req_pkt->status & TW_CL_ERR_REQ_INVALID_TARGET)
655237460Smav				ccb->ccb_h.status |= CAM_SEL_TIMEOUT;
656144966Svkashyap			else if (req_pkt->status & TW_CL_ERR_REQ_INVALID_LUN)
657237460Smav				ccb->ccb_h.status |= CAM_DEV_NOT_THERE;
658144966Svkashyap			else if (req_pkt->status & TW_CL_ERR_REQ_SCSI_ERROR)
659144966Svkashyap				ccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR;
660144966Svkashyap			else if (req_pkt->status & TW_CL_ERR_REQ_BUS_RESET)
661212008Sdelphij				ccb->ccb_h.status |= (CAM_REQUEUE_REQ | CAM_SCSI_BUS_RESET);
662144966Svkashyap			/*
663144966Svkashyap			 * If none of the above errors occurred, simply
664144966Svkashyap			 * mark completion error.
665144966Svkashyap			 */
666144966Svkashyap			if (ccb->ccb_h.status == 0)
667144966Svkashyap				ccb->ccb_h.status = CAM_REQ_CMP_ERR;
668144966Svkashyap
669144966Svkashyap			if (req_pkt->status & TW_CL_ERR_REQ_AUTO_SENSE_VALID) {
670144966Svkashyap				ccb->csio.sense_len = scsi_req->sense_len;
671144966Svkashyap				ccb->ccb_h.status |= CAM_AUTOSNS_VALID;
672144966Svkashyap			}
673144966Svkashyap		}
674144966Svkashyap
675144966Svkashyap		ccb->csio.scsi_status = scsi_req->scsi_status;
676144966Svkashyap	}
677144966Svkashyap
678144966Svkashyap	ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
679172496Sscottl	mtx_lock(sc->sim_lock);
680144966Svkashyap	xpt_done(ccb);
681172496Sscottl	mtx_unlock(sc->sim_lock);
682144966Svkashyap	if (! req->error_code)
683144966Svkashyap		 /* twa_action will free the request otherwise */
684144966Svkashyap		tw_osli_req_q_insert_tail(req, TW_OSLI_FREE_Q);
685144966Svkashyap}
686144966Svkashyap
687