1250963Sachim/*-
2250963Sachim * Copyright (c) 2002-2010 Adaptec, Inc.
3250963Sachim * Copyright (c) 2010-2012 PMC-Sierra, Inc.
4250963Sachim * All rights reserved.
5250963Sachim *
6250963Sachim * Redistribution and use in source and binary forms, with or without
7250963Sachim * modification, are permitted provided that the following conditions
8250963Sachim * are met:
9250963Sachim * 1. Redistributions of source code must retain the above copyright
10250963Sachim *    notice, this list of conditions and the following disclaimer.
11250963Sachim * 2. Redistributions in binary form must reproduce the above copyright
12250963Sachim *    notice, this list of conditions and the following disclaimer in the
13250963Sachim *    documentation and/or other materials provided with the distribution.
14250963Sachim *
15250963Sachim * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16250963Sachim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17250963Sachim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18250963Sachim * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19250963Sachim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20250963Sachim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21250963Sachim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22250963Sachim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23250963Sachim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24250963Sachim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25250963Sachim * SUCH DAMAGE.
26250963Sachim */
27250963Sachim
28250963Sachim#include <sys/cdefs.h>
29250963Sachim__FBSDID("$FreeBSD: stable/10/sys/dev/aacraid/aacraid_cam.c 316857 2017-04-14 16:40:10Z avg $");
30250963Sachim
31250963Sachim/*
32250963Sachim * CAM front-end for communicating with non-DASD devices
33250963Sachim */
34250963Sachim
35250963Sachim#include "opt_aacraid.h"
36250963Sachim
37250963Sachim#include <sys/param.h>
38250963Sachim#include <sys/systm.h>
39250963Sachim#include <sys/kernel.h>
40250963Sachim#include <sys/sysctl.h>
41250963Sachim#include <sys/lock.h>
42250963Sachim#include <sys/malloc.h>
43250963Sachim#include <sys/module.h>
44250963Sachim#include <sys/mutex.h>
45250963Sachim
46250963Sachim#include <cam/cam.h>
47250963Sachim#include <cam/cam_ccb.h>
48250963Sachim#include <cam/cam_debug.h>
49250963Sachim#include <cam/cam_periph.h>
50250963Sachim#if __FreeBSD_version < 801000
51250963Sachim#include <cam/cam_xpt_periph.h>
52250963Sachim#endif
53250963Sachim#include <cam/cam_sim.h>
54250963Sachim#include <cam/cam_xpt_sim.h>
55250963Sachim#include <cam/scsi/scsi_all.h>
56250963Sachim#include <cam/scsi/scsi_message.h>
57250963Sachim
58250963Sachim#include <sys/bus.h>
59250963Sachim#include <sys/conf.h>
60250963Sachim#include <sys/disk.h>
61250963Sachim
62250963Sachim#include <machine/md_var.h>
63250963Sachim#include <machine/bus.h>
64250963Sachim#include <sys/rman.h>
65250963Sachim
66250963Sachim#include <vm/vm.h>
67250963Sachim#include <vm/pmap.h>
68250963Sachim
69250963Sachim#include <dev/aacraid/aacraid_reg.h>
70250963Sachim#include <sys/aac_ioctl.h>
71250963Sachim#include <dev/aacraid/aacraid_debug.h>
72250963Sachim#include <dev/aacraid/aacraid_var.h>
73250963Sachim
74250963Sachim#if __FreeBSD_version >= 700025
75250963Sachim#ifndef	CAM_NEW_TRAN_CODE
76250963Sachim#define	CAM_NEW_TRAN_CODE	1
77250963Sachim#endif
78250963Sachim#endif
79250963Sachim
80250963Sachim#ifndef SVPD_SUPPORTED_PAGE_LIST
81250963Sachimstruct scsi_vpd_supported_page_list
82250963Sachim{
83250963Sachim	u_int8_t device;
84250963Sachim	u_int8_t page_code;
85250963Sachim#define	SVPD_SUPPORTED_PAGE_LIST 0x00
86250963Sachim	u_int8_t reserved;
87250963Sachim	u_int8_t length;	/* number of VPD entries */
88250963Sachim#define	SVPD_SUPPORTED_PAGES_SIZE	251
89250963Sachim	u_int8_t list[SVPD_SUPPORTED_PAGES_SIZE];
90250963Sachim};
91250963Sachim#endif
92250963Sachim
93250963Sachim/************************** Version Compatibility *************************/
94250963Sachim#if	__FreeBSD_version < 700031
95250963Sachim#define	aac_sim_alloc(a,b,c,d,e,f,g,h,i)	cam_sim_alloc(a,b,c,d,e,g,h,i)
96250963Sachim#else
97250963Sachim#define	aac_sim_alloc				cam_sim_alloc
98250963Sachim#endif
99250963Sachim
100250963Sachimstruct aac_cam {
101250963Sachim	device_t		dev;
102250963Sachim	struct aac_sim		*inf;
103250963Sachim	struct cam_sim		*sim;
104250963Sachim	struct cam_path		*path;
105250963Sachim};
106250963Sachim
107250963Sachimstatic int aac_cam_probe(device_t dev);
108250963Sachimstatic int aac_cam_attach(device_t dev);
109250963Sachimstatic int aac_cam_detach(device_t dev);
110250963Sachimstatic void aac_cam_action(struct cam_sim *, union ccb *);
111250963Sachimstatic void aac_cam_poll(struct cam_sim *);
112250963Sachimstatic void aac_cam_complete(struct aac_command *);
113250963Sachimstatic void aac_container_complete(struct aac_command *);
114250963Sachim#if __FreeBSD_version >= 700000
115250963Sachimstatic void aac_cam_rescan(struct aac_softc *sc, uint32_t channel,
116250963Sachim	uint32_t target_id);
117250963Sachim#endif
118250963Sachimstatic void aac_set_scsi_error(struct aac_softc *sc, union ccb *ccb,
119250963Sachim	u_int8_t status, u_int8_t key, u_int8_t asc, u_int8_t ascq);
120250963Sachimstatic int aac_load_map_command_sg(struct aac_softc *, struct aac_command *);
121250963Sachimstatic u_int64_t aac_eval_blockno(u_int8_t *);
122250963Sachimstatic void aac_container_rw_command(struct cam_sim *, union ccb *, u_int8_t *);
123250963Sachimstatic void aac_container_special_command(struct cam_sim *, union ccb *,
124250963Sachim	u_int8_t *);
125250963Sachimstatic void aac_passthrough_command(struct cam_sim *, union ccb *);
126250963Sachim
127250963Sachimstatic u_int32_t aac_cam_reset_bus(struct cam_sim *, union ccb *);
128250963Sachimstatic u_int32_t aac_cam_abort_ccb(struct cam_sim *, union ccb *);
129250963Sachimstatic u_int32_t aac_cam_term_io(struct cam_sim *, union ccb *);
130250963Sachim
131250963Sachimstatic devclass_t	aacraid_pass_devclass;
132250963Sachim
133250963Sachimstatic device_method_t	aacraid_pass_methods[] = {
134250963Sachim	DEVMETHOD(device_probe,		aac_cam_probe),
135250963Sachim	DEVMETHOD(device_attach,	aac_cam_attach),
136250963Sachim	DEVMETHOD(device_detach,	aac_cam_detach),
137250963Sachim	{ 0, 0 }
138250963Sachim};
139250963Sachim
140250963Sachimstatic driver_t	aacraid_pass_driver = {
141250963Sachim	"aacraidp",
142250963Sachim	aacraid_pass_methods,
143250963Sachim	sizeof(struct aac_cam)
144250963Sachim};
145250963Sachim
146250963SachimDRIVER_MODULE(aacraidp, aacraid, aacraid_pass_driver, aacraid_pass_devclass, 0, 0);
147250963SachimMODULE_DEPEND(aacraidp, cam, 1, 1, 1);
148250963Sachim
149250963SachimMALLOC_DEFINE(M_AACRAIDCAM, "aacraidcam", "AACRAID CAM info");
150250963Sachim
151250963Sachimstatic void
152250963Sachimaac_set_scsi_error(struct aac_softc *sc, union ccb *ccb, u_int8_t status,
153250963Sachim	u_int8_t key, u_int8_t asc, u_int8_t ascq)
154250963Sachim{
155250963Sachim#if __FreeBSD_version >= 900000
156250963Sachim	struct scsi_sense_data_fixed *sense =
157250963Sachim		(struct scsi_sense_data_fixed *)&ccb->csio.sense_data;
158250963Sachim#else
159250963Sachim	struct scsi_sense_data *sense = &ccb->csio.sense_data;
160250963Sachim#endif
161250963Sachim
162250963Sachim	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "Error %d!", status);
163250963Sachim
164250963Sachim	ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR;
165250963Sachim	ccb->csio.scsi_status = status;
166250963Sachim	if (status == SCSI_STATUS_CHECK_COND) {
167250963Sachim		ccb->ccb_h.status |= CAM_AUTOSNS_VALID;
168250963Sachim		bzero(&ccb->csio.sense_data, ccb->csio.sense_len);
169250963Sachim		ccb->csio.sense_data.error_code =
170250963Sachim			SSD_CURRENT_ERROR | SSD_ERRCODE_VALID;
171250963Sachim		sense->flags = key;
172250963Sachim		if (ccb->csio.sense_len >= 14) {
173250963Sachim			sense->extra_len = 6;
174250963Sachim			sense->add_sense_code = asc;
175250963Sachim			sense->add_sense_code_qual = ascq;
176250963Sachim		}
177250963Sachim	}
178250963Sachim}
179250963Sachim
180250963Sachim#if __FreeBSD_version >= 700000
181250963Sachimstatic void
182250963Sachimaac_cam_rescan(struct aac_softc *sc, uint32_t channel, uint32_t target_id)
183250963Sachim{
184250963Sachim	union ccb *ccb;
185250963Sachim	struct aac_sim *sim;
186250963Sachim	struct aac_cam *camsc;
187250963Sachim
188250963Sachim	if (target_id == AAC_CAM_TARGET_WILDCARD)
189250963Sachim		target_id = CAM_TARGET_WILDCARD;
190250963Sachim
191250963Sachim	TAILQ_FOREACH(sim, &sc->aac_sim_tqh, sim_link) {
192250963Sachim		camsc = sim->aac_cam;
193250963Sachim		if (camsc == NULL || camsc->inf == NULL ||
194250963Sachim		    camsc->inf->BusNumber != channel)
195250963Sachim			continue;
196250963Sachim
197250963Sachim		ccb = xpt_alloc_ccb_nowait();
198250963Sachim		if (ccb == NULL) {
199250963Sachim			device_printf(sc->aac_dev,
200250963Sachim			    "Cannot allocate ccb for bus rescan.\n");
201250963Sachim			return;
202250963Sachim		}
203250963Sachim
204250963Sachim		if (xpt_create_path(&ccb->ccb_h.path, xpt_periph,
205250963Sachim		    cam_sim_path(camsc->sim),
206250963Sachim		    target_id, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
207250963Sachim			xpt_free_ccb(ccb);
208250963Sachim			device_printf(sc->aac_dev,
209250963Sachim			    "Cannot create path for bus rescan.\n");
210250963Sachim			return;
211250963Sachim		}
212250963Sachim		xpt_rescan(ccb);
213250963Sachim		break;
214250963Sachim	}
215250963Sachim}
216250963Sachim#endif
217250963Sachim
218250963Sachimstatic void
219250963Sachimaac_cam_event(struct aac_softc *sc, struct aac_event *event, void *arg)
220250963Sachim{
221250963Sachim	union ccb *ccb;
222250963Sachim	struct aac_cam *camsc;
223250963Sachim
224250963Sachim	switch (event->ev_type) {
225250963Sachim	case AAC_EVENT_CMFREE:
226250963Sachim		ccb = arg;
227250963Sachim		camsc = ccb->ccb_h.sim_priv.entries[0].ptr;
228250963Sachim		free(event, M_AACRAIDCAM);
229250963Sachim		xpt_release_simq(camsc->sim, 1);
230250963Sachim		ccb->ccb_h.status = CAM_REQUEUE_REQ;
231250963Sachim		xpt_done(ccb);
232250963Sachim		break;
233250963Sachim	default:
234250963Sachim		device_printf(sc->aac_dev, "unknown event %d in aac_cam\n",
235250963Sachim		    event->ev_type);
236250963Sachim		break;
237250963Sachim	}
238250963Sachim
239250963Sachim	return;
240250963Sachim}
241250963Sachim
242250963Sachimstatic int
243250963Sachimaac_cam_probe(device_t dev)
244250963Sachim{
245250963Sachim	struct aac_cam *camsc;
246250963Sachim
247250963Sachim	camsc = (struct aac_cam *)device_get_softc(dev);
248250963Sachim	if (!camsc->inf)
249250963Sachim		return (0);
250316846Savg	fwprintf(camsc->inf->aac_sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
251250963Sachim	return (0);
252250963Sachim}
253250963Sachim
254250963Sachimstatic int
255250963Sachimaac_cam_detach(device_t dev)
256250963Sachim{
257250963Sachim	struct aac_softc *sc;
258250963Sachim	struct aac_cam *camsc;
259250963Sachim
260250963Sachim	camsc = (struct aac_cam *)device_get_softc(dev);
261250963Sachim	if (!camsc->inf)
262250963Sachim		return (0);
263250963Sachim	sc = camsc->inf->aac_sc;
264250963Sachim	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
265250963Sachim	camsc->inf->aac_cam = NULL;
266250963Sachim
267250963Sachim	mtx_lock(&sc->aac_io_lock);
268250963Sachim
269250963Sachim	xpt_async(AC_LOST_DEVICE, camsc->path, NULL);
270250963Sachim	xpt_free_path(camsc->path);
271250963Sachim	xpt_bus_deregister(cam_sim_path(camsc->sim));
272250963Sachim	cam_sim_free(camsc->sim, /*free_devq*/TRUE);
273250963Sachim
274250963Sachim	sc->cam_rescan_cb = NULL;
275250963Sachim
276250963Sachim	mtx_unlock(&sc->aac_io_lock);
277250963Sachim
278250963Sachim	return (0);
279250963Sachim}
280250963Sachim
281250963Sachim/*
282250963Sachim * Register the driver as a CAM SIM
283250963Sachim */
284250963Sachimstatic int
285250963Sachimaac_cam_attach(device_t dev)
286250963Sachim{
287250963Sachim	struct cam_devq *devq;
288250963Sachim	struct cam_sim *sim;
289250963Sachim	struct cam_path *path;
290250963Sachim	struct aac_cam *camsc;
291250963Sachim	struct aac_sim *inf;
292250963Sachim
293250963Sachim	camsc = (struct aac_cam *)device_get_softc(dev);
294250963Sachim	inf = (struct aac_sim *)device_get_ivars(dev);
295250963Sachim	if (!inf)
296250963Sachim		return (EIO);
297250963Sachim	fwprintf(inf->aac_sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
298250963Sachim	camsc->inf = inf;
299250963Sachim	camsc->inf->aac_cam = camsc;
300250963Sachim
301250963Sachim	devq = cam_simq_alloc(inf->TargetsPerBus);
302250963Sachim	if (devq == NULL)
303250963Sachim		return (EIO);
304250963Sachim
305250963Sachim	sim = aac_sim_alloc(aac_cam_action, aac_cam_poll, "aacraidp", camsc,
306250963Sachim	    device_get_unit(dev), &inf->aac_sc->aac_io_lock, 1, 1, devq);
307250963Sachim	if (sim == NULL) {
308250963Sachim		cam_simq_free(devq);
309250963Sachim		return (EIO);
310250963Sachim	}
311250963Sachim
312250963Sachim	/* Since every bus has it's own sim, every bus 'appears' as bus 0 */
313250963Sachim	mtx_lock(&inf->aac_sc->aac_io_lock);
314250963Sachim	if (aac_xpt_bus_register(sim, dev, 0) != CAM_SUCCESS) {
315250963Sachim		cam_sim_free(sim, TRUE);
316250963Sachim		mtx_unlock(&inf->aac_sc->aac_io_lock);
317250963Sachim		return (EIO);
318250963Sachim	}
319250963Sachim
320250963Sachim	if (xpt_create_path(&path, NULL, cam_sim_path(sim),
321250963Sachim	    CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
322250963Sachim		xpt_bus_deregister(cam_sim_path(sim));
323250963Sachim		cam_sim_free(sim, TRUE);
324250963Sachim		mtx_unlock(&inf->aac_sc->aac_io_lock);
325250963Sachim		return (EIO);
326250963Sachim	}
327250963Sachim
328250963Sachim#if __FreeBSD_version >= 700000
329250963Sachim	inf->aac_sc->cam_rescan_cb = aac_cam_rescan;
330250963Sachim#endif
331250963Sachim	mtx_unlock(&inf->aac_sc->aac_io_lock);
332250963Sachim
333250963Sachim	camsc->sim = sim;
334250963Sachim	camsc->path = path;
335250963Sachim
336250963Sachim	return (0);
337250963Sachim}
338250963Sachim
339250963Sachimstatic u_int64_t
340250963Sachimaac_eval_blockno(u_int8_t *cmdp)
341250963Sachim{
342250963Sachim	u_int64_t blockno;
343250963Sachim
344250963Sachim	switch (cmdp[0]) {
345250963Sachim	case READ_6:
346250963Sachim	case WRITE_6:
347250963Sachim		blockno = scsi_3btoul(((struct scsi_rw_6 *)cmdp)->addr);
348250963Sachim		break;
349250963Sachim	case READ_10:
350250963Sachim	case WRITE_10:
351250963Sachim		blockno = scsi_4btoul(((struct scsi_rw_10 *)cmdp)->addr);
352250963Sachim		break;
353250963Sachim	case READ_12:
354250963Sachim	case WRITE_12:
355250963Sachim		blockno = scsi_4btoul(((struct scsi_rw_12 *)cmdp)->addr);
356250963Sachim		break;
357250963Sachim	case READ_16:
358250963Sachim	case WRITE_16:
359250963Sachim		blockno = scsi_8btou64(((struct scsi_rw_16 *)cmdp)->addr);
360250963Sachim		break;
361250963Sachim	default:
362250963Sachim		blockno = 0;
363250963Sachim		break;
364250963Sachim	}
365250963Sachim	return(blockno);
366250963Sachim}
367250963Sachim
368250963Sachimstatic void
369250963Sachimaac_container_rw_command(struct cam_sim *sim, union ccb *ccb, u_int8_t *cmdp)
370250963Sachim{
371250963Sachim	struct	aac_cam *camsc;
372250963Sachim	struct	aac_softc *sc;
373250963Sachim	struct	aac_command *cm;
374250963Sachim	struct	aac_fib *fib;
375250963Sachim	u_int64_t blockno;
376250963Sachim
377250963Sachim	camsc = (struct aac_cam *)cam_sim_softc(sim);
378250963Sachim	sc = camsc->inf->aac_sc;
379250963Sachim	mtx_assert(&sc->aac_io_lock, MA_OWNED);
380250963Sachim
381250963Sachim	if (aacraid_alloc_command(sc, &cm)) {
382250963Sachim		struct aac_event *event;
383250963Sachim
384250963Sachim		xpt_freeze_simq(sim, 1);
385250963Sachim		ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
386250963Sachim		ccb->ccb_h.sim_priv.entries[0].ptr = camsc;
387250963Sachim		event = malloc(sizeof(struct aac_event), M_AACRAIDCAM,
388250963Sachim		    M_NOWAIT | M_ZERO);
389250963Sachim		if (event == NULL) {
390250963Sachim			device_printf(sc->aac_dev,
391250963Sachim			    "Warning, out of memory for event\n");
392250963Sachim			return;
393250963Sachim		}
394250963Sachim		event->ev_callback = aac_cam_event;
395250963Sachim		event->ev_arg = ccb;
396250963Sachim		event->ev_type = AAC_EVENT_CMFREE;
397250963Sachim		aacraid_add_event(sc, event);
398250963Sachim		return;
399250963Sachim	}
400250963Sachim
401250963Sachim	fib = cm->cm_fib;
402250963Sachim	switch (ccb->ccb_h.flags & CAM_DIR_MASK) {
403250963Sachim	case CAM_DIR_IN:
404250963Sachim		cm->cm_flags |= AAC_CMD_DATAIN;
405250963Sachim		break;
406250963Sachim	case CAM_DIR_OUT:
407250963Sachim		cm->cm_flags |= AAC_CMD_DATAOUT;
408250963Sachim		break;
409250963Sachim	case CAM_DIR_NONE:
410250963Sachim		break;
411250963Sachim	default:
412250963Sachim		cm->cm_flags |= AAC_CMD_DATAIN | AAC_CMD_DATAOUT;
413250963Sachim		break;
414250963Sachim	}
415250963Sachim
416250963Sachim	blockno = aac_eval_blockno(cmdp);
417250963Sachim
418250963Sachim	cm->cm_complete = aac_container_complete;
419250963Sachim	cm->cm_ccb = ccb;
420250963Sachim	cm->cm_timestamp = time_uptime;
421250963Sachim	cm->cm_data = (void *)ccb->csio.data_ptr;
422250963Sachim	cm->cm_datalen = ccb->csio.dxfer_len;
423250963Sachim
424250963Sachim	fib->Header.Size = sizeof(struct aac_fib_header);
425250963Sachim	fib->Header.XferState =
426250963Sachim		AAC_FIBSTATE_HOSTOWNED   |
427250963Sachim		AAC_FIBSTATE_INITIALISED |
428250963Sachim		AAC_FIBSTATE_EMPTY	 |
429250963Sachim		AAC_FIBSTATE_FROMHOST	 |
430250963Sachim		AAC_FIBSTATE_REXPECTED   |
431250963Sachim		AAC_FIBSTATE_NORM	 |
432250963Sachim		AAC_FIBSTATE_ASYNC	 |
433250963Sachim		AAC_FIBSTATE_FAST_RESPONSE;
434250963Sachim
435250963Sachim	if (sc->flags & AAC_FLAGS_NEW_COMM_TYPE2) {
436250963Sachim		struct aac_raw_io2 *raw;
437250963Sachim		raw = (struct aac_raw_io2 *)&fib->data[0];
438250963Sachim		bzero(raw, sizeof(struct aac_raw_io2));
439250963Sachim		fib->Header.Command = RawIo2;
440250963Sachim		raw->strtBlkLow = (u_int32_t)blockno;
441250963Sachim		raw->strtBlkHigh = (u_int32_t)(blockno >> 32);
442250963Sachim		raw->byteCnt = cm->cm_datalen;
443250963Sachim		raw->ldNum = ccb->ccb_h.target_id;
444250963Sachim		fib->Header.Size += sizeof(struct aac_raw_io2);
445250963Sachim		cm->cm_sgtable = (struct aac_sg_table *)raw->sge;
446250963Sachim		if (cm->cm_flags & AAC_CMD_DATAIN)
447250963Sachim			raw->flags = RIO2_IO_TYPE_READ | RIO2_SG_FORMAT_IEEE1212;
448250963Sachim		else
449250963Sachim			raw->flags = RIO2_IO_TYPE_WRITE | RIO2_SG_FORMAT_IEEE1212;
450250963Sachim	} else if (sc->flags & AAC_FLAGS_RAW_IO) {
451250963Sachim		struct aac_raw_io *raw;
452250963Sachim		raw = (struct aac_raw_io *)&fib->data[0];
453250963Sachim		bzero(raw, sizeof(struct aac_raw_io));
454250963Sachim		fib->Header.Command = RawIo;
455250963Sachim		raw->BlockNumber = blockno;
456250963Sachim		raw->ByteCount = cm->cm_datalen;
457250963Sachim		raw->ContainerId = ccb->ccb_h.target_id;
458250963Sachim		fib->Header.Size += sizeof(struct aac_raw_io);
459250963Sachim		cm->cm_sgtable = (struct aac_sg_table *)
460250963Sachim			&raw->SgMapRaw;
461250963Sachim		if (cm->cm_flags & AAC_CMD_DATAIN)
462250963Sachim			raw->Flags = 1;
463250963Sachim	} else if ((sc->flags & AAC_FLAGS_SG_64BIT) == 0) {
464250963Sachim		fib->Header.Command = ContainerCommand;
465250963Sachim		if (cm->cm_flags & AAC_CMD_DATAIN) {
466250963Sachim			struct aac_blockread *br;
467250963Sachim			br = (struct aac_blockread *)&fib->data[0];
468250963Sachim			br->Command = VM_CtBlockRead;
469250963Sachim			br->ContainerId = ccb->ccb_h.target_id;
470250963Sachim			br->BlockNumber = blockno;
471250963Sachim			br->ByteCount = cm->cm_datalen;
472250963Sachim			fib->Header.Size += sizeof(struct aac_blockread);
473250963Sachim			cm->cm_sgtable = &br->SgMap;
474250963Sachim		} else {
475250963Sachim			struct aac_blockwrite *bw;
476250963Sachim			bw = (struct aac_blockwrite *)&fib->data[0];
477250963Sachim			bw->Command = VM_CtBlockWrite;
478250963Sachim			bw->ContainerId = ccb->ccb_h.target_id;
479250963Sachim			bw->BlockNumber = blockno;
480250963Sachim			bw->ByteCount = cm->cm_datalen;
481250963Sachim			bw->Stable = CUNSTABLE;
482250963Sachim			fib->Header.Size += sizeof(struct aac_blockwrite);
483250963Sachim			cm->cm_sgtable = &bw->SgMap;
484250963Sachim		}
485250963Sachim	} else {
486250963Sachim		fib->Header.Command = ContainerCommand64;
487250963Sachim		if (cm->cm_flags & AAC_CMD_DATAIN) {
488250963Sachim			struct aac_blockread64 *br;
489250963Sachim			br = (struct aac_blockread64 *)&fib->data[0];
490250963Sachim			br->Command = VM_CtHostRead64;
491250963Sachim			br->ContainerId = ccb->ccb_h.target_id;
492250963Sachim			br->SectorCount = cm->cm_datalen/AAC_BLOCK_SIZE;
493250963Sachim			br->BlockNumber = blockno;
494250963Sachim			br->Pad = 0;
495250963Sachim			br->Flags = 0;
496250963Sachim			fib->Header.Size += sizeof(struct aac_blockread64);
497250963Sachim			cm->cm_sgtable = (struct aac_sg_table *)&br->SgMap64;
498250963Sachim		} else {
499250963Sachim			struct aac_blockwrite64 *bw;
500250963Sachim			bw = (struct aac_blockwrite64 *)&fib->data[0];
501250963Sachim			bw->Command = VM_CtHostWrite64;
502250963Sachim			bw->ContainerId = ccb->ccb_h.target_id;
503250963Sachim			bw->SectorCount = cm->cm_datalen/AAC_BLOCK_SIZE;
504250963Sachim			bw->BlockNumber = blockno;
505250963Sachim			bw->Pad = 0;
506250963Sachim			bw->Flags = 0;
507250963Sachim			fib->Header.Size += sizeof(struct aac_blockwrite64);
508250963Sachim			cm->cm_sgtable = (struct aac_sg_table *)&bw->SgMap64;
509250963Sachim		}
510250963Sachim	}
511250963Sachim	aac_enqueue_ready(cm);
512250963Sachim	aacraid_startio(cm->cm_sc);
513250963Sachim}
514250963Sachim
515250963Sachimstatic void
516250963Sachimaac_container_special_command(struct cam_sim *sim, union ccb *ccb,
517250963Sachim	u_int8_t *cmdp)
518250963Sachim{
519250963Sachim	struct	aac_cam *camsc;
520250963Sachim	struct	aac_softc *sc;
521250963Sachim	struct	aac_container *co;
522250963Sachim
523250963Sachim	camsc = (struct aac_cam *)cam_sim_softc(sim);
524250963Sachim	sc = camsc->inf->aac_sc;
525250963Sachim	mtx_assert(&sc->aac_io_lock, MA_OWNED);
526250963Sachim
527250963Sachim	TAILQ_FOREACH(co, &sc->aac_container_tqh, co_link) {
528250963Sachim		fwprintf(sc, HBA_FLAGS_DBG_ERROR_B, "found container %d search for %d", co->co_mntobj.ObjectId, ccb->ccb_h.target_id);
529250963Sachim		if (co->co_mntobj.ObjectId == ccb->ccb_h.target_id)
530250963Sachim			break;
531250963Sachim	}
532250963Sachim	if (co == NULL || ccb->ccb_h.target_lun != 0) {
533250963Sachim		fwprintf(sc, HBA_FLAGS_DBG_ERROR_B,
534250963Sachim			"Container not present: cmd 0x%x id %d lun %d len %d",
535250963Sachim			*cmdp, ccb->ccb_h.target_id, ccb->ccb_h.target_lun,
536250963Sachim			ccb->csio.dxfer_len);
537250963Sachim		ccb->ccb_h.status = CAM_DEV_NOT_THERE;
538250963Sachim		xpt_done(ccb);
539250963Sachim		return;
540250963Sachim	}
541250963Sachim
542250963Sachim	if (ccb->csio.dxfer_len)
543250963Sachim		bzero(ccb->csio.data_ptr, ccb->csio.dxfer_len);
544250963Sachim
545250963Sachim	switch (*cmdp) {
546250963Sachim	case INQUIRY:
547250963Sachim	{
548250963Sachim		struct scsi_inquiry *inq = (struct scsi_inquiry *)cmdp;
549250963Sachim
550250963Sachim		fwprintf(sc, HBA_FLAGS_DBG_COMM_B,
551250963Sachim		"Container INQUIRY id %d lun %d len %d VPD 0x%x Page 0x%x",
552250963Sachim			ccb->ccb_h.target_id, ccb->ccb_h.target_lun,
553250963Sachim			ccb->csio.dxfer_len, inq->byte2, inq->page_code);
554250963Sachim		if (!(inq->byte2 & SI_EVPD)) {
555250963Sachim			struct scsi_inquiry_data *p =
556250963Sachim				(struct scsi_inquiry_data *)ccb->csio.data_ptr;
557250963Sachim			if (inq->page_code != 0) {
558250963Sachim				aac_set_scsi_error(sc, ccb,
559250963Sachim					SCSI_STATUS_CHECK_COND,
560250963Sachim					SSD_KEY_ILLEGAL_REQUEST, 0x24, 0x00);
561250963Sachim				xpt_done(ccb);
562250963Sachim				return;
563250963Sachim			}
564250963Sachim			p->device = T_DIRECT;
565250963Sachim			p->version = SCSI_REV_SPC2;
566250963Sachim			p->response_format = 2;
567250963Sachim			if (ccb->csio.dxfer_len >= 36) {
568250963Sachim				p->additional_length = 31;
569250963Sachim				p->flags = SID_WBus16|SID_Sync|SID_CmdQue;
570250963Sachim				/* OEM Vendor defines */
571299635Sngie				strncpy(p->vendor, "Adaptec ", sizeof(p->vendor));
572299635Sngie				strncpy(p->product, "Array           ",
573299635Sngie				    sizeof(p->product));
574299635Sngie				strncpy(p->revision, "V1.0",
575299635Sngie				    sizeof(p->revision));
576250963Sachim			}
577250963Sachim		} else {
578250963Sachim			if (inq->page_code == SVPD_SUPPORTED_PAGE_LIST) {
579250963Sachim				struct scsi_vpd_supported_page_list *p =
580250963Sachim					(struct scsi_vpd_supported_page_list *)
581250963Sachim					ccb->csio.data_ptr;
582250963Sachim				p->device = T_DIRECT;
583250963Sachim				p->page_code = SVPD_SUPPORTED_PAGE_LIST;
584250963Sachim				p->length = 2;
585250963Sachim				p->list[0] = SVPD_SUPPORTED_PAGE_LIST;
586250963Sachim				p->list[1] = SVPD_UNIT_SERIAL_NUMBER;
587250963Sachim			} else if (inq->page_code == SVPD_UNIT_SERIAL_NUMBER) {
588250963Sachim				struct scsi_vpd_unit_serial_number *p =
589250963Sachim					(struct scsi_vpd_unit_serial_number *)
590250963Sachim					ccb->csio.data_ptr;
591250963Sachim				p->device = T_DIRECT;
592250963Sachim				p->page_code = SVPD_UNIT_SERIAL_NUMBER;
593250963Sachim				p->length = sprintf((char *)p->serial_num,
594250963Sachim					"%08X%02X", co->co_uid,
595250963Sachim					ccb->ccb_h.target_id);
596250963Sachim			} else {
597250963Sachim				aac_set_scsi_error(sc, ccb,
598250963Sachim					SCSI_STATUS_CHECK_COND,
599250963Sachim					SSD_KEY_ILLEGAL_REQUEST, 0x24, 0x00);
600250963Sachim				xpt_done(ccb);
601250963Sachim				return;
602250963Sachim			}
603250963Sachim		}
604250963Sachim		ccb->ccb_h.status = CAM_REQ_CMP;
605250963Sachim		break;
606250963Sachim	}
607250963Sachim
608250963Sachim	case REPORT_LUNS:
609250963Sachim		fwprintf(sc, HBA_FLAGS_DBG_COMM_B,
610250963Sachim		"Container REPORT_LUNS id %d lun %d len %d",
611250963Sachim		ccb->ccb_h.target_id, ccb->ccb_h.target_lun,
612250963Sachim		ccb->csio.dxfer_len);
613250963Sachim		ccb->ccb_h.status = CAM_REQ_CMP;
614250963Sachim		break;
615250963Sachim
616250963Sachim	case START_STOP:
617250963Sachim	{
618250963Sachim		struct scsi_start_stop_unit *ss =
619250963Sachim			(struct scsi_start_stop_unit *)cmdp;
620250963Sachim		fwprintf(sc, HBA_FLAGS_DBG_COMM_B,
621250963Sachim		"Container START_STOP id %d lun %d len %d",
622250963Sachim		ccb->ccb_h.target_id, ccb->ccb_h.target_lun,
623250963Sachim		ccb->csio.dxfer_len);
624250963Sachim		if (sc->aac_support_opt2 & AAC_SUPPORTED_POWER_MANAGEMENT) {
625250963Sachim			struct aac_command *cm;
626250963Sachim			struct aac_fib *fib;
627250963Sachim			struct aac_cnt_config *ccfg;
628250963Sachim
629250963Sachim			if (aacraid_alloc_command(sc, &cm)) {
630250963Sachim				struct aac_event *event;
631250963Sachim
632250963Sachim				xpt_freeze_simq(sim, 1);
633250963Sachim				ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
634250963Sachim				ccb->ccb_h.sim_priv.entries[0].ptr = camsc;
635250963Sachim				event = malloc(sizeof(struct aac_event), M_AACRAIDCAM,
636250963Sachim					M_NOWAIT | M_ZERO);
637250963Sachim				if (event == NULL) {
638250963Sachim					device_printf(sc->aac_dev,
639250963Sachim						"Warning, out of memory for event\n");
640250963Sachim					return;
641250963Sachim				}
642250963Sachim				event->ev_callback = aac_cam_event;
643250963Sachim				event->ev_arg = ccb;
644250963Sachim				event->ev_type = AAC_EVENT_CMFREE;
645250963Sachim				aacraid_add_event(sc, event);
646250963Sachim				return;
647250963Sachim			}
648250963Sachim
649250963Sachim			fib = cm->cm_fib;
650250963Sachim			cm->cm_timestamp = time_uptime;
651250963Sachim			cm->cm_datalen = 0;
652250963Sachim
653250963Sachim			fib->Header.Size =
654250963Sachim				sizeof(struct aac_fib_header) + sizeof(struct aac_cnt_config);
655250963Sachim			fib->Header.XferState =
656250963Sachim				AAC_FIBSTATE_HOSTOWNED   |
657250963Sachim				AAC_FIBSTATE_INITIALISED |
658250963Sachim				AAC_FIBSTATE_EMPTY	 |
659250963Sachim				AAC_FIBSTATE_FROMHOST	 |
660250963Sachim				AAC_FIBSTATE_REXPECTED   |
661250963Sachim				AAC_FIBSTATE_NORM	 |
662250963Sachim				AAC_FIBSTATE_ASYNC	 |
663250963Sachim				AAC_FIBSTATE_FAST_RESPONSE;
664250963Sachim			fib->Header.Command = ContainerCommand;
665250963Sachim
666250963Sachim			/* Start unit */
667250963Sachim			ccfg = (struct aac_cnt_config *)&fib->data[0];
668250963Sachim			bzero(ccfg, sizeof (*ccfg) - CT_PACKET_SIZE);
669250963Sachim			ccfg->Command = VM_ContainerConfig;
670250963Sachim			ccfg->CTCommand.command = CT_PM_DRIVER_SUPPORT;
671250963Sachim			ccfg->CTCommand.param[0] = (ss->how & SSS_START ?
672250963Sachim				AAC_PM_DRIVERSUP_START_UNIT :
673250963Sachim				AAC_PM_DRIVERSUP_STOP_UNIT);
674250963Sachim			ccfg->CTCommand.param[1] = co->co_mntobj.ObjectId;
675250963Sachim			ccfg->CTCommand.param[2] = 0;	/* 1 - immediate */
676250963Sachim
677250963Sachim			if (aacraid_wait_command(cm) != 0 ||
678250963Sachim				*(u_int32_t *)&fib->data[0] != 0) {
679250963Sachim				printf("Power Management: Error start/stop container %d\n",
680250963Sachim				co->co_mntobj.ObjectId);
681250963Sachim			}
682250963Sachim			aacraid_release_command(cm);
683250963Sachim		}
684250963Sachim		ccb->ccb_h.status = CAM_REQ_CMP;
685250963Sachim		break;
686250963Sachim	}
687250963Sachim
688250963Sachim	case TEST_UNIT_READY:
689250963Sachim		fwprintf(sc, HBA_FLAGS_DBG_COMM_B,
690250963Sachim		"Container TEST_UNIT_READY id %d lun %d len %d",
691250963Sachim		ccb->ccb_h.target_id, ccb->ccb_h.target_lun,
692250963Sachim		ccb->csio.dxfer_len);
693250963Sachim		ccb->ccb_h.status = CAM_REQ_CMP;
694250963Sachim		break;
695250963Sachim
696250963Sachim	case REQUEST_SENSE:
697250963Sachim		fwprintf(sc, HBA_FLAGS_DBG_COMM_B,
698250963Sachim		"Container REQUEST_SENSE id %d lun %d len %d",
699250963Sachim		ccb->ccb_h.target_id, ccb->ccb_h.target_lun,
700250963Sachim		ccb->csio.dxfer_len);
701250963Sachim		ccb->ccb_h.status = CAM_REQ_CMP;
702250963Sachim		break;
703250963Sachim
704250963Sachim	case READ_CAPACITY:
705250963Sachim	{
706250963Sachim		struct scsi_read_capacity_data *p =
707250963Sachim			(struct scsi_read_capacity_data *)ccb->csio.data_ptr;
708250963Sachim		fwprintf(sc, HBA_FLAGS_DBG_COMM_B,
709250963Sachim		"Container READ_CAPACITY id %d lun %d len %d",
710250963Sachim		ccb->ccb_h.target_id, ccb->ccb_h.target_lun,
711250963Sachim		ccb->csio.dxfer_len);
712263024Sachim		scsi_ulto4b(co->co_mntobj.ObjExtension.BlockDevice.BlockSize, p->length);
713250963Sachim		/* check if greater than 2TB */
714250963Sachim		if (co->co_mntobj.CapacityHigh) {
715250963Sachim			if (sc->flags & AAC_FLAGS_LBA_64BIT)
716250963Sachim				scsi_ulto4b(0xffffffff, p->addr);
717250963Sachim		} else {
718250963Sachim			scsi_ulto4b(co->co_mntobj.Capacity-1, p->addr);
719250963Sachim		}
720250963Sachim		ccb->ccb_h.status = CAM_REQ_CMP;
721250963Sachim		break;
722250963Sachim	}
723250963Sachim
724250963Sachim	case SERVICE_ACTION_IN:
725250963Sachim	{
726250963Sachim		struct scsi_read_capacity_data_long *p =
727250963Sachim			(struct scsi_read_capacity_data_long *)
728250963Sachim			ccb->csio.data_ptr;
729250963Sachim		fwprintf(sc, HBA_FLAGS_DBG_COMM_B,
730250963Sachim		"Container SERVICE_ACTION_IN id %d lun %d len %d",
731250963Sachim		ccb->ccb_h.target_id, ccb->ccb_h.target_lun,
732250963Sachim		ccb->csio.dxfer_len);
733250963Sachim		if (((struct scsi_read_capacity_16 *)cmdp)->service_action !=
734250963Sachim			SRC16_SERVICE_ACTION) {
735250963Sachim			aac_set_scsi_error(sc, ccb, SCSI_STATUS_CHECK_COND,
736250963Sachim				SSD_KEY_ILLEGAL_REQUEST, 0x24, 0x00);
737250963Sachim			xpt_done(ccb);
738250963Sachim			return;
739250963Sachim		}
740263024Sachim		scsi_ulto4b(co->co_mntobj.ObjExtension.BlockDevice.BlockSize, p->length);
741250963Sachim		scsi_ulto4b(co->co_mntobj.CapacityHigh, p->addr);
742250963Sachim		scsi_ulto4b(co->co_mntobj.Capacity-1, &p->addr[4]);
743263024Sachim
744263024Sachim		if (ccb->csio.dxfer_len >= 14) {
745263024Sachim			u_int32_t mapping = co->co_mntobj.ObjExtension.BlockDevice.bdLgclPhysMap;
746263024Sachim			p->prot_lbppbe = 0;
747263024Sachim			while (mapping > 1) {
748263024Sachim				mapping >>= 1;
749263024Sachim				p->prot_lbppbe++;
750263024Sachim			}
751263024Sachim			p->prot_lbppbe &= 0x0f;
752263024Sachim		}
753263024Sachim
754250963Sachim		ccb->ccb_h.status = CAM_REQ_CMP;
755250963Sachim		break;
756250963Sachim	}
757250963Sachim
758250963Sachim	case MODE_SENSE_6:
759250963Sachim	{
760250963Sachim		struct scsi_mode_sense_6 *msp =(struct scsi_mode_sense_6 *)cmdp;
761250963Sachim		struct ms6_data {
762250963Sachim			struct scsi_mode_hdr_6 hd;
763250963Sachim			struct scsi_mode_block_descr bd;
764250963Sachim			char pages;
765250963Sachim		} *p = (struct ms6_data *)ccb->csio.data_ptr;
766250963Sachim		char *pagep;
767250963Sachim		int return_all_pages = FALSE;
768250963Sachim
769250963Sachim		fwprintf(sc, HBA_FLAGS_DBG_COMM_B,
770250963Sachim		"Container MODE_SENSE id %d lun %d len %d page %d",
771250963Sachim		ccb->ccb_h.target_id, ccb->ccb_h.target_lun,
772250963Sachim		ccb->csio.dxfer_len, msp->page);
773250963Sachim		p->hd.datalen = sizeof(struct scsi_mode_hdr_6) - 1;
774250963Sachim		if (co->co_mntobj.ContentState & AAC_FSCS_READONLY)
775250963Sachim			p->hd.dev_specific = 0x80;	/* WP */
776250963Sachim		p->hd.dev_specific |= 0x10;	/* DPOFUA */
777250963Sachim		if (msp->byte2 & SMS_DBD) {
778250963Sachim			p->hd.block_descr_len = 0;
779250963Sachim		} else {
780250963Sachim			p->hd.block_descr_len =
781250963Sachim				sizeof(struct scsi_mode_block_descr);
782250963Sachim			p->hd.datalen += p->hd.block_descr_len;
783263024Sachim			scsi_ulto3b(co->co_mntobj.ObjExtension.BlockDevice.BlockSize, p->bd.block_len);
784250963Sachim			if (co->co_mntobj.Capacity > 0xffffff ||
785250963Sachim				co->co_mntobj.CapacityHigh) {
786250963Sachim				p->bd.num_blocks[0] = 0xff;
787250963Sachim				p->bd.num_blocks[1] = 0xff;
788250963Sachim				p->bd.num_blocks[2] = 0xff;
789250963Sachim			} else {
790250963Sachim				p->bd.num_blocks[0] = (u_int8_t)
791250963Sachim					(co->co_mntobj.Capacity >> 16);
792250963Sachim				p->bd.num_blocks[1] = (u_int8_t)
793250963Sachim					(co->co_mntobj.Capacity >> 8);
794250963Sachim				p->bd.num_blocks[2] = (u_int8_t)
795250963Sachim					(co->co_mntobj.Capacity);
796250963Sachim			}
797250963Sachim		}
798250963Sachim		pagep = &p->pages;
799250963Sachim		switch (msp->page & SMS_PAGE_CODE) {
800250963Sachim		case SMS_ALL_PAGES_PAGE:
801250963Sachim			return_all_pages = TRUE;
802250963Sachim		case SMS_CONTROL_MODE_PAGE:
803250963Sachim		{
804250963Sachim			struct scsi_control_page *cp =
805250963Sachim				(struct scsi_control_page *)pagep;
806250963Sachim
807250963Sachim			if (ccb->csio.dxfer_len <= p->hd.datalen + 8) {
808250963Sachim				aac_set_scsi_error(sc, ccb,
809250963Sachim					SCSI_STATUS_CHECK_COND,
810250963Sachim					SSD_KEY_ILLEGAL_REQUEST, 0x24, 0x00);
811250963Sachim				xpt_done(ccb);
812250963Sachim				return;
813250963Sachim			}
814250963Sachim			cp->page_code = SMS_CONTROL_MODE_PAGE;
815250963Sachim			cp->page_length = 6;
816250963Sachim			p->hd.datalen += 8;
817250963Sachim			pagep += 8;
818250963Sachim			if (!return_all_pages)
819250963Sachim				break;
820250963Sachim		}
821250963Sachim		case SMS_VENDOR_SPECIFIC_PAGE:
822250963Sachim			break;
823250963Sachim		default:
824250963Sachim			aac_set_scsi_error(sc, ccb, SCSI_STATUS_CHECK_COND,
825250963Sachim				SSD_KEY_ILLEGAL_REQUEST, 0x24, 0x00);
826250963Sachim			xpt_done(ccb);
827250963Sachim			return;
828250963Sachim		}
829250963Sachim		ccb->ccb_h.status = CAM_REQ_CMP;
830250963Sachim		break;
831250963Sachim	}
832250963Sachim
833250963Sachim	case SYNCHRONIZE_CACHE:
834250963Sachim		fwprintf(sc, HBA_FLAGS_DBG_COMM_B,
835250963Sachim		"Container SYNCHRONIZE_CACHE id %d lun %d len %d",
836250963Sachim		ccb->ccb_h.target_id, ccb->ccb_h.target_lun,
837250963Sachim		ccb->csio.dxfer_len);
838250963Sachim		ccb->ccb_h.status = CAM_REQ_CMP;
839250963Sachim		break;
840250963Sachim
841250963Sachim	default:
842250963Sachim		fwprintf(sc, HBA_FLAGS_DBG_ERROR_B,
843250963Sachim		"Container unsupp. cmd 0x%x id %d lun %d len %d",
844250963Sachim		*cmdp, ccb->ccb_h.target_id, ccb->ccb_h.target_lun,
845250963Sachim		ccb->csio.dxfer_len);
846250963Sachim		ccb->ccb_h.status = CAM_REQ_CMP; /*CAM_REQ_INVALID*/
847250963Sachim		break;
848250963Sachim	}
849250963Sachim	xpt_done(ccb);
850250963Sachim}
851250963Sachim
852250963Sachimstatic void
853250963Sachimaac_passthrough_command(struct cam_sim *sim, union ccb *ccb)
854250963Sachim{
855250963Sachim	struct	aac_cam *camsc;
856250963Sachim	struct	aac_softc *sc;
857250963Sachim	struct	aac_command *cm;
858250963Sachim	struct	aac_fib *fib;
859250963Sachim	struct	aac_srb *srb;
860250963Sachim
861250963Sachim	camsc = (struct aac_cam *)cam_sim_softc(sim);
862250963Sachim	sc = camsc->inf->aac_sc;
863250963Sachim	mtx_assert(&sc->aac_io_lock, MA_OWNED);
864250963Sachim
865250963Sachim	if (aacraid_alloc_command(sc, &cm)) {
866250963Sachim		struct aac_event *event;
867250963Sachim
868250963Sachim		xpt_freeze_simq(sim, 1);
869250963Sachim		ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
870250963Sachim		ccb->ccb_h.sim_priv.entries[0].ptr = camsc;
871250963Sachim		event = malloc(sizeof(struct aac_event), M_AACRAIDCAM,
872250963Sachim		    M_NOWAIT | M_ZERO);
873250963Sachim		if (event == NULL) {
874250963Sachim			device_printf(sc->aac_dev,
875250963Sachim			    "Warning, out of memory for event\n");
876250963Sachim			return;
877250963Sachim		}
878250963Sachim		event->ev_callback = aac_cam_event;
879250963Sachim		event->ev_arg = ccb;
880250963Sachim		event->ev_type = AAC_EVENT_CMFREE;
881250963Sachim		aacraid_add_event(sc, event);
882250963Sachim		return;
883250963Sachim	}
884250963Sachim
885250963Sachim	fib = cm->cm_fib;
886250963Sachim	switch (ccb->ccb_h.flags & CAM_DIR_MASK) {
887250963Sachim	case CAM_DIR_IN:
888250963Sachim		cm->cm_flags |= AAC_CMD_DATAIN;
889250963Sachim		break;
890250963Sachim	case CAM_DIR_OUT:
891250963Sachim		cm->cm_flags |= AAC_CMD_DATAOUT;
892250963Sachim		break;
893250963Sachim	case CAM_DIR_NONE:
894250963Sachim		break;
895250963Sachim	default:
896250963Sachim		cm->cm_flags |= AAC_CMD_DATAIN | AAC_CMD_DATAOUT;
897250963Sachim		break;
898250963Sachim	}
899250963Sachim
900250963Sachim	srb = (struct aac_srb *)&fib->data[0];
901250963Sachim	srb->function = AAC_SRB_FUNC_EXECUTE_SCSI;
902250963Sachim	if (cm->cm_flags & (AAC_CMD_DATAIN|AAC_CMD_DATAOUT))
903250963Sachim		srb->flags = AAC_SRB_FLAGS_UNSPECIFIED_DIRECTION;
904250963Sachim	if (cm->cm_flags & AAC_CMD_DATAIN)
905250963Sachim		srb->flags = AAC_SRB_FLAGS_DATA_IN;
906250963Sachim	else if (cm->cm_flags & AAC_CMD_DATAOUT)
907250963Sachim		srb->flags = AAC_SRB_FLAGS_DATA_OUT;
908250963Sachim	else
909250963Sachim		srb->flags = AAC_SRB_FLAGS_NO_DATA_XFER;
910250963Sachim
911250963Sachim	/*
912250963Sachim	 * Copy the CDB into the SRB.  It's only 6-16 bytes,
913250963Sachim	 * so a copy is not too expensive.
914250963Sachim	 */
915250963Sachim	srb->cdb_len = ccb->csio.cdb_len;
916250963Sachim	if (ccb->ccb_h.flags & CAM_CDB_POINTER)
917250963Sachim		bcopy(ccb->csio.cdb_io.cdb_ptr, (u_int8_t *)&srb->cdb[0],
918250963Sachim			srb->cdb_len);
919250963Sachim	else
920250963Sachim		bcopy(ccb->csio.cdb_io.cdb_bytes, (u_int8_t *)&srb->cdb[0],
921250963Sachim			srb->cdb_len);
922250963Sachim
923250963Sachim	/* Set command */
924250963Sachim	fib->Header.Command = (sc->flags & AAC_FLAGS_SG_64BIT) ?
925250963Sachim		ScsiPortCommandU64 : ScsiPortCommand;
926250963Sachim	fib->Header.Size = sizeof(struct aac_fib_header) +
927250963Sachim			sizeof(struct aac_srb);
928250963Sachim
929250963Sachim	/* Map the s/g list */
930250963Sachim	cm->cm_sgtable = &srb->sg_map;
931250963Sachim	if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
932250963Sachim		/*
933250963Sachim		 * Arrange things so that the S/G
934250963Sachim		 * map will get set up automagically
935250963Sachim		 */
936250963Sachim		cm->cm_data = (void *)ccb->csio.data_ptr;
937250963Sachim		cm->cm_datalen = ccb->csio.dxfer_len;
938250963Sachim		srb->data_len = ccb->csio.dxfer_len;
939250963Sachim	} else {
940250963Sachim		cm->cm_data = NULL;
941250963Sachim		cm->cm_datalen = 0;
942250963Sachim		srb->data_len = 0;
943250963Sachim	}
944250963Sachim
945250963Sachim	srb->bus = camsc->inf->BusNumber - 1; /* Bus no. rel. to the card */
946250963Sachim	srb->target = ccb->ccb_h.target_id;
947250963Sachim	srb->lun = ccb->ccb_h.target_lun;
948250963Sachim	srb->timeout = ccb->ccb_h.timeout;	/* XXX */
949250963Sachim	srb->retry_limit = 0;
950250963Sachim
951250963Sachim	cm->cm_complete = aac_cam_complete;
952250963Sachim	cm->cm_ccb = ccb;
953250963Sachim	cm->cm_timestamp = time_uptime;
954250963Sachim
955250963Sachim	fib->Header.XferState =
956250963Sachim			AAC_FIBSTATE_HOSTOWNED	|
957250963Sachim			AAC_FIBSTATE_INITIALISED	|
958250963Sachim			AAC_FIBSTATE_FROMHOST	|
959250963Sachim			AAC_FIBSTATE_REXPECTED	|
960250963Sachim			AAC_FIBSTATE_NORM	|
961250963Sachim			AAC_FIBSTATE_ASYNC	 |
962250963Sachim			AAC_FIBSTATE_FAST_RESPONSE;
963250963Sachim
964250963Sachim	aac_enqueue_ready(cm);
965250963Sachim	aacraid_startio(cm->cm_sc);
966250963Sachim}
967250963Sachim
968250963Sachimstatic void
969250963Sachimaac_cam_action(struct cam_sim *sim, union ccb *ccb)
970250963Sachim{
971250963Sachim	struct	aac_cam *camsc;
972250963Sachim	struct	aac_softc *sc;
973250963Sachim
974250963Sachim	camsc = (struct aac_cam *)cam_sim_softc(sim);
975250963Sachim	sc = camsc->inf->aac_sc;
976250963Sachim	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
977250963Sachim	mtx_assert(&sc->aac_io_lock, MA_OWNED);
978250963Sachim
979250963Sachim	/* Synchronous ops, and ops that don't require communication with the
980250963Sachim	 * controller */
981250963Sachim	switch(ccb->ccb_h.func_code) {
982250963Sachim	case XPT_SCSI_IO:
983250963Sachim		/* This is handled down below */
984250963Sachim		break;
985250963Sachim	case XPT_CALC_GEOMETRY:
986250963Sachim	{
987250963Sachim		struct ccb_calc_geometry *ccg;
988250963Sachim		u_int32_t size_mb;
989250963Sachim		u_int32_t secs_per_cylinder;
990250963Sachim
991250963Sachim		ccg = &ccb->ccg;
992250963Sachim		size_mb = ccg->volume_size /
993250963Sachim		    ((1024L * 1024L) / ccg->block_size);
994250963Sachim		if (size_mb >= (2 * 1024)) {		/* 2GB */
995250963Sachim			ccg->heads = 255;
996250963Sachim			ccg->secs_per_track = 63;
997250963Sachim		} else if (size_mb >= (1 * 1024)) {	/* 1GB */
998250963Sachim			ccg->heads = 128;
999250963Sachim			ccg->secs_per_track = 32;
1000250963Sachim		} else {
1001250963Sachim			ccg->heads = 64;
1002250963Sachim			ccg->secs_per_track = 32;
1003250963Sachim		}
1004250963Sachim		secs_per_cylinder = ccg->heads * ccg->secs_per_track;
1005250963Sachim		ccg->cylinders = ccg->volume_size / secs_per_cylinder;
1006250963Sachim
1007250963Sachim		ccb->ccb_h.status = CAM_REQ_CMP;
1008250963Sachim		xpt_done(ccb);
1009250963Sachim		return;
1010250963Sachim	}
1011250963Sachim	case XPT_PATH_INQ:
1012250963Sachim	{
1013250963Sachim		struct ccb_pathinq *cpi = &ccb->cpi;
1014250963Sachim
1015250963Sachim		cpi->version_num = 1;
1016250963Sachim		cpi->target_sprt = 0;
1017250963Sachim		cpi->hba_eng_cnt = 0;
1018250963Sachim		cpi->max_target = camsc->inf->TargetsPerBus;
1019250963Sachim		cpi->max_lun = 8;	/* Per the controller spec */
1020250963Sachim		cpi->initiator_id = camsc->inf->InitiatorBusId;
1021250963Sachim		cpi->bus_id = camsc->inf->BusNumber;
1022250963Sachim#if __FreeBSD_version >= 800000
1023250963Sachim		cpi->maxio = sc->aac_max_sectors << 9;
1024250963Sachim#endif
1025250963Sachim
1026250963Sachim		/*
1027250963Sachim		 * Resetting via the passthrough or parallel bus scan
1028250963Sachim		 * causes problems.
1029250963Sachim		 */
1030250963Sachim		cpi->hba_misc = PIM_NOBUSRESET;
1031250963Sachim		cpi->hba_inquiry = PI_TAG_ABLE;
1032250963Sachim		cpi->base_transfer_speed = 300000;
1033250963Sachim#ifdef CAM_NEW_TRAN_CODE
1034250963Sachim		cpi->hba_misc |= PIM_SEQSCAN;
1035250963Sachim		cpi->protocol = PROTO_SCSI;
1036250963Sachim		cpi->transport = XPORT_SAS;
1037250963Sachim		cpi->transport_version = 0;
1038250963Sachim		cpi->protocol_version = SCSI_REV_SPC2;
1039250963Sachim#endif
1040315813Smav		strlcpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
1041315813Smav		strlcpy(cpi->hba_vid, "PMC-Sierra", HBA_IDLEN);
1042315813Smav		strlcpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
1043250963Sachim		cpi->unit_number = cam_sim_unit(sim);
1044250963Sachim		ccb->ccb_h.status = CAM_REQ_CMP;
1045250963Sachim		xpt_done(ccb);
1046250963Sachim		return;
1047250963Sachim	}
1048250963Sachim	case XPT_GET_TRAN_SETTINGS:
1049250963Sachim	{
1050250963Sachim#ifdef CAM_NEW_TRAN_CODE
1051250963Sachim		struct ccb_trans_settings_scsi *scsi =
1052250963Sachim			&ccb->cts.proto_specific.scsi;
1053250963Sachim		struct ccb_trans_settings_spi *spi =
1054250963Sachim			&ccb->cts.xport_specific.spi;
1055250963Sachim		ccb->cts.protocol = PROTO_SCSI;
1056250963Sachim		ccb->cts.protocol_version = SCSI_REV_SPC2;
1057250963Sachim		ccb->cts.transport = XPORT_SAS;
1058250963Sachim		ccb->cts.transport_version = 0;
1059250963Sachim		scsi->valid = CTS_SCSI_VALID_TQ;
1060250963Sachim		scsi->flags = CTS_SCSI_FLAGS_TAG_ENB;
1061250963Sachim		spi->valid |= CTS_SPI_VALID_DISC;
1062250963Sachim		spi->flags |= CTS_SPI_FLAGS_DISC_ENB;
1063250963Sachim#else
1064250963Sachim		ccb->cts.flags = ~(CCB_TRANS_DISC_ENB | CCB_TRANS_TAG_ENB);
1065250963Sachim		ccb->cts.valid = CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID;
1066250963Sachim#endif
1067250963Sachim		ccb->ccb_h.status = CAM_REQ_CMP;
1068250963Sachim		xpt_done(ccb);
1069250963Sachim		return;
1070250963Sachim	}
1071250963Sachim	case XPT_SET_TRAN_SETTINGS:
1072250963Sachim		ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
1073250963Sachim		xpt_done(ccb);
1074250963Sachim		return;
1075250963Sachim	case XPT_RESET_BUS:
1076250963Sachim		if (!(sc->flags & AAC_FLAGS_CAM_NORESET) &&
1077250963Sachim			camsc->inf->BusType != CONTAINER_BUS) {
1078250963Sachim			ccb->ccb_h.status = aac_cam_reset_bus(sim, ccb);
1079250963Sachim		} else {
1080250963Sachim			ccb->ccb_h.status = CAM_REQ_CMP;
1081250963Sachim		}
1082250963Sachim		xpt_done(ccb);
1083250963Sachim		return;
1084250963Sachim	case XPT_RESET_DEV:
1085250963Sachim		ccb->ccb_h.status = CAM_REQ_CMP;
1086250963Sachim		xpt_done(ccb);
1087250963Sachim		return;
1088250963Sachim	case XPT_ABORT:
1089250963Sachim		ccb->ccb_h.status = aac_cam_abort_ccb(sim, ccb);
1090250963Sachim		xpt_done(ccb);
1091250963Sachim		return;
1092250963Sachim	case XPT_TERM_IO:
1093250963Sachim		ccb->ccb_h.status = aac_cam_term_io(sim, ccb);
1094250963Sachim		xpt_done(ccb);
1095250963Sachim		return;
1096250963Sachim	default:
1097250963Sachim		device_printf(sc->aac_dev, "Unsupported command 0x%x\n",
1098250963Sachim		    ccb->ccb_h.func_code);
1099250963Sachim		ccb->ccb_h.status = CAM_PROVIDE_FAIL;
1100250963Sachim		xpt_done(ccb);
1101250963Sachim		return;
1102250963Sachim	}
1103250963Sachim
1104250963Sachim	/* Async ops that require communcation with the controller */
1105250963Sachim	if (camsc->inf->BusType == CONTAINER_BUS) {
1106250963Sachim		u_int8_t *cmdp;
1107250963Sachim
1108250963Sachim		if (ccb->ccb_h.flags & CAM_CDB_POINTER)
1109250963Sachim			cmdp = ccb->csio.cdb_io.cdb_ptr;
1110250963Sachim		else
1111250963Sachim			cmdp = &ccb->csio.cdb_io.cdb_bytes[0];
1112250963Sachim
1113250963Sachim		if (*cmdp==READ_6 || *cmdp==WRITE_6 || *cmdp==READ_10 ||
1114250963Sachim			*cmdp==WRITE_10 || *cmdp==READ_12 || *cmdp==WRITE_12 ||
1115250963Sachim			*cmdp==READ_16 || *cmdp==WRITE_16)
1116250963Sachim			aac_container_rw_command(sim, ccb, cmdp);
1117250963Sachim		else
1118250963Sachim			aac_container_special_command(sim, ccb, cmdp);
1119250963Sachim	} else {
1120250963Sachim		aac_passthrough_command(sim, ccb);
1121250963Sachim	}
1122250963Sachim}
1123250963Sachim
1124250963Sachimstatic void
1125250963Sachimaac_cam_poll(struct cam_sim *sim)
1126250963Sachim{
1127250963Sachim	/*
1128250963Sachim	 * Pinging the interrupt routine isn't very safe, nor is it
1129250963Sachim	 * really necessary.  Do nothing.
1130250963Sachim	 */
1131250963Sachim}
1132250963Sachim
1133250963Sachimstatic void
1134250963Sachimaac_container_complete(struct aac_command *cm)
1135250963Sachim{
1136250963Sachim	union	ccb *ccb;
1137250963Sachim	u_int32_t status;
1138250963Sachim
1139316846Savg	fwprintf(cm->cm_sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
1140250963Sachim	ccb = cm->cm_ccb;
1141250963Sachim	status = ((u_int32_t *)cm->cm_fib->data)[0];
1142250963Sachim
1143250963Sachim	if (cm->cm_flags & AAC_CMD_RESET) {
1144250963Sachim		ccb->ccb_h.status = CAM_SCSI_BUS_RESET;
1145315854Savg	} else if (status == ST_OK) {
1146250963Sachim		ccb->ccb_h.status = CAM_REQ_CMP;
1147250963Sachim	} else if (status == ST_NOT_READY) {
1148250963Sachim		ccb->ccb_h.status = CAM_BUSY;
1149250963Sachim	} else {
1150250963Sachim		ccb->ccb_h.status = CAM_REQ_CMP_ERR;
1151250963Sachim	}
1152250963Sachim
1153250963Sachim	aacraid_release_command(cm);
1154250963Sachim	xpt_done(ccb);
1155250963Sachim}
1156250963Sachim
1157250963Sachimstatic void
1158250963Sachimaac_cam_complete(struct aac_command *cm)
1159250963Sachim{
1160250963Sachim	union	ccb *ccb;
1161250963Sachim	struct 	aac_srb_response *srbr;
1162250963Sachim	struct	aac_softc *sc;
1163250963Sachim
1164250963Sachim	sc = cm->cm_sc;
1165250963Sachim	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
1166250963Sachim	ccb = cm->cm_ccb;
1167250963Sachim	srbr = (struct aac_srb_response *)&cm->cm_fib->data[0];
1168250963Sachim
1169250963Sachim	if (cm->cm_flags & AAC_CMD_FASTRESP) {
1170250963Sachim		/* fast response */
1171250963Sachim		srbr->srb_status = CAM_REQ_CMP;
1172250963Sachim		srbr->scsi_status = SCSI_STATUS_OK;
1173250963Sachim		srbr->sense_len = 0;
1174250963Sachim	}
1175250963Sachim
1176250963Sachim	if (cm->cm_flags & AAC_CMD_RESET) {
1177250963Sachim		ccb->ccb_h.status = CAM_SCSI_BUS_RESET;
1178250963Sachim	} else if (srbr->fib_status != 0) {
1179250963Sachim		device_printf(sc->aac_dev, "Passthru FIB failed!\n");
1180250963Sachim		ccb->ccb_h.status = CAM_REQ_ABORTED;
1181250963Sachim	} else {
1182250963Sachim		/*
1183250963Sachim		 * The SRB error codes just happen to match the CAM error
1184250963Sachim		 * codes.  How convienient!
1185250963Sachim		 */
1186250963Sachim		ccb->ccb_h.status = srbr->srb_status;
1187250963Sachim
1188250963Sachim		/* Take care of SCSI_IO ops. */
1189250963Sachim		if (ccb->ccb_h.func_code == XPT_SCSI_IO) {
1190250963Sachim			u_int8_t command, device;
1191250963Sachim
1192250963Sachim			ccb->csio.scsi_status = srbr->scsi_status;
1193250963Sachim
1194250963Sachim			/* Take care of autosense */
1195250963Sachim			if (srbr->sense_len) {
1196250963Sachim				int sense_len, scsi_sense_len;
1197250963Sachim
1198250963Sachim				scsi_sense_len = sizeof(struct scsi_sense_data);
1199250963Sachim				bzero(&ccb->csio.sense_data, scsi_sense_len);
1200250963Sachim				sense_len = (srbr->sense_len >
1201250963Sachim				    scsi_sense_len) ? scsi_sense_len :
1202250963Sachim				    srbr->sense_len;
1203250963Sachim				bcopy(&srbr->sense[0], &ccb->csio.sense_data,
1204250963Sachim				    srbr->sense_len);
1205250963Sachim				ccb->csio.sense_len = sense_len;
1206250963Sachim				ccb->ccb_h.status |= CAM_AUTOSNS_VALID;
1207250963Sachim				// scsi_sense_print(&ccb->csio);
1208250963Sachim			}
1209250963Sachim
1210250963Sachim			/* If this is an inquiry command, fake things out */
1211250963Sachim			if (ccb->ccb_h.flags & CAM_CDB_POINTER)
1212250963Sachim				command = ccb->csio.cdb_io.cdb_ptr[0];
1213250963Sachim			else
1214250963Sachim				command = ccb->csio.cdb_io.cdb_bytes[0];
1215250963Sachim
1216250963Sachim			if (command == INQUIRY) {
1217250963Sachim				if (ccb->ccb_h.status == CAM_REQ_CMP) {
1218250963Sachim				  device = ccb->csio.data_ptr[0] & 0x1f;
1219250963Sachim				  /*
1220250963Sachim				   * We want DASD and PROC devices to only be
1221250963Sachim				   * visible through the pass device.
1222250963Sachim				   */
1223250963Sachim				  if ((device == T_DIRECT &&
1224250963Sachim				    !(sc->aac_feature_bits & AAC_SUPPL_SUPPORTED_JBOD)) ||
1225263024Sachim				    (device == T_PROCESSOR))
1226250963Sachim				    ccb->csio.data_ptr[0] =
1227250963Sachim				  	((device & 0xe0) | T_NODEVICE);
1228250963Sachim
1229263024Sachim				  /* handle phys. components of a log. drive */
1230263024Sachim				  if (ccb->csio.data_ptr[0] & 0x20) {
1231263024Sachim					if (sc->hint_flags & 8) {
1232263024Sachim					  /* expose phys. device (daXX) */
1233263024Sachim					  ccb->csio.data_ptr[0] &= 0xdf;
1234263024Sachim					} else {
1235263024Sachim					  /* phys. device only visible through pass device (passXX) */
1236263024Sachim					  ccb->csio.data_ptr[0] |= 0x10;
1237263024Sachim					}
1238263024Sachim				  }
1239250963Sachim				} else if (ccb->ccb_h.status == CAM_SEL_TIMEOUT &&
1240250963Sachim				  ccb->ccb_h.target_lun != 0) {
1241250963Sachim				  /* fix for INQUIRYs on Lun>0 */
1242250963Sachim				  ccb->ccb_h.status = CAM_DEV_NOT_THERE;
1243250963Sachim				}
1244250963Sachim			}
1245250963Sachim		}
1246250963Sachim	}
1247250963Sachim
1248250963Sachim	aacraid_release_command(cm);
1249250963Sachim	xpt_done(ccb);
1250250963Sachim}
1251250963Sachim
1252250963Sachimstatic u_int32_t
1253250963Sachimaac_cam_reset_bus(struct cam_sim *sim, union ccb *ccb)
1254250963Sachim{
1255250963Sachim	struct aac_command *cm;
1256250963Sachim	struct aac_fib *fib;
1257250963Sachim	struct aac_softc *sc;
1258250963Sachim	struct aac_cam *camsc;
1259250963Sachim	struct aac_vmioctl *vmi;
1260250963Sachim	struct aac_resetbus *rbc;
1261250963Sachim	u_int32_t rval;
1262250963Sachim
1263250963Sachim	camsc = (struct aac_cam *)cam_sim_softc(sim);
1264250963Sachim	sc = camsc->inf->aac_sc;
1265250963Sachim
1266250963Sachim	if (sc == NULL) {
1267250963Sachim		printf("aac: Null sc?\n");
1268250963Sachim		return (CAM_REQ_ABORTED);
1269250963Sachim	}
1270250963Sachim
1271250963Sachim	if (aacraid_alloc_command(sc, &cm)) {
1272250963Sachim		struct aac_event *event;
1273250963Sachim
1274250963Sachim		xpt_freeze_simq(sim, 1);
1275250963Sachim		ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
1276250963Sachim		ccb->ccb_h.sim_priv.entries[0].ptr = camsc;
1277250963Sachim		event = malloc(sizeof(struct aac_event), M_AACRAIDCAM,
1278250963Sachim			M_NOWAIT | M_ZERO);
1279250963Sachim		if (event == NULL) {
1280250963Sachim			device_printf(sc->aac_dev,
1281250963Sachim				"Warning, out of memory for event\n");
1282250963Sachim			return (CAM_REQ_ABORTED);
1283250963Sachim		}
1284250963Sachim		event->ev_callback = aac_cam_event;
1285250963Sachim		event->ev_arg = ccb;
1286250963Sachim		event->ev_type = AAC_EVENT_CMFREE;
1287250963Sachim		aacraid_add_event(sc, event);
1288250963Sachim		return (CAM_REQ_ABORTED);
1289250963Sachim	}
1290250963Sachim
1291250963Sachim	fib = cm->cm_fib;
1292250963Sachim	cm->cm_timestamp = time_uptime;
1293250963Sachim	cm->cm_datalen = 0;
1294250963Sachim
1295250963Sachim	fib->Header.Size =
1296250963Sachim		sizeof(struct aac_fib_header) + sizeof(struct aac_vmioctl);
1297250963Sachim	fib->Header.XferState =
1298250963Sachim		AAC_FIBSTATE_HOSTOWNED   |
1299250963Sachim		AAC_FIBSTATE_INITIALISED |
1300250963Sachim		AAC_FIBSTATE_EMPTY	 |
1301250963Sachim		AAC_FIBSTATE_FROMHOST	 |
1302250963Sachim		AAC_FIBSTATE_REXPECTED   |
1303250963Sachim		AAC_FIBSTATE_NORM	 |
1304250963Sachim		AAC_FIBSTATE_ASYNC	 |
1305250963Sachim		AAC_FIBSTATE_FAST_RESPONSE;
1306250963Sachim	fib->Header.Command = ContainerCommand;
1307250963Sachim
1308250963Sachim	vmi = (struct aac_vmioctl *)&fib->data[0];
1309250963Sachim	bzero(vmi, sizeof(struct aac_vmioctl));
1310250963Sachim
1311250963Sachim	vmi->Command = VM_Ioctl;
1312250963Sachim	vmi->ObjType = FT_DRIVE;
1313250963Sachim	vmi->MethId = sc->scsi_method_id;
1314250963Sachim	vmi->ObjId = 0;
1315250963Sachim	vmi->IoctlCmd = ResetBus;
1316250963Sachim
1317250963Sachim	rbc = (struct aac_resetbus *)&vmi->IoctlBuf[0];
1318250963Sachim	rbc->BusNumber = camsc->inf->BusNumber - 1;
1319250963Sachim
1320250963Sachim	if (aacraid_wait_command(cm) != 0) {
1321250963Sachim		device_printf(sc->aac_dev,"Error sending ResetBus command\n");
1322250963Sachim		rval = CAM_REQ_ABORTED;
1323250963Sachim	} else {
1324250963Sachim		rval = CAM_REQ_CMP;
1325250963Sachim	}
1326250963Sachim	aacraid_release_command(cm);
1327250963Sachim	return (rval);
1328250963Sachim}
1329250963Sachim
1330250963Sachimstatic u_int32_t
1331250963Sachimaac_cam_abort_ccb(struct cam_sim *sim, union ccb *ccb)
1332250963Sachim{
1333250963Sachim	return (CAM_UA_ABORT);
1334250963Sachim}
1335250963Sachim
1336250963Sachimstatic u_int32_t
1337250963Sachimaac_cam_term_io(struct cam_sim *sim, union ccb *ccb)
1338250963Sachim{
1339250963Sachim	return (CAM_UA_TERMIO);
1340250963Sachim}
1341250963Sachim
1342250963Sachimstatic int
1343250963Sachimaac_load_map_command_sg(struct aac_softc *sc, struct aac_command *cm)
1344250963Sachim{
1345250963Sachim	int error;
1346250963Sachim
1347250963Sachim	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
1348250963Sachim	error = bus_dmamap_load(sc->aac_buffer_dmat,
1349250963Sachim				cm->cm_datamap, cm->cm_data, cm->cm_datalen,
1350250963Sachim				aacraid_map_command_sg, cm, 0);
1351250963Sachim	if (error == EINPROGRESS) {
1352250963Sachim		fwprintf(sc, HBA_FLAGS_DBG_INIT_B, "freezing queue\n");
1353250963Sachim		sc->flags |= AAC_QUEUE_FRZN;
1354250963Sachim		error = 0;
1355250963Sachim	} else if (error != 0) {
1356250963Sachim		panic("aac_load_map_command_sg: unexpected error %d from "
1357250963Sachim	     		"busdma", error);
1358250963Sachim	}
1359250963Sachim	return(error);
1360250963Sachim}
1361250963Sachim
1362250963Sachim/*
1363250963Sachim * Start as much queued I/O as possible on the controller
1364250963Sachim */
1365250963Sachimvoid
1366250963Sachimaacraid_startio(struct aac_softc *sc)
1367250963Sachim{
1368250963Sachim	struct aac_command *cm;
1369250963Sachim
1370250963Sachim	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
1371250963Sachim
1372250963Sachim	for (;;) {
1373250963Sachim		if (sc->aac_state & AAC_STATE_RESET) {
1374250963Sachim			fwprintf(sc, HBA_FLAGS_DBG_ERROR_B, "AAC_STATE_RESET");
1375250963Sachim			break;
1376250963Sachim		}
1377250963Sachim		/*
1378250963Sachim		 * This flag might be set if the card is out of resources.
1379250963Sachim		 * Checking it here prevents an infinite loop of deferrals.
1380250963Sachim		 */
1381250963Sachim		if (sc->flags & AAC_QUEUE_FRZN) {
1382250963Sachim			fwprintf(sc, HBA_FLAGS_DBG_ERROR_B, "AAC_QUEUE_FRZN");
1383250963Sachim			break;
1384250963Sachim		}
1385250963Sachim
1386250963Sachim		/*
1387250963Sachim		 * Try to get a command that's been put off for lack of
1388250963Sachim		 * resources
1389250963Sachim		 */
1390250963Sachim		if (sc->flags & AAC_FLAGS_SYNC_MODE) {
1391250963Sachim			/* sync. transfer mode */
1392250963Sachim			if (sc->aac_sync_cm)
1393250963Sachim				break;
1394250963Sachim			cm = aac_dequeue_ready(sc);
1395250963Sachim			sc->aac_sync_cm = cm;
1396250963Sachim		} else {
1397250963Sachim			cm = aac_dequeue_ready(sc);
1398250963Sachim		}
1399250963Sachim
1400250963Sachim		/* nothing to do? */
1401250963Sachim		if (cm == NULL)
1402250963Sachim			break;
1403250963Sachim
1404250963Sachim		/* don't map more than once */
1405250963Sachim		if (cm->cm_flags & AAC_CMD_MAPPED)
1406250963Sachim			panic("aac: command %p already mapped", cm);
1407250963Sachim
1408250963Sachim		/*
1409250963Sachim		 * Set up the command to go to the controller.  If there are no
1410250963Sachim		 * data buffers associated with the command then it can bypass
1411250963Sachim		 * busdma.
1412250963Sachim		 */
1413250963Sachim		if (cm->cm_datalen)
1414250963Sachim			aac_load_map_command_sg(sc, cm);
1415250963Sachim		else
1416250963Sachim			aacraid_map_command_sg(cm, NULL, 0, 0);
1417250963Sachim	}
1418250963Sachim}
1419