1098ca2bdSWarner Losh /*-
2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
3718cf2ccSPedro F. Giffuni *
4fe3cb0e1SScott Long * Copyright (c) 2002 Adaptec, Inc.
5fe3cb0e1SScott Long * All rights reserved.
6fe3cb0e1SScott Long *
7fe3cb0e1SScott Long * Redistribution and use in source and binary forms, with or without
8fe3cb0e1SScott Long * modification, are permitted provided that the following conditions
9fe3cb0e1SScott Long * are met:
10fe3cb0e1SScott Long * 1. Redistributions of source code must retain the above copyright
11fe3cb0e1SScott Long * notice, this list of conditions and the following disclaimer.
12fe3cb0e1SScott Long * 2. Redistributions in binary form must reproduce the above copyright
13fe3cb0e1SScott Long * notice, this list of conditions and the following disclaimer in the
14fe3cb0e1SScott Long * documentation and/or other materials provided with the distribution.
15fe3cb0e1SScott Long *
16fe3cb0e1SScott Long * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17fe3cb0e1SScott Long * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18fe3cb0e1SScott Long * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19fe3cb0e1SScott Long * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20fe3cb0e1SScott Long * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21fe3cb0e1SScott Long * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22fe3cb0e1SScott Long * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23fe3cb0e1SScott Long * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24fe3cb0e1SScott Long * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25fe3cb0e1SScott Long * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26fe3cb0e1SScott Long * SUCH DAMAGE.
27fe3cb0e1SScott Long */
28fe3cb0e1SScott Long
29aad970f1SDavid E. O'Brien #include <sys/cdefs.h>
30fe3cb0e1SScott Long /*
31fe3cb0e1SScott Long * CAM front-end for communicating with non-DASD devices
32fe3cb0e1SScott Long */
33fe3cb0e1SScott Long
34fe3cb0e1SScott Long #include "opt_aac.h"
35fe3cb0e1SScott Long
36fe3cb0e1SScott Long #include <sys/param.h>
37fe3cb0e1SScott Long #include <sys/systm.h>
38fe3cb0e1SScott Long #include <sys/kernel.h>
39fe3cb0e1SScott Long #include <sys/sysctl.h>
40851f59d7SEd Maste #include <sys/lock.h>
41fe3cb0e1SScott Long #include <sys/malloc.h>
42fe12f24bSPoul-Henning Kamp #include <sys/module.h>
43851f59d7SEd Maste #include <sys/mutex.h>
44fe3cb0e1SScott Long
45fe3cb0e1SScott Long #include <cam/cam.h>
46fe3cb0e1SScott Long #include <cam/cam_ccb.h>
47fe3cb0e1SScott Long #include <cam/cam_debug.h>
48851f59d7SEd Maste #include <cam/cam_periph.h>
49fe3cb0e1SScott Long #include <cam/cam_sim.h>
50fe3cb0e1SScott Long #include <cam/cam_xpt_sim.h>
51fe3cb0e1SScott Long #include <cam/scsi/scsi_all.h>
52fe3cb0e1SScott Long #include <cam/scsi/scsi_message.h>
53fe3cb0e1SScott Long
54fe3cb0e1SScott Long #include <sys/bus.h>
55fe3cb0e1SScott Long #include <sys/conf.h>
56fe3cb0e1SScott Long #include <sys/disk.h>
57fe3cb0e1SScott Long
58fe3cb0e1SScott Long #include <machine/md_var.h>
59fe3cb0e1SScott Long #include <machine/bus.h>
60fe3cb0e1SScott Long #include <sys/rman.h>
61fe3cb0e1SScott Long
62fe3cb0e1SScott Long #include <vm/vm.h>
63fe3cb0e1SScott Long #include <vm/pmap.h>
64fe3cb0e1SScott Long
65fe3cb0e1SScott Long #include <dev/aac/aacreg.h>
660b0594cdSScott Long #include <sys/aac_ioctl.h>
67fe3cb0e1SScott Long #include <dev/aac/aacvar.h>
68fe3cb0e1SScott Long
69fe3cb0e1SScott Long struct aac_cam {
70fe3cb0e1SScott Long device_t dev;
7170545d1aSScott Long struct aac_sim *inf;
72fe3cb0e1SScott Long struct cam_sim *sim;
73fe3cb0e1SScott Long struct cam_path *path;
74fe3cb0e1SScott Long };
75fe3cb0e1SScott Long
76fe3cb0e1SScott Long static int aac_cam_probe(device_t dev);
77fe3cb0e1SScott Long static int aac_cam_attach(device_t dev);
78fe3cb0e1SScott Long static int aac_cam_detach(device_t dev);
79fe3cb0e1SScott Long static void aac_cam_action(struct cam_sim *, union ccb *);
80fe3cb0e1SScott Long static void aac_cam_poll(struct cam_sim *);
81fe3cb0e1SScott Long static void aac_cam_complete(struct aac_command *);
82851f59d7SEd Maste static void aac_cam_rescan(struct aac_softc *sc, uint32_t channel,
83851f59d7SEd Maste uint32_t target_id);
84851f59d7SEd Maste
85fe3cb0e1SScott Long static u_int32_t aac_cam_reset_bus(struct cam_sim *, union ccb *);
86fe3cb0e1SScott Long static u_int32_t aac_cam_abort_ccb(struct cam_sim *, union ccb *);
87fe3cb0e1SScott Long static u_int32_t aac_cam_term_io(struct cam_sim *, union ccb *);
88fe3cb0e1SScott Long
89fe3cb0e1SScott Long static device_method_t aac_pass_methods[] = {
90fe3cb0e1SScott Long DEVMETHOD(device_probe, aac_cam_probe),
91fe3cb0e1SScott Long DEVMETHOD(device_attach, aac_cam_attach),
92fe3cb0e1SScott Long DEVMETHOD(device_detach, aac_cam_detach),
93da4882c2SMarius Strobl DEVMETHOD_END
94fe3cb0e1SScott Long };
95fe3cb0e1SScott Long
96fe3cb0e1SScott Long static driver_t aac_pass_driver = {
97fe3cb0e1SScott Long "aacp",
98fe3cb0e1SScott Long aac_pass_methods,
99fe3cb0e1SScott Long sizeof(struct aac_cam)
100fe3cb0e1SScott Long };
101fe3cb0e1SScott Long
1025a2ae6d0SJohn Baldwin DRIVER_MODULE(aacp, aac, aac_pass_driver, NULL, NULL);
103fe3cb0e1SScott Long MODULE_DEPEND(aacp, cam, 1, 1, 1);
104fe3cb0e1SScott Long
105d745c852SEd Schouten static MALLOC_DEFINE(M_AACCAM, "aaccam", "AAC CAM info");
106fe3cb0e1SScott Long
1077cb209f5SScott Long static void
aac_cam_rescan(struct aac_softc * sc,uint32_t channel,uint32_t target_id)108851f59d7SEd Maste aac_cam_rescan(struct aac_softc *sc, uint32_t channel, uint32_t target_id)
109851f59d7SEd Maste {
110851f59d7SEd Maste union ccb *ccb;
111851f59d7SEd Maste struct aac_sim *sim;
112851f59d7SEd Maste struct aac_cam *camsc;
113851f59d7SEd Maste
114851f59d7SEd Maste if (target_id == AAC_CAM_TARGET_WILDCARD)
115851f59d7SEd Maste target_id = CAM_TARGET_WILDCARD;
116851f59d7SEd Maste
117851f59d7SEd Maste TAILQ_FOREACH(sim, &sc->aac_sim_tqh, sim_link) {
118851f59d7SEd Maste camsc = sim->aac_cam;
119851f59d7SEd Maste if (camsc == NULL || camsc->inf == NULL ||
120851f59d7SEd Maste camsc->inf->BusNumber != channel)
121851f59d7SEd Maste continue;
122851f59d7SEd Maste
123851f59d7SEd Maste ccb = xpt_alloc_ccb_nowait();
124851f59d7SEd Maste if (ccb == NULL) {
125851f59d7SEd Maste device_printf(sc->aac_dev,
126851f59d7SEd Maste "Cannot allocate ccb for bus rescan.\n");
127851f59d7SEd Maste return;
128851f59d7SEd Maste }
129851f59d7SEd Maste
130e5dfa058SAlexander Motin if (xpt_create_path(&ccb->ccb_h.path, NULL,
131851f59d7SEd Maste cam_sim_path(camsc->sim),
132851f59d7SEd Maste target_id, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
133851f59d7SEd Maste xpt_free_ccb(ccb);
134851f59d7SEd Maste device_printf(sc->aac_dev,
135851f59d7SEd Maste "Cannot create path for bus rescan.\n");
136851f59d7SEd Maste return;
137851f59d7SEd Maste }
138851f59d7SEd Maste xpt_rescan(ccb);
139851f59d7SEd Maste break;
140851f59d7SEd Maste }
141851f59d7SEd Maste }
142851f59d7SEd Maste
143851f59d7SEd Maste static void
aac_cam_event(struct aac_softc * sc,struct aac_event * event,void * arg)1447cb209f5SScott Long aac_cam_event(struct aac_softc *sc, struct aac_event *event, void *arg)
1457cb209f5SScott Long {
146eb5cbaa0SEd Maste union ccb *ccb;
1477cb209f5SScott Long struct aac_cam *camsc;
1487cb209f5SScott Long
1497cb209f5SScott Long switch (event->ev_type) {
1507cb209f5SScott Long case AAC_EVENT_CMFREE:
151eb5cbaa0SEd Maste ccb = arg;
152eb5cbaa0SEd Maste camsc = ccb->ccb_h.sim_priv.entries[0].ptr;
1537cb209f5SScott Long free(event, M_AACCAM);
1547cb209f5SScott Long xpt_release_simq(camsc->sim, 1);
155eb5cbaa0SEd Maste ccb->ccb_h.status = CAM_REQUEUE_REQ;
156eb5cbaa0SEd Maste xpt_done(ccb);
1577cb209f5SScott Long break;
1587cb209f5SScott Long default:
1597cb209f5SScott Long device_printf(sc->aac_dev, "unknown event %d in aac_cam\n",
1607cb209f5SScott Long event->ev_type);
1617cb209f5SScott Long break;
1627cb209f5SScott Long }
1637cb209f5SScott Long }
1647cb209f5SScott Long
165fe3cb0e1SScott Long static int
aac_cam_probe(device_t dev)166fe3cb0e1SScott Long aac_cam_probe(device_t dev)
167fe3cb0e1SScott Long {
16831a0399eSEd Maste fwprintf(NULL, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
169fe3cb0e1SScott Long
170fe3cb0e1SScott Long return (0);
171fe3cb0e1SScott Long }
172fe3cb0e1SScott Long
173fe3cb0e1SScott Long static int
aac_cam_detach(device_t dev)174fe3cb0e1SScott Long aac_cam_detach(device_t dev)
175fe3cb0e1SScott Long {
176eb5cbaa0SEd Maste struct aac_softc *sc;
177ddb8683eSScott Long struct aac_cam *camsc;
17831a0399eSEd Maste fwprintf(NULL, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
179fe3cb0e1SScott Long
180ddb8683eSScott Long camsc = (struct aac_cam *)device_get_softc(dev);
181eb5cbaa0SEd Maste sc = camsc->inf->aac_sc;
182851f59d7SEd Maste camsc->inf->aac_cam = NULL;
183ddb8683eSScott Long
184eb5cbaa0SEd Maste mtx_lock(&sc->aac_io_lock);
185c5a8036cSScott Long
186ddb8683eSScott Long xpt_async(AC_LOST_DEVICE, camsc->path, NULL);
187ddb8683eSScott Long xpt_free_path(camsc->path);
188ddb8683eSScott Long xpt_bus_deregister(cam_sim_path(camsc->sim));
189ddb8683eSScott Long cam_sim_free(camsc->sim, /*free_devq*/TRUE);
190ddb8683eSScott Long
191851f59d7SEd Maste sc->cam_rescan_cb = NULL;
192851f59d7SEd Maste
193eb5cbaa0SEd Maste mtx_unlock(&sc->aac_io_lock);
194c5a8036cSScott Long
195ddb8683eSScott Long return (0);
196fe3cb0e1SScott Long }
197fe3cb0e1SScott Long
198fe3cb0e1SScott Long /*
199fe3cb0e1SScott Long * Register the driver as a CAM SIM
200fe3cb0e1SScott Long */
201fe3cb0e1SScott Long static int
aac_cam_attach(device_t dev)202fe3cb0e1SScott Long aac_cam_attach(device_t dev)
203fe3cb0e1SScott Long {
204fe3cb0e1SScott Long struct cam_devq *devq;
205fe3cb0e1SScott Long struct cam_sim *sim;
206fe3cb0e1SScott Long struct cam_path *path;
207fe3cb0e1SScott Long struct aac_cam *camsc;
20870545d1aSScott Long struct aac_sim *inf;
209fe3cb0e1SScott Long
21031a0399eSEd Maste fwprintf(NULL, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
211fe3cb0e1SScott Long
212fe3cb0e1SScott Long camsc = (struct aac_cam *)device_get_softc(dev);
21370545d1aSScott Long inf = (struct aac_sim *)device_get_ivars(dev);
214fe3cb0e1SScott Long camsc->inf = inf;
215851f59d7SEd Maste camsc->inf->aac_cam = camsc;
216fe3cb0e1SScott Long
217fe3cb0e1SScott Long devq = cam_simq_alloc(inf->TargetsPerBus);
218fe3cb0e1SScott Long if (devq == NULL)
219fe3cb0e1SScott Long return (EIO);
220fe3cb0e1SScott Long
221fe3cb0e1SScott Long sim = cam_sim_alloc(aac_cam_action, aac_cam_poll, "aacp", camsc,
222eb5cbaa0SEd Maste device_get_unit(dev), &inf->aac_sc->aac_io_lock, 1, 1, devq);
223fe3cb0e1SScott Long if (sim == NULL) {
224fe3cb0e1SScott Long cam_simq_free(devq);
225fe3cb0e1SScott Long return (EIO);
226fe3cb0e1SScott Long }
227fe3cb0e1SScott Long
2281089f082SScott Long /* Since every bus has it's own sim, every bus 'appears' as bus 0 */
229eb5cbaa0SEd Maste mtx_lock(&inf->aac_sc->aac_io_lock);
230b50569b7SScott Long if (xpt_bus_register(sim, dev, 0) != CAM_SUCCESS) {
231fe3cb0e1SScott Long cam_sim_free(sim, TRUE);
232eb5cbaa0SEd Maste mtx_unlock(&inf->aac_sc->aac_io_lock);
233fe3cb0e1SScott Long return (EIO);
234fe3cb0e1SScott Long }
235fe3cb0e1SScott Long
236fe3cb0e1SScott Long if (xpt_create_path(&path, NULL, cam_sim_path(sim),
237fe3cb0e1SScott Long CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
238fe3cb0e1SScott Long xpt_bus_deregister(cam_sim_path(sim));
239fe3cb0e1SScott Long cam_sim_free(sim, TRUE);
240eb5cbaa0SEd Maste mtx_unlock(&inf->aac_sc->aac_io_lock);
241fe3cb0e1SScott Long return (EIO);
242fe3cb0e1SScott Long }
243851f59d7SEd Maste inf->aac_sc->cam_rescan_cb = aac_cam_rescan;
244eb5cbaa0SEd Maste mtx_unlock(&inf->aac_sc->aac_io_lock);
245fe3cb0e1SScott Long
246fe3cb0e1SScott Long camsc->sim = sim;
247fe3cb0e1SScott Long camsc->path = path;
248fe3cb0e1SScott Long
249fe3cb0e1SScott Long return (0);
250fe3cb0e1SScott Long }
251fe3cb0e1SScott Long
252fe3cb0e1SScott Long static void
aac_cam_action(struct cam_sim * sim,union ccb * ccb)253fe3cb0e1SScott Long aac_cam_action(struct cam_sim *sim, union ccb *ccb)
254fe3cb0e1SScott Long {
255fe3cb0e1SScott Long struct aac_cam *camsc;
256fe3cb0e1SScott Long struct aac_softc *sc;
257c89d07b9SEd Maste struct aac_srb *srb;
258fe3cb0e1SScott Long struct aac_fib *fib;
259fe3cb0e1SScott Long struct aac_command *cm;
260fe3cb0e1SScott Long
261fe3cb0e1SScott Long camsc = (struct aac_cam *)cam_sim_softc(sim);
262fe3cb0e1SScott Long sc = camsc->inf->aac_sc;
26331a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
264fe3cb0e1SScott Long
265fe3cb0e1SScott Long /* Synchronous ops, and ops that don't require communication with the
266fe3cb0e1SScott Long * controller */
267fe3cb0e1SScott Long switch(ccb->ccb_h.func_code) {
268fe3cb0e1SScott Long case XPT_SCSI_IO:
269fe3cb0e1SScott Long case XPT_RESET_DEV:
270fe3cb0e1SScott Long /* These are handled down below */
271fe3cb0e1SScott Long break;
272fe3cb0e1SScott Long case XPT_CALC_GEOMETRY:
273fe3cb0e1SScott Long {
274fe3cb0e1SScott Long struct ccb_calc_geometry *ccg;
275fe3cb0e1SScott Long u_int32_t size_mb;
276fe3cb0e1SScott Long u_int32_t secs_per_cylinder;
277fe3cb0e1SScott Long
278fe3cb0e1SScott Long ccg = &ccb->ccg;
279fe3cb0e1SScott Long size_mb = ccg->volume_size /
280fe3cb0e1SScott Long ((1024L * 1024L) / ccg->block_size);
281fe3cb0e1SScott Long if (size_mb >= (2 * 1024)) { /* 2GB */
282fe3cb0e1SScott Long ccg->heads = 255;
283fe3cb0e1SScott Long ccg->secs_per_track = 63;
284fe3cb0e1SScott Long } else if (size_mb >= (1 * 1024)) { /* 1GB */
285fe3cb0e1SScott Long ccg->heads = 128;
286fe3cb0e1SScott Long ccg->secs_per_track = 32;
287fe3cb0e1SScott Long } else {
288fe3cb0e1SScott Long ccg->heads = 64;
289fe3cb0e1SScott Long ccg->secs_per_track = 32;
290fe3cb0e1SScott Long }
291fe3cb0e1SScott Long secs_per_cylinder = ccg->heads * ccg->secs_per_track;
292fe3cb0e1SScott Long ccg->cylinders = ccg->volume_size / secs_per_cylinder;
293fe3cb0e1SScott Long
294fe3cb0e1SScott Long ccb->ccb_h.status = CAM_REQ_CMP;
295fe3cb0e1SScott Long xpt_done(ccb);
296fe3cb0e1SScott Long return;
297fe3cb0e1SScott Long }
298fe3cb0e1SScott Long case XPT_PATH_INQ:
299fe3cb0e1SScott Long {
300fe3cb0e1SScott Long struct ccb_pathinq *cpi = &ccb->cpi;
301fe3cb0e1SScott Long
302fe3cb0e1SScott Long cpi->version_num = 1;
303fe3cb0e1SScott Long cpi->hba_inquiry = PI_WIDE_16;
304fe3cb0e1SScott Long cpi->target_sprt = 0;
3052ffaffaaSScott Long
30623e876b1SJung-uk Kim /*
30723e876b1SJung-uk Kim * Resetting via the passthrough or parallel bus scan
30823e876b1SJung-uk Kim * causes problems.
30923e876b1SJung-uk Kim */
31023e876b1SJung-uk Kim cpi->hba_misc = PIM_NOBUSRESET | PIM_SEQSCAN;
311fe3cb0e1SScott Long cpi->hba_eng_cnt = 0;
312fe3cb0e1SScott Long cpi->max_target = camsc->inf->TargetsPerBus;
313fe3cb0e1SScott Long cpi->max_lun = 8; /* Per the controller spec */
314fe3cb0e1SScott Long cpi->initiator_id = camsc->inf->InitiatorBusId;
3151089f082SScott Long cpi->bus_id = camsc->inf->BusNumber;
316fe3cb0e1SScott Long cpi->base_transfer_speed = 3300;
3174195c7deSAlan Somers strlcpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
3184195c7deSAlan Somers strlcpy(cpi->hba_vid, "Adaptec", HBA_IDLEN);
3194195c7deSAlan Somers strlcpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
320fe3cb0e1SScott Long cpi->unit_number = cam_sim_unit(sim);
321fa9ed865SMatt Jacob cpi->transport = XPORT_SPI;
322fa9ed865SMatt Jacob cpi->transport_version = 2;
323fa9ed865SMatt Jacob cpi->protocol = PROTO_SCSI;
324fa9ed865SMatt Jacob cpi->protocol_version = SCSI_REV_2;
325fe3cb0e1SScott Long ccb->ccb_h.status = CAM_REQ_CMP;
326fe3cb0e1SScott Long xpt_done(ccb);
327fe3cb0e1SScott Long return;
328fe3cb0e1SScott Long }
329fe3cb0e1SScott Long case XPT_GET_TRAN_SETTINGS:
330fe3cb0e1SScott Long {
331fa9ed865SMatt Jacob struct ccb_trans_settings_scsi *scsi =
332fa9ed865SMatt Jacob &ccb->cts.proto_specific.scsi;
333fa9ed865SMatt Jacob struct ccb_trans_settings_spi *spi =
334fa9ed865SMatt Jacob &ccb->cts.xport_specific.spi;
335fa9ed865SMatt Jacob ccb->cts.protocol = PROTO_SCSI;
336fa9ed865SMatt Jacob ccb->cts.protocol_version = SCSI_REV_2;
337fa9ed865SMatt Jacob ccb->cts.transport = XPORT_SPI;
338fa9ed865SMatt Jacob ccb->cts.transport_version = 2;
339fa9ed865SMatt Jacob if (ccb->ccb_h.target_lun != CAM_LUN_WILDCARD) {
340fa9ed865SMatt Jacob scsi->valid = CTS_SCSI_VALID_TQ;
341fa9ed865SMatt Jacob spi->valid |= CTS_SPI_VALID_DISC;
342fa9ed865SMatt Jacob } else {
343fa9ed865SMatt Jacob scsi->valid = 0;
344fa9ed865SMatt Jacob }
3457cb209f5SScott Long ccb->ccb_h.status = CAM_REQ_CMP;
346fe3cb0e1SScott Long xpt_done(ccb);
347fe3cb0e1SScott Long return;
348fe3cb0e1SScott Long }
349fe3cb0e1SScott Long case XPT_SET_TRAN_SETTINGS:
350fe3cb0e1SScott Long ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
351fe3cb0e1SScott Long xpt_done(ccb);
352fe3cb0e1SScott Long return;
353fe3cb0e1SScott Long case XPT_RESET_BUS:
354a6d35632SScott Long if (!(sc->flags & AAC_FLAGS_CAM_NORESET)) {
355fe3cb0e1SScott Long ccb->ccb_h.status = aac_cam_reset_bus(sim, ccb);
356fe3cb0e1SScott Long } else {
357fe3cb0e1SScott Long ccb->ccb_h.status = CAM_REQ_CMP;
358fe3cb0e1SScott Long }
359fe3cb0e1SScott Long xpt_done(ccb);
360fe3cb0e1SScott Long return;
361fe3cb0e1SScott Long case XPT_ABORT:
362fe3cb0e1SScott Long ccb->ccb_h.status = aac_cam_abort_ccb(sim, ccb);
363fe3cb0e1SScott Long xpt_done(ccb);
364fe3cb0e1SScott Long return;
365fe3cb0e1SScott Long case XPT_TERM_IO:
366fe3cb0e1SScott Long ccb->ccb_h.status = aac_cam_term_io(sim, ccb);
367fe3cb0e1SScott Long xpt_done(ccb);
368fe3cb0e1SScott Long return;
369fe3cb0e1SScott Long default:
370fe3cb0e1SScott Long device_printf(sc->aac_dev, "Unsupported command 0x%x\n",
371fe3cb0e1SScott Long ccb->ccb_h.func_code);
372fe3cb0e1SScott Long ccb->ccb_h.status = CAM_PROVIDE_FAIL;
373fe3cb0e1SScott Long xpt_done(ccb);
374fe3cb0e1SScott Long return;
375fe3cb0e1SScott Long }
376fe3cb0e1SScott Long
377fe3cb0e1SScott Long /* Async ops that require communcation with the controller */
378fe3cb0e1SScott Long
379fe3cb0e1SScott Long if (aac_alloc_command(sc, &cm)) {
3807cb209f5SScott Long struct aac_event *event;
3817cb209f5SScott Long
382fe3cb0e1SScott Long xpt_freeze_simq(sim, 1);
383eb5cbaa0SEd Maste ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
384eb5cbaa0SEd Maste ccb->ccb_h.sim_priv.entries[0].ptr = camsc;
3857cb209f5SScott Long event = malloc(sizeof(struct aac_event), M_AACCAM,
3867cb209f5SScott Long M_NOWAIT | M_ZERO);
3877cb209f5SScott Long if (event == NULL) {
3887cb209f5SScott Long device_printf(sc->aac_dev,
3897cb209f5SScott Long "Warning, out of memory for event\n");
3907cb209f5SScott Long return;
3917cb209f5SScott Long }
3927cb209f5SScott Long event->ev_callback = aac_cam_event;
393eb5cbaa0SEd Maste event->ev_arg = ccb;
3947cb209f5SScott Long event->ev_type = AAC_EVENT_CMFREE;
3957cb209f5SScott Long aac_add_event(sc, event);
396fe3cb0e1SScott Long return;
397fe3cb0e1SScott Long }
398fe3cb0e1SScott Long
399fe3cb0e1SScott Long fib = cm->cm_fib;
400c89d07b9SEd Maste srb = (struct aac_srb *)&fib->data[0];
401fe3cb0e1SScott Long cm->cm_datalen = 0;
402fe3cb0e1SScott Long
403fe3cb0e1SScott Long switch (ccb->ccb_h.flags & CAM_DIR_MASK) {
404fe3cb0e1SScott Long case CAM_DIR_IN:
405fe3cb0e1SScott Long srb->flags = AAC_SRB_FLAGS_DATA_IN;
406fe3cb0e1SScott Long cm->cm_flags |= AAC_CMD_DATAIN;
407fe3cb0e1SScott Long break;
408fe3cb0e1SScott Long case CAM_DIR_OUT:
409fe3cb0e1SScott Long srb->flags = AAC_SRB_FLAGS_DATA_OUT;
410fe3cb0e1SScott Long cm->cm_flags |= AAC_CMD_DATAOUT;
411fe3cb0e1SScott Long break;
412fe3cb0e1SScott Long case CAM_DIR_NONE:
413fe3cb0e1SScott Long srb->flags = AAC_SRB_FLAGS_NO_DATA_XFER;
414fe3cb0e1SScott Long break;
415fe3cb0e1SScott Long default:
416fe3cb0e1SScott Long srb->flags = AAC_SRB_FLAGS_UNSPECIFIED_DIRECTION;
417fe3cb0e1SScott Long cm->cm_flags |= AAC_CMD_DATAIN | AAC_CMD_DATAOUT;
418fe3cb0e1SScott Long break;
419fe3cb0e1SScott Long }
420fe3cb0e1SScott Long
421fe3cb0e1SScott Long switch(ccb->ccb_h.func_code) {
422fe3cb0e1SScott Long case XPT_SCSI_IO:
423fe3cb0e1SScott Long {
424fe3cb0e1SScott Long struct ccb_scsiio *csio = &ccb->csio;
425fe3cb0e1SScott Long
426fe3cb0e1SScott Long srb->function = AAC_SRB_FUNC_EXECUTE_SCSI;
427fe3cb0e1SScott Long
428fe3cb0e1SScott Long /*
429fe3cb0e1SScott Long * Copy the CDB into the SRB. It's only 6-16 bytes,
430fe3cb0e1SScott Long * so a copy is not too expensive.
431fe3cb0e1SScott Long */
432fe3cb0e1SScott Long srb->cdb_len = csio->cdb_len;
433fe3cb0e1SScott Long if (ccb->ccb_h.flags & CAM_CDB_POINTER)
434fe3cb0e1SScott Long bcopy(csio->cdb_io.cdb_ptr, (u_int8_t *)&srb->cdb[0],
435fe3cb0e1SScott Long srb->cdb_len);
436fe3cb0e1SScott Long else
437fe3cb0e1SScott Long bcopy(csio->cdb_io.cdb_bytes, (u_int8_t *)&srb->cdb[0],
438fe3cb0e1SScott Long srb->cdb_len);
439fe3cb0e1SScott Long
4409bffabceSEd Maste /* Set command */
4419bffabceSEd Maste fib->Header.Command = (sc->flags & AAC_FLAGS_SG_64BIT) ?
4429bffabceSEd Maste ScsiPortCommandU64 : ScsiPortCommand;
4439bffabceSEd Maste
444fe3cb0e1SScott Long /* Map the s/g list. XXX 32bit addresses only! */
445fe3cb0e1SScott Long if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
446dd0b4fb6SKonstantin Belousov switch ((ccb->ccb_h.flags & CAM_DATA_MASK)) {
447dd0b4fb6SKonstantin Belousov case CAM_DATA_VADDR:
448fe3cb0e1SScott Long srb->data_len = csio->dxfer_len;
449fe3cb0e1SScott Long /*
450fe3cb0e1SScott Long * Arrange things so that the S/G
451fe3cb0e1SScott Long * map will get set up automagically
452fe3cb0e1SScott Long */
453fe3cb0e1SScott Long cm->cm_data = (void *)csio->data_ptr;
454fe3cb0e1SScott Long cm->cm_datalen = csio->dxfer_len;
4558e7e6335SEd Maste cm->cm_sgtable = &srb->sg_map;
456dd0b4fb6SKonstantin Belousov break;
457dd0b4fb6SKonstantin Belousov case CAM_DATA_PADDR:
458dd0b4fb6SKonstantin Belousov /* Send a 32bit command */
459dd0b4fb6SKonstantin Belousov fib->Header.Command = ScsiPortCommand;
460dd0b4fb6SKonstantin Belousov srb->sg_map.SgCount = 1;
461dd0b4fb6SKonstantin Belousov srb->sg_map.SgEntry[0].SgAddress =
462dd0b4fb6SKonstantin Belousov (uint32_t)(uintptr_t)csio->data_ptr;
463dd0b4fb6SKonstantin Belousov srb->sg_map.SgEntry[0].SgByteCount =
464dd0b4fb6SKonstantin Belousov csio->dxfer_len;
465dd0b4fb6SKonstantin Belousov srb->data_len = csio->dxfer_len;
466dd0b4fb6SKonstantin Belousov break;
467dd0b4fb6SKonstantin Belousov default:
468fe3cb0e1SScott Long /* XXX Need to handle multiple s/g elements */
469fe3cb0e1SScott Long panic("aac_cam: multiple s/g elements");
470fe3cb0e1SScott Long }
471fe3cb0e1SScott Long } else {
4728e7e6335SEd Maste srb->sg_map.SgCount = 0;
4738e7e6335SEd Maste srb->sg_map.SgEntry[0].SgByteCount = 0;
474fe3cb0e1SScott Long srb->data_len = 0;
475fe3cb0e1SScott Long }
476fe3cb0e1SScott Long
477fe3cb0e1SScott Long break;
478fe3cb0e1SScott Long }
479fe3cb0e1SScott Long case XPT_RESET_DEV:
480a6d35632SScott Long if (!(sc->flags & AAC_FLAGS_CAM_NORESET)) {
481fe3cb0e1SScott Long srb->function = AAC_SRB_FUNC_RESET_DEVICE;
482fe3cb0e1SScott Long break;
483fe3cb0e1SScott Long } else {
484fe3cb0e1SScott Long ccb->ccb_h.status = CAM_REQ_CMP;
485fe3cb0e1SScott Long xpt_done(ccb);
486fe3cb0e1SScott Long return;
487fe3cb0e1SScott Long }
488fe3cb0e1SScott Long default:
489fe3cb0e1SScott Long break;
490fe3cb0e1SScott Long }
491fe3cb0e1SScott Long
4921089f082SScott Long srb->bus = camsc->inf->BusNumber; /* Bus number relative to the card */
493fe3cb0e1SScott Long srb->target = ccb->ccb_h.target_id;
494fe3cb0e1SScott Long srb->lun = ccb->ccb_h.target_lun;
495fe3cb0e1SScott Long srb->timeout = ccb->ccb_h.timeout; /* XXX */
496fe3cb0e1SScott Long srb->retry_limit = 0;
497fe3cb0e1SScott Long
498fe3cb0e1SScott Long cm->cm_complete = aac_cam_complete;
499fe3cb0e1SScott Long cm->cm_private = ccb;
500552d3432SScott Long cm->cm_timestamp = time_uptime;
501fe3cb0e1SScott Long
502fe3cb0e1SScott Long fib->Header.XferState =
503fe3cb0e1SScott Long AAC_FIBSTATE_HOSTOWNED |
504fe3cb0e1SScott Long AAC_FIBSTATE_INITIALISED |
505fe3cb0e1SScott Long AAC_FIBSTATE_FROMHOST |
506fe3cb0e1SScott Long AAC_FIBSTATE_REXPECTED |
507fe3cb0e1SScott Long AAC_FIBSTATE_NORM;
508fe3cb0e1SScott Long fib->Header.Size = sizeof(struct aac_fib_header) +
509c89d07b9SEd Maste sizeof(struct aac_srb);
510fe3cb0e1SScott Long
511fe3cb0e1SScott Long aac_enqueue_ready(cm);
512fe3cb0e1SScott Long aac_startio(cm->cm_sc);
513fe3cb0e1SScott Long }
514fe3cb0e1SScott Long
515fe3cb0e1SScott Long static void
aac_cam_poll(struct cam_sim * sim)516fe3cb0e1SScott Long aac_cam_poll(struct cam_sim *sim)
517fe3cb0e1SScott Long {
518fe3cb0e1SScott Long /*
519fe3cb0e1SScott Long * Pinging the interrupt routine isn't very safe, nor is it
520fe3cb0e1SScott Long * really necessary. Do nothing.
521fe3cb0e1SScott Long */
522fe3cb0e1SScott Long }
523fe3cb0e1SScott Long
524fe3cb0e1SScott Long static void
aac_cam_fix_inquiry(struct aac_softc * sc,union ccb * ccb)525a916893fSRyan Stone aac_cam_fix_inquiry(struct aac_softc *sc, union ccb *ccb)
526a916893fSRyan Stone {
527a916893fSRyan Stone struct scsi_inquiry_data *inq;
528a916893fSRyan Stone uint8_t *data;
529a916893fSRyan Stone uint8_t device, qual;
530a916893fSRyan Stone
531a916893fSRyan Stone /* If this is an inquiry command, fake things out */
532a916893fSRyan Stone if (ccb->ccb_h.flags & CAM_CDB_POINTER)
533a916893fSRyan Stone data = ccb->csio.cdb_io.cdb_ptr;
534a916893fSRyan Stone else
535a916893fSRyan Stone data = ccb->csio.cdb_io.cdb_bytes;
536a916893fSRyan Stone
537a916893fSRyan Stone if (data[0] != INQUIRY)
538a916893fSRyan Stone return;
539a916893fSRyan Stone
540a916893fSRyan Stone if (ccb->ccb_h.status == CAM_REQ_CMP) {
541a916893fSRyan Stone inq = (struct scsi_inquiry_data *)ccb->csio.data_ptr;
542a916893fSRyan Stone device = SID_TYPE(inq);
543a916893fSRyan Stone qual = SID_QUAL(inq);
544a916893fSRyan Stone
545a916893fSRyan Stone /*
546a916893fSRyan Stone * We want DASD and PROC devices to only be
547a916893fSRyan Stone * visible through the pass device.
548a916893fSRyan Stone */
549a916893fSRyan Stone if (((device == T_DIRECT) ||
550a916893fSRyan Stone (device == T_PROCESSOR) ||
551a916893fSRyan Stone (sc->flags & AAC_FLAGS_CAM_PASSONLY))) {
552a916893fSRyan Stone /*
553a916893fSRyan Stone * Some aac(4) adapters will always report that a direct
554a916893fSRyan Stone * access device is offline in response to a INQUIRY
555453130d9SPedro F. Giffuni * command that does not retrieve vital product data.
556a916893fSRyan Stone * Force the qualifier to connected so that upper layers
557a916893fSRyan Stone * correctly recognize that a disk is present.
558a916893fSRyan Stone */
559a916893fSRyan Stone if ((data[1] & SI_EVPD) == 0 && device == T_DIRECT &&
560a916893fSRyan Stone qual == SID_QUAL_LU_OFFLINE)
561a916893fSRyan Stone qual = SID_QUAL_LU_CONNECTED;
562a916893fSRyan Stone ccb->csio.data_ptr[0] = (qual << 5) | T_NODEVICE;
563a916893fSRyan Stone }
564a916893fSRyan Stone } else if (ccb->ccb_h.status == CAM_SEL_TIMEOUT &&
565a916893fSRyan Stone ccb->ccb_h.target_lun != 0) {
566a916893fSRyan Stone /* fix for INQUIRYs on Lun>0 */
567a916893fSRyan Stone ccb->ccb_h.status = CAM_DEV_NOT_THERE;
568a916893fSRyan Stone }
569a916893fSRyan Stone }
570a916893fSRyan Stone
571a916893fSRyan Stone static void
aac_cam_complete(struct aac_command * cm)572fe3cb0e1SScott Long aac_cam_complete(struct aac_command *cm)
573fe3cb0e1SScott Long {
574fe3cb0e1SScott Long union ccb *ccb;
575fe3cb0e1SScott Long struct aac_srb_response *srbr;
576fe3cb0e1SScott Long struct aac_softc *sc;
5771e5addb7SMarius Strobl int sense_returned;
578fe3cb0e1SScott Long
579fe3cb0e1SScott Long sc = cm->cm_sc;
58031a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
581fe3cb0e1SScott Long ccb = cm->cm_private;
582fe3cb0e1SScott Long srbr = (struct aac_srb_response *)&cm->cm_fib->data[0];
583fe3cb0e1SScott Long
584fe3cb0e1SScott Long if (srbr->fib_status != 0) {
585fe3cb0e1SScott Long device_printf(sc->aac_dev, "Passthru FIB failed!\n");
586fe3cb0e1SScott Long ccb->ccb_h.status = CAM_REQ_ABORTED;
587fe3cb0e1SScott Long } else {
588fe3cb0e1SScott Long /*
589fe3cb0e1SScott Long * The SRB error codes just happen to match the CAM error
590453130d9SPedro F. Giffuni * codes. How convenient!
591fe3cb0e1SScott Long */
592fe3cb0e1SScott Long ccb->ccb_h.status = srbr->srb_status;
593fe3cb0e1SScott Long
594fe3cb0e1SScott Long /* Take care of SCSI_IO ops. */
595fe3cb0e1SScott Long if (ccb->ccb_h.func_code == XPT_SCSI_IO) {
596fe3cb0e1SScott Long ccb->csio.scsi_status = srbr->scsi_status;
597fe3cb0e1SScott Long
598fe3cb0e1SScott Long /* Take care of autosense */
599fe3cb0e1SScott Long if (srbr->sense_len) {
6001e5addb7SMarius Strobl sense_returned = srbr->sense_len;
6011e5addb7SMarius Strobl if (sense_returned < ccb->csio.sense_len)
6021e5addb7SMarius Strobl ccb->csio.sense_resid =
6031e5addb7SMarius Strobl ccb->csio.sense_len -
6041e5addb7SMarius Strobl sense_returned;
6051e5addb7SMarius Strobl else
6061e5addb7SMarius Strobl ccb->csio.sense_resid = 0;
6071e5addb7SMarius Strobl bzero(&ccb->csio.sense_data,
6081e5addb7SMarius Strobl sizeof(struct scsi_sense_data));
609fe3cb0e1SScott Long bcopy(&srbr->sense[0], &ccb->csio.sense_data,
6101e5addb7SMarius Strobl min(ccb->csio.sense_len, sense_returned));
611fe3cb0e1SScott Long ccb->ccb_h.status |= CAM_AUTOSNS_VALID;
6127cb209f5SScott Long // scsi_sense_print(&ccb->csio);
613fe3cb0e1SScott Long }
614fe3cb0e1SScott Long
615a916893fSRyan Stone aac_cam_fix_inquiry(sc, ccb);
616fe3cb0e1SScott Long }
617fe3cb0e1SScott Long }
618fe3cb0e1SScott Long
619fe3cb0e1SScott Long aac_release_command(cm);
620fe3cb0e1SScott Long xpt_done(ccb);
621fe3cb0e1SScott Long }
622fe3cb0e1SScott Long
623fe3cb0e1SScott Long static u_int32_t
aac_cam_reset_bus(struct cam_sim * sim,union ccb * ccb)624fe3cb0e1SScott Long aac_cam_reset_bus(struct cam_sim *sim, union ccb *ccb)
625fe3cb0e1SScott Long {
626fe3cb0e1SScott Long struct aac_fib *fib;
627fe3cb0e1SScott Long struct aac_softc *sc;
628fe3cb0e1SScott Long struct aac_cam *camsc;
629fe3cb0e1SScott Long struct aac_vmioctl *vmi;
630fe3cb0e1SScott Long struct aac_resetbus *rbc;
631fe3cb0e1SScott Long int e;
632fe3cb0e1SScott Long
633fe3cb0e1SScott Long camsc = (struct aac_cam *)cam_sim_softc(sim);
634fe3cb0e1SScott Long sc = camsc->inf->aac_sc;
635fe3cb0e1SScott Long
636fe3cb0e1SScott Long if (sc == NULL) {
637dbb34a64SEd Maste printf("aac: Null sc?\n");
638fe3cb0e1SScott Long return (CAM_REQ_ABORTED);
639fe3cb0e1SScott Long }
640fe3cb0e1SScott Long
64103b5fe51SScott Long aac_alloc_sync_fib(sc, &fib);
642fe3cb0e1SScott Long
643fe3cb0e1SScott Long vmi = (struct aac_vmioctl *)&fib->data[0];
64439ee03c3SScott Long bzero(vmi, sizeof(struct aac_vmioctl));
64539ee03c3SScott Long
646fe3cb0e1SScott Long vmi->Command = VM_Ioctl;
647fe3cb0e1SScott Long vmi->ObjType = FT_DRIVE;
648fe3cb0e1SScott Long vmi->MethId = sc->scsi_method_id;
649fe3cb0e1SScott Long vmi->ObjId = 0;
650fe3cb0e1SScott Long vmi->IoctlCmd = ResetBus;
651fe3cb0e1SScott Long
652fe3cb0e1SScott Long rbc = (struct aac_resetbus *)&vmi->IoctlBuf[0];
6531089f082SScott Long rbc->BusNumber = camsc->inf->BusNumber;
654fe3cb0e1SScott Long
655fe3cb0e1SScott Long e = aac_sync_fib(sc, ContainerCommand, 0, fib,
656fe3cb0e1SScott Long sizeof(struct aac_vmioctl));
657fe3cb0e1SScott Long if (e) {
6582ffaffaaSScott Long device_printf(sc->aac_dev,"Error %d sending ResetBus command\n",
659fe3cb0e1SScott Long e);
660fe3cb0e1SScott Long aac_release_sync_fib(sc);
661fe3cb0e1SScott Long return (CAM_REQ_ABORTED);
662fe3cb0e1SScott Long }
663fe3cb0e1SScott Long
664fe3cb0e1SScott Long aac_release_sync_fib(sc);
665fe3cb0e1SScott Long return (CAM_REQ_CMP);
666fe3cb0e1SScott Long }
667fe3cb0e1SScott Long
668fe3cb0e1SScott Long static u_int32_t
aac_cam_abort_ccb(struct cam_sim * sim,union ccb * ccb)669fe3cb0e1SScott Long aac_cam_abort_ccb(struct cam_sim *sim, union ccb *ccb)
670fe3cb0e1SScott Long {
671fe3cb0e1SScott Long return (CAM_UA_ABORT);
672fe3cb0e1SScott Long }
673fe3cb0e1SScott Long
674fe3cb0e1SScott Long static u_int32_t
aac_cam_term_io(struct cam_sim * sim,union ccb * ccb)675fe3cb0e1SScott Long aac_cam_term_io(struct cam_sim *sim, union ccb *ccb)
676fe3cb0e1SScott Long {
677fe3cb0e1SScott Long return (CAM_UA_TERMIO);
678fe3cb0e1SScott Long }
679