xref: /freebsd/sys/powerpc/pseries/phyp_vscsi.c (revision fdafd315ad0d0f28a11b9fb4476a9ab059c62b92)
1391dff86SNathan Whitehorn /*-
2*4d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
371e3c308SPedro F. Giffuni  *
4391dff86SNathan Whitehorn  * Copyright 2013 Nathan Whitehorn
5391dff86SNathan Whitehorn  * All rights reserved.
6391dff86SNathan Whitehorn  *
7391dff86SNathan Whitehorn  * Redistribution and use in source and binary forms, with or without
8391dff86SNathan Whitehorn  * modification, are permitted provided that the following conditions
9391dff86SNathan Whitehorn  * are met:
10391dff86SNathan Whitehorn  * 1. Redistributions of source code must retain the above copyright
11391dff86SNathan Whitehorn  *    notice, this list of conditions and the following disclaimer.
12391dff86SNathan Whitehorn  * 2. Redistributions in binary form must reproduce the above copyright
13391dff86SNathan Whitehorn  *    notice, this list of conditions and the following disclaimer in the
14391dff86SNathan Whitehorn  *    documentation and/or other materials provided with the distribution.
15391dff86SNathan Whitehorn  *
16391dff86SNathan Whitehorn  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17391dff86SNathan Whitehorn  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18391dff86SNathan Whitehorn  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19391dff86SNathan Whitehorn  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20391dff86SNathan Whitehorn  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21391dff86SNathan Whitehorn  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22391dff86SNathan Whitehorn  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23391dff86SNathan Whitehorn  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24391dff86SNathan Whitehorn  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25391dff86SNathan Whitehorn  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26391dff86SNathan Whitehorn  * SUCH DAMAGE.
27391dff86SNathan Whitehorn  */
28391dff86SNathan Whitehorn 
29391dff86SNathan Whitehorn #include <sys/param.h>
30391dff86SNathan Whitehorn #include <sys/systm.h>
31391dff86SNathan Whitehorn #include <sys/kernel.h>
32391dff86SNathan Whitehorn #include <sys/malloc.h>
33391dff86SNathan Whitehorn #include <sys/module.h>
34391dff86SNathan Whitehorn #include <sys/selinfo.h>
35391dff86SNathan Whitehorn #include <sys/bus.h>
36391dff86SNathan Whitehorn #include <sys/conf.h>
37391dff86SNathan Whitehorn #include <sys/eventhandler.h>
38391dff86SNathan Whitehorn #include <sys/rman.h>
39391dff86SNathan Whitehorn #include <sys/bus_dma.h>
40391dff86SNathan Whitehorn #include <sys/bio.h>
41391dff86SNathan Whitehorn #include <sys/ioccom.h>
42391dff86SNathan Whitehorn #include <sys/uio.h>
43391dff86SNathan Whitehorn #include <sys/proc.h>
44391dff86SNathan Whitehorn #include <sys/signalvar.h>
45391dff86SNathan Whitehorn #include <sys/sysctl.h>
46391dff86SNathan Whitehorn #include <sys/endian.h>
47391dff86SNathan Whitehorn #include <sys/vmem.h>
48391dff86SNathan Whitehorn 
49391dff86SNathan Whitehorn #include <cam/cam.h>
50391dff86SNathan Whitehorn #include <cam/cam_ccb.h>
51391dff86SNathan Whitehorn #include <cam/cam_debug.h>
52391dff86SNathan Whitehorn #include <cam/cam_periph.h>
53391dff86SNathan Whitehorn #include <cam/cam_sim.h>
54391dff86SNathan Whitehorn #include <cam/cam_xpt_periph.h>
55391dff86SNathan Whitehorn #include <cam/cam_xpt_sim.h>
56391dff86SNathan Whitehorn #include <cam/scsi/scsi_all.h>
57391dff86SNathan Whitehorn #include <cam/scsi/scsi_message.h>
58391dff86SNathan Whitehorn 
59391dff86SNathan Whitehorn #include <dev/ofw/openfirm.h>
60391dff86SNathan Whitehorn #include <dev/ofw/ofw_bus.h>
61391dff86SNathan Whitehorn #include <dev/ofw/ofw_bus_subr.h>
62391dff86SNathan Whitehorn 
63391dff86SNathan Whitehorn #include <machine/bus.h>
64391dff86SNathan Whitehorn #include <machine/resource.h>
65391dff86SNathan Whitehorn 
66391dff86SNathan Whitehorn #include <powerpc/pseries/phyp-hvcall.h>
67391dff86SNathan Whitehorn 
68391dff86SNathan Whitehorn struct vscsi_softc;
69391dff86SNathan Whitehorn 
70391dff86SNathan Whitehorn /* VSCSI CRQ format from table 260 of PAPR spec 2.4 (page 760) */
71391dff86SNathan Whitehorn struct vscsi_crq {
72391dff86SNathan Whitehorn 	uint8_t valid;
73391dff86SNathan Whitehorn 	uint8_t format;
74391dff86SNathan Whitehorn 	uint8_t reserved;
75391dff86SNathan Whitehorn 	uint8_t status;
76391dff86SNathan Whitehorn 	uint16_t timeout;
77391dff86SNathan Whitehorn 	uint16_t iu_length;
78391dff86SNathan Whitehorn 	uint64_t iu_data;
79391dff86SNathan Whitehorn };
80391dff86SNathan Whitehorn 
81391dff86SNathan Whitehorn struct vscsi_xfer {
82391dff86SNathan Whitehorn         TAILQ_ENTRY(vscsi_xfer) queue;
83391dff86SNathan Whitehorn         struct vscsi_softc *sc;
84391dff86SNathan Whitehorn         union ccb *ccb;
85391dff86SNathan Whitehorn         bus_dmamap_t dmamap;
86391dff86SNathan Whitehorn         uint64_t tag;
87391dff86SNathan Whitehorn 
88391dff86SNathan Whitehorn 	vmem_addr_t srp_iu_offset;
89391dff86SNathan Whitehorn 	vmem_size_t srp_iu_size;
90391dff86SNathan Whitehorn };
91391dff86SNathan Whitehorn 
92391dff86SNathan Whitehorn TAILQ_HEAD(vscsi_xferq, vscsi_xfer);
93391dff86SNathan Whitehorn 
94391dff86SNathan Whitehorn struct vscsi_softc {
95391dff86SNathan Whitehorn 	device_t	dev;
96391dff86SNathan Whitehorn 	struct cam_devq *devq;
97391dff86SNathan Whitehorn 	struct cam_sim	*sim;
98391dff86SNathan Whitehorn 	struct cam_path	*path;
99391dff86SNathan Whitehorn 	struct mtx io_lock;
100391dff86SNathan Whitehorn 
101391dff86SNathan Whitehorn 	cell_t		unit;
102391dff86SNathan Whitehorn 	int		bus_initialized;
103391dff86SNathan Whitehorn 	int		bus_logged_in;
104391dff86SNathan Whitehorn 	int		max_transactions;
105391dff86SNathan Whitehorn 
106391dff86SNathan Whitehorn 	int		irqid;
107391dff86SNathan Whitehorn 	struct resource	*irq;
108391dff86SNathan Whitehorn 	void		*irq_cookie;
109391dff86SNathan Whitehorn 
110391dff86SNathan Whitehorn 	bus_dma_tag_t	crq_tag;
111391dff86SNathan Whitehorn 	struct vscsi_crq *crq_queue;
112391dff86SNathan Whitehorn 	int		n_crqs, cur_crq;
113391dff86SNathan Whitehorn 	bus_dmamap_t	crq_map;
114391dff86SNathan Whitehorn 	bus_addr_t	crq_phys;
115391dff86SNathan Whitehorn 
116391dff86SNathan Whitehorn 	vmem_t		*srp_iu_arena;
117391dff86SNathan Whitehorn 	void		*srp_iu_queue;
118391dff86SNathan Whitehorn 	bus_addr_t	srp_iu_phys;
119391dff86SNathan Whitehorn 
120391dff86SNathan Whitehorn 	bus_dma_tag_t	data_tag;
121391dff86SNathan Whitehorn 
122391dff86SNathan Whitehorn 	struct vscsi_xfer loginxp;
123391dff86SNathan Whitehorn 	struct vscsi_xfer *xfer;
124391dff86SNathan Whitehorn 	struct vscsi_xferq active_xferq;
125391dff86SNathan Whitehorn 	struct vscsi_xferq free_xferq;
126391dff86SNathan Whitehorn };
127391dff86SNathan Whitehorn 
128391dff86SNathan Whitehorn struct srp_login {
129391dff86SNathan Whitehorn 	uint8_t type;
130391dff86SNathan Whitehorn 	uint8_t reserved[7];
131391dff86SNathan Whitehorn 	uint64_t tag;
132391dff86SNathan Whitehorn 	uint64_t max_cmd_length;
133391dff86SNathan Whitehorn 	uint32_t reserved2;
134391dff86SNathan Whitehorn 	uint16_t buffer_formats;
135391dff86SNathan Whitehorn 	uint8_t flags;
136391dff86SNathan Whitehorn 	uint8_t reserved3[5];
137391dff86SNathan Whitehorn 	uint8_t initiator_port_id[16];
138391dff86SNathan Whitehorn 	uint8_t target_port_id[16];
139391dff86SNathan Whitehorn } __packed;
140391dff86SNathan Whitehorn 
141391dff86SNathan Whitehorn struct srp_login_rsp {
142391dff86SNathan Whitehorn 	uint8_t type;
143391dff86SNathan Whitehorn 	uint8_t reserved[3];
144391dff86SNathan Whitehorn 	uint32_t request_limit_delta;
145391dff86SNathan Whitehorn 	uint8_t tag;
146391dff86SNathan Whitehorn 	uint32_t max_i_to_t_len;
147391dff86SNathan Whitehorn 	uint32_t max_t_to_i_len;
148391dff86SNathan Whitehorn 	uint16_t buffer_formats;
149391dff86SNathan Whitehorn 	uint8_t flags;
150391dff86SNathan Whitehorn 	/* Some reserved bits follow */
151391dff86SNathan Whitehorn } __packed;
152391dff86SNathan Whitehorn 
153391dff86SNathan Whitehorn struct srp_cmd {
154391dff86SNathan Whitehorn 	uint8_t type;
155391dff86SNathan Whitehorn 	uint8_t flags1;
156391dff86SNathan Whitehorn 	uint8_t reserved[3];
157391dff86SNathan Whitehorn 	uint8_t formats;
158391dff86SNathan Whitehorn 	uint8_t out_buffer_count;
159391dff86SNathan Whitehorn 	uint8_t in_buffer_count;
160391dff86SNathan Whitehorn 	uint64_t tag;
161391dff86SNathan Whitehorn 	uint32_t reserved2;
162391dff86SNathan Whitehorn 	uint64_t lun;
163391dff86SNathan Whitehorn 	uint8_t reserved3[3];
164391dff86SNathan Whitehorn 	uint8_t additional_cdb;
165391dff86SNathan Whitehorn 	uint8_t cdb[16];
166391dff86SNathan Whitehorn 	uint8_t data_payload[0];
167391dff86SNathan Whitehorn } __packed;
168391dff86SNathan Whitehorn 
169391dff86SNathan Whitehorn struct srp_rsp {
170391dff86SNathan Whitehorn 	uint8_t type;
171391dff86SNathan Whitehorn 	uint8_t reserved[3];
172391dff86SNathan Whitehorn 	uint32_t request_limit_delta;
173391dff86SNathan Whitehorn 	uint64_t tag;
174391dff86SNathan Whitehorn 	uint16_t reserved2;
175391dff86SNathan Whitehorn 	uint8_t flags;
176391dff86SNathan Whitehorn 	uint8_t status;
177391dff86SNathan Whitehorn 	uint32_t data_out_resid;
178391dff86SNathan Whitehorn 	uint32_t data_in_resid;
179391dff86SNathan Whitehorn 	uint32_t sense_data_len;
180391dff86SNathan Whitehorn 	uint32_t response_data_len;
181391dff86SNathan Whitehorn 	uint8_t data_payload[0];
182391dff86SNathan Whitehorn } __packed;
183391dff86SNathan Whitehorn 
184391dff86SNathan Whitehorn struct srp_tsk_mgmt {
185391dff86SNathan Whitehorn 	uint8_t type;
186391dff86SNathan Whitehorn 	uint8_t reserved[7];
187391dff86SNathan Whitehorn 	uint64_t tag;
188391dff86SNathan Whitehorn 	uint32_t reserved2;
189391dff86SNathan Whitehorn 	uint64_t lun;
190391dff86SNathan Whitehorn 	uint8_t reserved3[2];
191391dff86SNathan Whitehorn 	uint8_t function;
192391dff86SNathan Whitehorn 	uint8_t reserved4;
193391dff86SNathan Whitehorn 	uint64_t manage_tag;
194391dff86SNathan Whitehorn 	uint64_t reserved5;
195391dff86SNathan Whitehorn } __packed;
196391dff86SNathan Whitehorn 
197391dff86SNathan Whitehorn /* Message code type */
198391dff86SNathan Whitehorn #define SRP_LOGIN_REQ	0x00
199391dff86SNathan Whitehorn #define SRP_TSK_MGMT	0x01
200391dff86SNathan Whitehorn #define SRP_CMD		0x02
201391dff86SNathan Whitehorn #define SRP_I_LOGOUT	0x03
202391dff86SNathan Whitehorn 
203391dff86SNathan Whitehorn #define SRP_LOGIN_RSP	0xC0
204391dff86SNathan Whitehorn #define SRP_RSP		0xC1
205391dff86SNathan Whitehorn #define SRP_LOGIN_REJ	0xC2
206391dff86SNathan Whitehorn 
207391dff86SNathan Whitehorn #define SRP_T_LOGOUT	0x80
208391dff86SNathan Whitehorn #define SRP_CRED_REQ	0x81
209391dff86SNathan Whitehorn #define SRP_AER_REQ	0x82
210391dff86SNathan Whitehorn 
211391dff86SNathan Whitehorn #define SRP_CRED_RSP	0x41
212391dff86SNathan Whitehorn #define SRP_AER_RSP	0x41
213391dff86SNathan Whitehorn 
214391dff86SNathan Whitehorn /* Flags for srp_rsp flags field */
215391dff86SNathan Whitehorn #define SRP_RSPVALID	0x01
216391dff86SNathan Whitehorn #define SRP_SNSVALID	0x02
217391dff86SNathan Whitehorn #define SRP_DOOVER	0x04
218391dff86SNathan Whitehorn #define SRP_DOUNDER	0x08
219391dff86SNathan Whitehorn #define SRP_DIOVER	0x10
220391dff86SNathan Whitehorn #define SRP_DIUNDER	0x20
221391dff86SNathan Whitehorn 
222391dff86SNathan Whitehorn #define	MAD_SUCESS			0x00
223391dff86SNathan Whitehorn #define	MAD_NOT_SUPPORTED		0xf1
224391dff86SNathan Whitehorn #define	MAD_FAILED			0xf7
225391dff86SNathan Whitehorn 
226391dff86SNathan Whitehorn #define	MAD_EMPTY_IU			0x01
227391dff86SNathan Whitehorn #define	MAD_ERROR_LOGGING_REQUEST	0x02
228391dff86SNathan Whitehorn #define	MAD_ADAPTER_INFO_REQUEST	0x03
229391dff86SNathan Whitehorn #define	MAD_CAPABILITIES_EXCHANGE	0x05
230391dff86SNathan Whitehorn #define	MAD_PHYS_ADAP_INFO_REQUEST	0x06
231391dff86SNathan Whitehorn #define	MAD_TAPE_PASSTHROUGH_REQUEST	0x07
232391dff86SNathan Whitehorn #define	MAD_ENABLE_FAST_FAIL		0x08
233391dff86SNathan Whitehorn 
234391dff86SNathan Whitehorn static int	vscsi_probe(device_t);
235391dff86SNathan Whitehorn static int	vscsi_attach(device_t);
236391dff86SNathan Whitehorn static int	vscsi_detach(device_t);
237391dff86SNathan Whitehorn static void	vscsi_cam_action(struct cam_sim *, union ccb *);
238391dff86SNathan Whitehorn static void	vscsi_cam_poll(struct cam_sim *);
239391dff86SNathan Whitehorn static void	vscsi_intr(void *arg);
240391dff86SNathan Whitehorn static void	vscsi_check_response_queue(struct vscsi_softc *sc);
241391dff86SNathan Whitehorn static void	vscsi_setup_bus(struct vscsi_softc *sc);
242391dff86SNathan Whitehorn 
243391dff86SNathan Whitehorn static void	vscsi_srp_login(struct vscsi_softc *sc);
244391dff86SNathan Whitehorn static void	vscsi_crq_load_cb(void *, bus_dma_segment_t *, int, int);
245391dff86SNathan Whitehorn static void	vscsi_scsi_command(void *xxp, bus_dma_segment_t *segs,
246391dff86SNathan Whitehorn 		    int nsegs, int err);
247391dff86SNathan Whitehorn static void	vscsi_task_management(struct vscsi_softc *sc, union ccb *ccb);
248391dff86SNathan Whitehorn static void	vscsi_srp_response(struct vscsi_xfer *, struct vscsi_crq *);
249391dff86SNathan Whitehorn 
250391dff86SNathan Whitehorn static device_method_t	vscsi_methods[] = {
251391dff86SNathan Whitehorn 	DEVMETHOD(device_probe,		vscsi_probe),
252391dff86SNathan Whitehorn 	DEVMETHOD(device_attach,	vscsi_attach),
253391dff86SNathan Whitehorn 	DEVMETHOD(device_detach,	vscsi_detach),
254391dff86SNathan Whitehorn 
255391dff86SNathan Whitehorn 	DEVMETHOD_END
256391dff86SNathan Whitehorn };
2579b9a5327SJohn Baldwin 
258391dff86SNathan Whitehorn static driver_t vscsi_driver = {
259391dff86SNathan Whitehorn 	"vscsi",
260391dff86SNathan Whitehorn 	vscsi_methods,
261391dff86SNathan Whitehorn 	sizeof(struct vscsi_softc)
262391dff86SNathan Whitehorn };
2639b9a5327SJohn Baldwin 
2649b9a5327SJohn Baldwin DRIVER_MODULE(vscsi, vdevice, vscsi_driver, 0, 0);
265391dff86SNathan Whitehorn MALLOC_DEFINE(M_VSCSI, "vscsi", "CAM device queue for VSCSI");
266391dff86SNathan Whitehorn 
267391dff86SNathan Whitehorn static int
vscsi_probe(device_t dev)268391dff86SNathan Whitehorn vscsi_probe(device_t dev)
269391dff86SNathan Whitehorn {
270391dff86SNathan Whitehorn 
271391dff86SNathan Whitehorn 	if (!ofw_bus_is_compatible(dev, "IBM,v-scsi"))
272391dff86SNathan Whitehorn 		return (ENXIO);
273391dff86SNathan Whitehorn 
274391dff86SNathan Whitehorn 	device_set_desc(dev, "POWER Hypervisor Virtual SCSI Bus");
275391dff86SNathan Whitehorn 	return (0);
276391dff86SNathan Whitehorn }
277391dff86SNathan Whitehorn 
278391dff86SNathan Whitehorn static int
vscsi_attach(device_t dev)279391dff86SNathan Whitehorn vscsi_attach(device_t dev)
280391dff86SNathan Whitehorn {
281391dff86SNathan Whitehorn 	struct vscsi_softc *sc;
282391dff86SNathan Whitehorn 	struct vscsi_xfer *xp;
283391dff86SNathan Whitehorn 	int error, i;
284391dff86SNathan Whitehorn 
285391dff86SNathan Whitehorn 	sc = device_get_softc(dev);
286391dff86SNathan Whitehorn 	if (sc == NULL)
287391dff86SNathan Whitehorn 		return (EINVAL);
288391dff86SNathan Whitehorn 
289391dff86SNathan Whitehorn 	sc->dev = dev;
290391dff86SNathan Whitehorn 	mtx_init(&sc->io_lock, "vscsi", NULL, MTX_DEF);
291391dff86SNathan Whitehorn 
292391dff86SNathan Whitehorn 	/* Get properties */
293509142e1SNathan Whitehorn 	OF_getencprop(ofw_bus_get_node(dev), "reg", &sc->unit,
294509142e1SNathan Whitehorn 	    sizeof(sc->unit));
295391dff86SNathan Whitehorn 
296391dff86SNathan Whitehorn 	/* Setup interrupt */
297391dff86SNathan Whitehorn 	sc->irqid = 0;
298391dff86SNathan Whitehorn 	sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irqid,
299391dff86SNathan Whitehorn 	    RF_ACTIVE);
300391dff86SNathan Whitehorn 
301391dff86SNathan Whitehorn 	if (!sc->irq) {
302391dff86SNathan Whitehorn 		device_printf(dev, "Could not allocate IRQ\n");
303391dff86SNathan Whitehorn 		mtx_destroy(&sc->io_lock);
304391dff86SNathan Whitehorn 		return (ENXIO);
305391dff86SNathan Whitehorn 	}
306391dff86SNathan Whitehorn 
307391dff86SNathan Whitehorn 	bus_setup_intr(dev, sc->irq, INTR_TYPE_CAM | INTR_MPSAFE |
308391dff86SNathan Whitehorn 	    INTR_ENTROPY, NULL, vscsi_intr, sc, &sc->irq_cookie);
309391dff86SNathan Whitehorn 
310391dff86SNathan Whitehorn 	/* Data DMA */
311391dff86SNathan Whitehorn 	error = bus_dma_tag_create(bus_get_dma_tag(dev), 1, 0,
312391dff86SNathan Whitehorn 	    BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, BUS_SPACE_MAXSIZE,
313391dff86SNathan Whitehorn 	    256, BUS_SPACE_MAXSIZE_32BIT, 0, busdma_lock_mutex, &sc->io_lock,
314391dff86SNathan Whitehorn 	    &sc->data_tag);
315391dff86SNathan Whitehorn 
316391dff86SNathan Whitehorn 	TAILQ_INIT(&sc->active_xferq);
317391dff86SNathan Whitehorn 	TAILQ_INIT(&sc->free_xferq);
318391dff86SNathan Whitehorn 
319391dff86SNathan Whitehorn 	/* First XFER for login data */
320391dff86SNathan Whitehorn 	sc->loginxp.sc = sc;
321391dff86SNathan Whitehorn 	bus_dmamap_create(sc->data_tag, 0, &sc->loginxp.dmamap);
322391dff86SNathan Whitehorn 	TAILQ_INSERT_TAIL(&sc->free_xferq, &sc->loginxp, queue);
323391dff86SNathan Whitehorn 
324391dff86SNathan Whitehorn 	/* CRQ area */
325391dff86SNathan Whitehorn 	error = bus_dma_tag_create(bus_get_dma_tag(dev), PAGE_SIZE, 0,
326391dff86SNathan Whitehorn 	    BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, 8*PAGE_SIZE,
327391dff86SNathan Whitehorn 	    1, BUS_SPACE_MAXSIZE, 0, NULL, NULL, &sc->crq_tag);
328391dff86SNathan Whitehorn 	error = bus_dmamem_alloc(sc->crq_tag, (void **)&sc->crq_queue,
329391dff86SNathan Whitehorn 	    BUS_DMA_WAITOK | BUS_DMA_ZERO, &sc->crq_map);
330391dff86SNathan Whitehorn 	sc->crq_phys = 0;
331391dff86SNathan Whitehorn 	sc->n_crqs = 0;
332391dff86SNathan Whitehorn 	error = bus_dmamap_load(sc->crq_tag, sc->crq_map, sc->crq_queue,
333391dff86SNathan Whitehorn 	    8*PAGE_SIZE, vscsi_crq_load_cb, sc, 0);
334391dff86SNathan Whitehorn 
335391dff86SNathan Whitehorn 	mtx_lock(&sc->io_lock);
336391dff86SNathan Whitehorn 	vscsi_setup_bus(sc);
337ac2fffa4SPedro F. Giffuni 	sc->xfer = malloc(sizeof(sc->xfer[0])*sc->max_transactions, M_VSCSI,
338ac2fffa4SPedro F. Giffuni 	    M_NOWAIT);
339391dff86SNathan Whitehorn 	for (i = 0; i < sc->max_transactions; i++) {
340391dff86SNathan Whitehorn 		xp = &sc->xfer[i];
341391dff86SNathan Whitehorn 		xp->sc = sc;
342391dff86SNathan Whitehorn 
343391dff86SNathan Whitehorn 		error = bus_dmamap_create(sc->data_tag, 0, &xp->dmamap);
344391dff86SNathan Whitehorn 		if (error) {
345391dff86SNathan Whitehorn 			device_printf(dev, "Could not create DMA map (%d)\n",
346391dff86SNathan Whitehorn 			    error);
347391dff86SNathan Whitehorn 			break;
348391dff86SNathan Whitehorn 		}
349391dff86SNathan Whitehorn 
350391dff86SNathan Whitehorn 		TAILQ_INSERT_TAIL(&sc->free_xferq, xp, queue);
351391dff86SNathan Whitehorn 	}
352391dff86SNathan Whitehorn 	mtx_unlock(&sc->io_lock);
353391dff86SNathan Whitehorn 
354391dff86SNathan Whitehorn 	/* Allocate CAM bits */
355391dff86SNathan Whitehorn 	if ((sc->devq = cam_simq_alloc(sc->max_transactions)) == NULL)
356391dff86SNathan Whitehorn 		return (ENOMEM);
357391dff86SNathan Whitehorn 
358391dff86SNathan Whitehorn 	sc->sim = cam_sim_alloc(vscsi_cam_action, vscsi_cam_poll, "vscsi", sc,
359391dff86SNathan Whitehorn 				device_get_unit(dev), &sc->io_lock,
360391dff86SNathan Whitehorn 				sc->max_transactions, sc->max_transactions,
361391dff86SNathan Whitehorn 				sc->devq);
362391dff86SNathan Whitehorn 	if (sc->sim == NULL) {
363391dff86SNathan Whitehorn 		cam_simq_free(sc->devq);
364391dff86SNathan Whitehorn 		sc->devq = NULL;
365391dff86SNathan Whitehorn 		device_printf(dev, "CAM SIM attach failed\n");
366391dff86SNathan Whitehorn 		return (EINVAL);
367391dff86SNathan Whitehorn 	}
368391dff86SNathan Whitehorn 
369391dff86SNathan Whitehorn 	mtx_lock(&sc->io_lock);
370391dff86SNathan Whitehorn 	if (xpt_bus_register(sc->sim, dev, 0) != 0) {
371391dff86SNathan Whitehorn 		device_printf(dev, "XPT bus registration failed\n");
372391dff86SNathan Whitehorn 		cam_sim_free(sc->sim, FALSE);
373391dff86SNathan Whitehorn 		sc->sim = NULL;
374391dff86SNathan Whitehorn 		cam_simq_free(sc->devq);
375391dff86SNathan Whitehorn 		sc->devq = NULL;
376391dff86SNathan Whitehorn 		mtx_unlock(&sc->io_lock);
377391dff86SNathan Whitehorn 		return (EINVAL);
378391dff86SNathan Whitehorn 	}
379391dff86SNathan Whitehorn 	mtx_unlock(&sc->io_lock);
380391dff86SNathan Whitehorn 
381391dff86SNathan Whitehorn 	return (0);
382391dff86SNathan Whitehorn }
383391dff86SNathan Whitehorn 
384391dff86SNathan Whitehorn static int
vscsi_detach(device_t dev)385391dff86SNathan Whitehorn vscsi_detach(device_t dev)
386391dff86SNathan Whitehorn {
387391dff86SNathan Whitehorn 	struct vscsi_softc *sc;
388391dff86SNathan Whitehorn 
389391dff86SNathan Whitehorn 	sc = device_get_softc(dev);
390391dff86SNathan Whitehorn 	if (sc == NULL)
391391dff86SNathan Whitehorn 		return (EINVAL);
392391dff86SNathan Whitehorn 
393391dff86SNathan Whitehorn 	if (sc->sim != NULL) {
394391dff86SNathan Whitehorn 		mtx_lock(&sc->io_lock);
395391dff86SNathan Whitehorn 		xpt_bus_deregister(cam_sim_path(sc->sim));
396391dff86SNathan Whitehorn 		cam_sim_free(sc->sim, FALSE);
397391dff86SNathan Whitehorn 		sc->sim = NULL;
398391dff86SNathan Whitehorn 		mtx_unlock(&sc->io_lock);
399391dff86SNathan Whitehorn 	}
400391dff86SNathan Whitehorn 
401391dff86SNathan Whitehorn 	if (sc->devq != NULL) {
402391dff86SNathan Whitehorn 		cam_simq_free(sc->devq);
403391dff86SNathan Whitehorn 		sc->devq = NULL;
404391dff86SNathan Whitehorn 	}
405391dff86SNathan Whitehorn 
406391dff86SNathan Whitehorn 	mtx_destroy(&sc->io_lock);
407391dff86SNathan Whitehorn 
408391dff86SNathan Whitehorn 	return (0);
409391dff86SNathan Whitehorn }
410391dff86SNathan Whitehorn 
411391dff86SNathan Whitehorn static void
vscsi_cam_action(struct cam_sim * sim,union ccb * ccb)412391dff86SNathan Whitehorn vscsi_cam_action(struct cam_sim *sim, union ccb *ccb)
413391dff86SNathan Whitehorn {
414391dff86SNathan Whitehorn 	struct vscsi_softc *sc = cam_sim_softc(sim);
415391dff86SNathan Whitehorn 
416391dff86SNathan Whitehorn 	mtx_assert(&sc->io_lock, MA_OWNED);
417391dff86SNathan Whitehorn 
418391dff86SNathan Whitehorn 	switch (ccb->ccb_h.func_code) {
419391dff86SNathan Whitehorn 	case XPT_PATH_INQ:
420391dff86SNathan Whitehorn 	{
421391dff86SNathan Whitehorn 		struct ccb_pathinq *cpi = &ccb->cpi;
422391dff86SNathan Whitehorn 
423391dff86SNathan Whitehorn 		cpi->version_num = 1;
424391dff86SNathan Whitehorn 		cpi->hba_inquiry = PI_TAG_ABLE;
425391dff86SNathan Whitehorn 		cpi->hba_misc = PIM_EXTLUNS;
426391dff86SNathan Whitehorn 		cpi->target_sprt = 0;
427391dff86SNathan Whitehorn 		cpi->hba_eng_cnt = 0;
428391dff86SNathan Whitehorn 		cpi->max_target = 0;
429d2a94a77SNathan Whitehorn 		cpi->max_lun = 0;
430391dff86SNathan Whitehorn 		cpi->initiator_id = ~0;
4314195c7deSAlan Somers 		strlcpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
4324195c7deSAlan Somers 		strlcpy(cpi->hba_vid, "IBM", HBA_IDLEN);
4334195c7deSAlan Somers 		strlcpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
434391dff86SNathan Whitehorn 		cpi->unit_number = cam_sim_unit(sim);
435391dff86SNathan Whitehorn 		cpi->bus_id = cam_sim_bus(sim);
436391dff86SNathan Whitehorn 		cpi->base_transfer_speed = 150000;
437391dff86SNathan Whitehorn 		cpi->transport = XPORT_SRP;
438391dff86SNathan Whitehorn 		cpi->transport_version = 0;
439391dff86SNathan Whitehorn 		cpi->protocol = PROTO_SCSI;
440391dff86SNathan Whitehorn 		cpi->protocol_version = SCSI_REV_SPC4;
441391dff86SNathan Whitehorn 		cpi->ccb_h.status = CAM_REQ_CMP;
442391dff86SNathan Whitehorn 		break;
443391dff86SNathan Whitehorn 	}
444391dff86SNathan Whitehorn 	case XPT_RESET_BUS:
445391dff86SNathan Whitehorn 		ccb->ccb_h.status = CAM_REQ_CMP;
446391dff86SNathan Whitehorn 		break;
447391dff86SNathan Whitehorn 	case XPT_RESET_DEV:
448391dff86SNathan Whitehorn 		ccb->ccb_h.status = CAM_REQ_INPROG;
449391dff86SNathan Whitehorn 		vscsi_task_management(sc, ccb);
450391dff86SNathan Whitehorn 		return;
451391dff86SNathan Whitehorn 	case XPT_GET_TRAN_SETTINGS:
452391dff86SNathan Whitehorn 		ccb->cts.protocol = PROTO_SCSI;
453391dff86SNathan Whitehorn 		ccb->cts.protocol_version = SCSI_REV_SPC4;
454391dff86SNathan Whitehorn 		ccb->cts.transport = XPORT_SRP;
455391dff86SNathan Whitehorn 		ccb->cts.transport_version = 0;
456391dff86SNathan Whitehorn 		ccb->cts.proto_specific.valid = 0;
457391dff86SNathan Whitehorn 		ccb->cts.xport_specific.valid = 0;
458391dff86SNathan Whitehorn 		ccb->ccb_h.status = CAM_REQ_CMP;
459391dff86SNathan Whitehorn 		break;
460391dff86SNathan Whitehorn 	case XPT_SET_TRAN_SETTINGS:
461391dff86SNathan Whitehorn 		ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
462391dff86SNathan Whitehorn 		break;
463391dff86SNathan Whitehorn 	case XPT_SCSI_IO:
464391dff86SNathan Whitehorn 	{
465391dff86SNathan Whitehorn 		struct vscsi_xfer *xp;
466391dff86SNathan Whitehorn 
467391dff86SNathan Whitehorn 		ccb->ccb_h.status = CAM_REQ_INPROG;
468391dff86SNathan Whitehorn 
469391dff86SNathan Whitehorn 		xp = TAILQ_FIRST(&sc->free_xferq);
470391dff86SNathan Whitehorn 		if (xp == NULL)
471391dff86SNathan Whitehorn 			panic("SCSI queue flooded");
472391dff86SNathan Whitehorn 		xp->ccb = ccb;
473391dff86SNathan Whitehorn 		TAILQ_REMOVE(&sc->free_xferq, xp, queue);
474391dff86SNathan Whitehorn 		TAILQ_INSERT_TAIL(&sc->active_xferq, xp, queue);
475391dff86SNathan Whitehorn 		bus_dmamap_load_ccb(sc->data_tag, xp->dmamap,
476391dff86SNathan Whitehorn 		    ccb, vscsi_scsi_command, xp, 0);
477391dff86SNathan Whitehorn 
478391dff86SNathan Whitehorn 		return;
479391dff86SNathan Whitehorn 	}
480391dff86SNathan Whitehorn 	default:
481391dff86SNathan Whitehorn 		ccb->ccb_h.status = CAM_REQ_INVALID;
482391dff86SNathan Whitehorn 		break;
483391dff86SNathan Whitehorn 	}
484391dff86SNathan Whitehorn 
485391dff86SNathan Whitehorn 	xpt_done(ccb);
486391dff86SNathan Whitehorn 	return;
487391dff86SNathan Whitehorn }
488391dff86SNathan Whitehorn 
489391dff86SNathan Whitehorn static void
vscsi_srp_login(struct vscsi_softc * sc)490391dff86SNathan Whitehorn vscsi_srp_login(struct vscsi_softc *sc)
491391dff86SNathan Whitehorn {
492391dff86SNathan Whitehorn 	struct vscsi_xfer *xp;
493391dff86SNathan Whitehorn 	struct srp_login *login;
494391dff86SNathan Whitehorn 	struct vscsi_crq crq;
495391dff86SNathan Whitehorn 	int err;
496391dff86SNathan Whitehorn 
497391dff86SNathan Whitehorn 	mtx_assert(&sc->io_lock, MA_OWNED);
498391dff86SNathan Whitehorn 
499391dff86SNathan Whitehorn 	xp = TAILQ_FIRST(&sc->free_xferq);
500391dff86SNathan Whitehorn 	if (xp == NULL)
501391dff86SNathan Whitehorn 		panic("SCSI queue flooded");
502391dff86SNathan Whitehorn 	xp->ccb = NULL;
503391dff86SNathan Whitehorn 	TAILQ_REMOVE(&sc->free_xferq, xp, queue);
504391dff86SNathan Whitehorn 	TAILQ_INSERT_TAIL(&sc->active_xferq, xp, queue);
505391dff86SNathan Whitehorn 
506391dff86SNathan Whitehorn 	/* Set up command */
507c0290b3dSBrandon Bergren 	xp->srp_iu_size = 64;
508c0290b3dSBrandon Bergren 	crq.iu_length = htobe16(xp->srp_iu_size);
509391dff86SNathan Whitehorn 	err = vmem_alloc(xp->sc->srp_iu_arena, xp->srp_iu_size,
510391dff86SNathan Whitehorn 	    M_BESTFIT | M_NOWAIT, &xp->srp_iu_offset);
511391dff86SNathan Whitehorn 	if (err)
512391dff86SNathan Whitehorn 		panic("Error during VMEM allocation (%d)", err);
513391dff86SNathan Whitehorn 
514391dff86SNathan Whitehorn 	login = (struct srp_login *)((uint8_t *)xp->sc->srp_iu_queue +
515391dff86SNathan Whitehorn 	    (uintptr_t)xp->srp_iu_offset);
516391dff86SNathan Whitehorn 	bzero(login, xp->srp_iu_size);
517391dff86SNathan Whitehorn 	login->type = SRP_LOGIN_REQ;
518391dff86SNathan Whitehorn 	login->tag = (uint64_t)(xp);
519391dff86SNathan Whitehorn 	login->max_cmd_length = htobe64(256);
520391dff86SNathan Whitehorn 	login->buffer_formats = htobe16(0x1 | 0x2); /* Direct and indirect */
521391dff86SNathan Whitehorn 	login->flags = 0;
522391dff86SNathan Whitehorn 
523391dff86SNathan Whitehorn 	/* Create CRQ entry */
524391dff86SNathan Whitehorn 	crq.valid = 0x80;
525391dff86SNathan Whitehorn 	crq.format = 0x01;
526c0290b3dSBrandon Bergren 	crq.iu_data = htobe64(xp->sc->srp_iu_phys + xp->srp_iu_offset);
527391dff86SNathan Whitehorn 	bus_dmamap_sync(sc->crq_tag, sc->crq_map, BUS_DMASYNC_PREWRITE);
528391dff86SNathan Whitehorn 
529c0290b3dSBrandon Bergren 	err = phyp_hcall(H_SEND_CRQ, xp->sc->unit,
530c0290b3dSBrandon Bergren 	    be64toh(((uint64_t *)(&crq))[0]),
531c0290b3dSBrandon Bergren 	    be64toh(((uint64_t *)(&crq))[1]));
532391dff86SNathan Whitehorn 	if (err != 0)
533391dff86SNathan Whitehorn 		panic("CRQ send failure (%d)", err);
534391dff86SNathan Whitehorn }
535391dff86SNathan Whitehorn 
536391dff86SNathan Whitehorn static void
vscsi_task_management(struct vscsi_softc * sc,union ccb * ccb)537391dff86SNathan Whitehorn vscsi_task_management(struct vscsi_softc *sc, union ccb *ccb)
538391dff86SNathan Whitehorn {
539391dff86SNathan Whitehorn 	struct srp_tsk_mgmt *cmd;
540391dff86SNathan Whitehorn 	struct vscsi_xfer *xp;
541391dff86SNathan Whitehorn 	struct vscsi_crq crq;
542391dff86SNathan Whitehorn 	int err;
543391dff86SNathan Whitehorn 
544391dff86SNathan Whitehorn 	mtx_assert(&sc->io_lock, MA_OWNED);
545391dff86SNathan Whitehorn 
546391dff86SNathan Whitehorn 	xp = TAILQ_FIRST(&sc->free_xferq);
547391dff86SNathan Whitehorn 	if (xp == NULL)
548391dff86SNathan Whitehorn 		panic("SCSI queue flooded");
549391dff86SNathan Whitehorn 	xp->ccb = ccb;
550391dff86SNathan Whitehorn 	TAILQ_REMOVE(&sc->free_xferq, xp, queue);
551391dff86SNathan Whitehorn 	TAILQ_INSERT_TAIL(&sc->active_xferq, xp, queue);
552391dff86SNathan Whitehorn 
553c0290b3dSBrandon Bergren 	xp->srp_iu_size = sizeof(*cmd);
554c0290b3dSBrandon Bergren 	crq.iu_length = htobe16(xp->srp_iu_size);
555391dff86SNathan Whitehorn 	err = vmem_alloc(xp->sc->srp_iu_arena, xp->srp_iu_size,
556391dff86SNathan Whitehorn 	    M_BESTFIT | M_NOWAIT, &xp->srp_iu_offset);
557391dff86SNathan Whitehorn 	if (err)
558391dff86SNathan Whitehorn 		panic("Error during VMEM allocation (%d)", err);
559391dff86SNathan Whitehorn 
560391dff86SNathan Whitehorn 	cmd = (struct srp_tsk_mgmt *)((uint8_t *)xp->sc->srp_iu_queue +
561391dff86SNathan Whitehorn 	    (uintptr_t)xp->srp_iu_offset);
562391dff86SNathan Whitehorn 	bzero(cmd, xp->srp_iu_size);
563391dff86SNathan Whitehorn 	cmd->type = SRP_TSK_MGMT;
564391dff86SNathan Whitehorn 	cmd->tag = (uint64_t)xp;
565ef5758faSNathan Whitehorn 	cmd->lun = htobe64(CAM_EXTLUN_BYTE_SWIZZLE(ccb->ccb_h.target_lun));
566391dff86SNathan Whitehorn 
567391dff86SNathan Whitehorn 	switch (ccb->ccb_h.func_code) {
568391dff86SNathan Whitehorn 	case XPT_RESET_DEV:
569391dff86SNathan Whitehorn 		cmd->function = 0x08;
570391dff86SNathan Whitehorn 		break;
571391dff86SNathan Whitehorn 	default:
572391dff86SNathan Whitehorn 		panic("Unimplemented code %d", ccb->ccb_h.func_code);
573391dff86SNathan Whitehorn 		break;
574391dff86SNathan Whitehorn 	}
575391dff86SNathan Whitehorn 
576391dff86SNathan Whitehorn 	bus_dmamap_sync(xp->sc->crq_tag, xp->sc->crq_map, BUS_DMASYNC_PREWRITE);
577391dff86SNathan Whitehorn 
578391dff86SNathan Whitehorn 	/* Create CRQ entry */
579391dff86SNathan Whitehorn 	crq.valid = 0x80;
580391dff86SNathan Whitehorn 	crq.format = 0x01;
581c0290b3dSBrandon Bergren 	crq.iu_data = htobe64(xp->sc->srp_iu_phys + xp->srp_iu_offset);
582391dff86SNathan Whitehorn 
583c0290b3dSBrandon Bergren 	err = phyp_hcall(H_SEND_CRQ, xp->sc->unit,
584c0290b3dSBrandon Bergren 	    be64toh(((uint64_t *)(&crq))[0]),
585c0290b3dSBrandon Bergren 	    be64toh(((uint64_t *)(&crq))[1]));
586391dff86SNathan Whitehorn 	if (err != 0)
587391dff86SNathan Whitehorn 		panic("CRQ send failure (%d)", err);
588391dff86SNathan Whitehorn }
589391dff86SNathan Whitehorn 
590391dff86SNathan Whitehorn static void
vscsi_scsi_command(void * xxp,bus_dma_segment_t * segs,int nsegs,int err)591391dff86SNathan Whitehorn vscsi_scsi_command(void *xxp, bus_dma_segment_t *segs, int nsegs, int err)
592391dff86SNathan Whitehorn {
593391dff86SNathan Whitehorn 	struct vscsi_xfer *xp = xxp;
594391dff86SNathan Whitehorn 	uint8_t *cdb;
595391dff86SNathan Whitehorn 	union ccb *ccb = xp->ccb;
596391dff86SNathan Whitehorn 	struct srp_cmd *cmd;
597391dff86SNathan Whitehorn 	uint64_t chunk_addr;
598391dff86SNathan Whitehorn 	uint32_t chunk_size;
599391dff86SNathan Whitehorn 	int desc_start, i;
600391dff86SNathan Whitehorn 	struct vscsi_crq crq;
601391dff86SNathan Whitehorn 
602391dff86SNathan Whitehorn 	KASSERT(err == 0, ("DMA error %d\n", err));
603391dff86SNathan Whitehorn 
604391dff86SNathan Whitehorn 	mtx_assert(&xp->sc->io_lock, MA_OWNED);
605391dff86SNathan Whitehorn 
606391dff86SNathan Whitehorn 	cdb = (ccb->ccb_h.flags & CAM_CDB_POINTER) ?
607391dff86SNathan Whitehorn 	    ccb->csio.cdb_io.cdb_ptr : ccb->csio.cdb_io.cdb_bytes;
608391dff86SNathan Whitehorn 
609391dff86SNathan Whitehorn 	/* Command format from Table 20, page 37 of SRP spec */
610c0290b3dSBrandon Bergren 	xp->srp_iu_size = 48 + ((nsegs > 1) ? 20 : 16) +
611391dff86SNathan Whitehorn 	    ((ccb->csio.cdb_len > 16) ? (ccb->csio.cdb_len - 16) : 0);
612c0290b3dSBrandon Bergren 	crq.iu_length = htobe16(xp->srp_iu_size);
613391dff86SNathan Whitehorn 	if (nsegs > 1)
614391dff86SNathan Whitehorn 		xp->srp_iu_size += nsegs*16;
615391dff86SNathan Whitehorn 	xp->srp_iu_size = roundup(xp->srp_iu_size, 16);
616391dff86SNathan Whitehorn 	err = vmem_alloc(xp->sc->srp_iu_arena, xp->srp_iu_size,
617391dff86SNathan Whitehorn 	    M_BESTFIT | M_NOWAIT, &xp->srp_iu_offset);
618391dff86SNathan Whitehorn 	if (err)
619391dff86SNathan Whitehorn 		panic("Error during VMEM allocation (%d)", err);
620391dff86SNathan Whitehorn 
621391dff86SNathan Whitehorn 	cmd = (struct srp_cmd *)((uint8_t *)xp->sc->srp_iu_queue +
622391dff86SNathan Whitehorn 	    (uintptr_t)xp->srp_iu_offset);
623391dff86SNathan Whitehorn 	bzero(cmd, xp->srp_iu_size);
624391dff86SNathan Whitehorn 	cmd->type = SRP_CMD;
625391dff86SNathan Whitehorn 	if (ccb->csio.cdb_len > 16)
626391dff86SNathan Whitehorn 		cmd->additional_cdb = (ccb->csio.cdb_len - 16) << 2;
627391dff86SNathan Whitehorn 	memcpy(cmd->cdb, cdb, ccb->csio.cdb_len);
628391dff86SNathan Whitehorn 
629391dff86SNathan Whitehorn 	cmd->tag = (uint64_t)(xp); /* Let the responder find this again */
630ef5758faSNathan Whitehorn 	cmd->lun = htobe64(CAM_EXTLUN_BYTE_SWIZZLE(ccb->ccb_h.target_lun));
631391dff86SNathan Whitehorn 
632391dff86SNathan Whitehorn 	if (nsegs > 1) {
633391dff86SNathan Whitehorn 		/* Use indirect descriptors */
634391dff86SNathan Whitehorn 		switch (ccb->ccb_h.flags & CAM_DIR_MASK) {
635391dff86SNathan Whitehorn 		case CAM_DIR_OUT:
636391dff86SNathan Whitehorn 			cmd->formats = (2 << 4);
637391dff86SNathan Whitehorn 			break;
638391dff86SNathan Whitehorn 		case CAM_DIR_IN:
639391dff86SNathan Whitehorn 			cmd->formats = 2;
640391dff86SNathan Whitehorn 			break;
641391dff86SNathan Whitehorn 		default:
642391dff86SNathan Whitehorn 			panic("Does not support bidirectional commands (%d)",
643391dff86SNathan Whitehorn 			    ccb->ccb_h.flags & CAM_DIR_MASK);
644391dff86SNathan Whitehorn 			break;
645391dff86SNathan Whitehorn 		}
646391dff86SNathan Whitehorn 
647391dff86SNathan Whitehorn 		desc_start = ((ccb->csio.cdb_len > 16) ?
648391dff86SNathan Whitehorn 		    ccb->csio.cdb_len - 16 : 0);
649c0290b3dSBrandon Bergren 		chunk_addr = htobe64(xp->sc->srp_iu_phys + xp->srp_iu_offset + 20 +
650c0290b3dSBrandon Bergren 		    desc_start + sizeof(*cmd));
651c0290b3dSBrandon Bergren 		chunk_size = htobe32(16*nsegs);
652391dff86SNathan Whitehorn 		memcpy(&cmd->data_payload[desc_start], &chunk_addr, 8);
653391dff86SNathan Whitehorn 		memcpy(&cmd->data_payload[desc_start+12], &chunk_size, 4);
654391dff86SNathan Whitehorn 		chunk_size = 0;
655391dff86SNathan Whitehorn 		for (i = 0; i < nsegs; i++)
656391dff86SNathan Whitehorn 			chunk_size += segs[i].ds_len;
657c0290b3dSBrandon Bergren 		chunk_size = htobe32(chunk_size);
658391dff86SNathan Whitehorn 		memcpy(&cmd->data_payload[desc_start+16], &chunk_size, 4);
659391dff86SNathan Whitehorn 		desc_start += 20;
660391dff86SNathan Whitehorn 		for (i = 0; i < nsegs; i++) {
661c0290b3dSBrandon Bergren 			chunk_addr = htobe64(segs[i].ds_addr);
662c0290b3dSBrandon Bergren 			chunk_size = htobe32(segs[i].ds_len);
663391dff86SNathan Whitehorn 
664391dff86SNathan Whitehorn 			memcpy(&cmd->data_payload[desc_start + 16*i],
665391dff86SNathan Whitehorn 			    &chunk_addr, 8);
666391dff86SNathan Whitehorn 			/* Set handle tag to 0 */
667391dff86SNathan Whitehorn 			memcpy(&cmd->data_payload[desc_start + 16*i + 12],
668391dff86SNathan Whitehorn 			    &chunk_size, 4);
669391dff86SNathan Whitehorn 		}
670391dff86SNathan Whitehorn 	} else if (nsegs == 1) {
671391dff86SNathan Whitehorn 		switch (ccb->ccb_h.flags & CAM_DIR_MASK) {
672391dff86SNathan Whitehorn 		case CAM_DIR_OUT:
673391dff86SNathan Whitehorn 			cmd->formats = (1 << 4);
674391dff86SNathan Whitehorn 			break;
675391dff86SNathan Whitehorn 		case CAM_DIR_IN:
676391dff86SNathan Whitehorn 			cmd->formats = 1;
677391dff86SNathan Whitehorn 			break;
678391dff86SNathan Whitehorn 		default:
679391dff86SNathan Whitehorn 			panic("Does not support bidirectional commands (%d)",
680391dff86SNathan Whitehorn 			    ccb->ccb_h.flags & CAM_DIR_MASK);
681391dff86SNathan Whitehorn 			break;
682391dff86SNathan Whitehorn 		}
683391dff86SNathan Whitehorn 
684391dff86SNathan Whitehorn 		/*
685391dff86SNathan Whitehorn 		 * Memory descriptor:
686391dff86SNathan Whitehorn 		 * 8 byte address
687391dff86SNathan Whitehorn 		 * 4 byte handle
688391dff86SNathan Whitehorn 		 * 4 byte length
689391dff86SNathan Whitehorn 		 */
690391dff86SNathan Whitehorn 
691c0290b3dSBrandon Bergren 		chunk_addr = htobe64(segs[0].ds_addr);
692c0290b3dSBrandon Bergren 		chunk_size = htobe32(segs[0].ds_len);
693391dff86SNathan Whitehorn 		desc_start = ((ccb->csio.cdb_len > 16) ?
694391dff86SNathan Whitehorn 		    ccb->csio.cdb_len - 16 : 0);
695391dff86SNathan Whitehorn 
696391dff86SNathan Whitehorn 		memcpy(&cmd->data_payload[desc_start], &chunk_addr, 8);
697391dff86SNathan Whitehorn 		/* Set handle tag to 0 */
698391dff86SNathan Whitehorn 		memcpy(&cmd->data_payload[desc_start+12], &chunk_size, 4);
699391dff86SNathan Whitehorn 		KASSERT(xp->srp_iu_size >= 48 + ((ccb->csio.cdb_len > 16) ?
700391dff86SNathan Whitehorn 		    ccb->csio.cdb_len : 16), ("SRP IU command length"));
701391dff86SNathan Whitehorn 	} else {
702391dff86SNathan Whitehorn 		cmd->formats = 0;
703391dff86SNathan Whitehorn 	}
704391dff86SNathan Whitehorn 	bus_dmamap_sync(xp->sc->crq_tag, xp->sc->crq_map, BUS_DMASYNC_PREWRITE);
705391dff86SNathan Whitehorn 
706391dff86SNathan Whitehorn 	/* Create CRQ entry */
707391dff86SNathan Whitehorn 	crq.valid = 0x80;
708391dff86SNathan Whitehorn 	crq.format = 0x01;
709c0290b3dSBrandon Bergren 	crq.iu_data = htobe64(xp->sc->srp_iu_phys + xp->srp_iu_offset);
710391dff86SNathan Whitehorn 
711c0290b3dSBrandon Bergren 	err = phyp_hcall(H_SEND_CRQ, xp->sc->unit,
712c0290b3dSBrandon Bergren 	    be64toh(((uint64_t *)(&crq))[0]),
713c0290b3dSBrandon Bergren 	    be64toh(((uint64_t *)(&crq))[1]));
714391dff86SNathan Whitehorn 	if (err != 0)
715391dff86SNathan Whitehorn 		panic("CRQ send failure (%d)", err);
716391dff86SNathan Whitehorn }
717391dff86SNathan Whitehorn 
718391dff86SNathan Whitehorn static void
vscsi_crq_load_cb(void * xsc,bus_dma_segment_t * segs,int nsegs,int err)719391dff86SNathan Whitehorn vscsi_crq_load_cb(void *xsc, bus_dma_segment_t *segs, int nsegs, int err)
720391dff86SNathan Whitehorn {
721391dff86SNathan Whitehorn 	struct vscsi_softc *sc = xsc;
722391dff86SNathan Whitehorn 
723391dff86SNathan Whitehorn 	sc->crq_phys = segs[0].ds_addr;
724391dff86SNathan Whitehorn 	sc->n_crqs = PAGE_SIZE/sizeof(struct vscsi_crq);
725391dff86SNathan Whitehorn 
726391dff86SNathan Whitehorn 	sc->srp_iu_queue = (uint8_t *)(sc->crq_queue);
727391dff86SNathan Whitehorn 	sc->srp_iu_phys = segs[0].ds_addr;
728391dff86SNathan Whitehorn 	sc->srp_iu_arena = vmem_create("VSCSI SRP IU", PAGE_SIZE,
729391dff86SNathan Whitehorn 	    segs[0].ds_len - PAGE_SIZE, 16, 0, M_BESTFIT | M_NOWAIT);
730391dff86SNathan Whitehorn }
731391dff86SNathan Whitehorn 
732391dff86SNathan Whitehorn static void
vscsi_setup_bus(struct vscsi_softc * sc)733391dff86SNathan Whitehorn vscsi_setup_bus(struct vscsi_softc *sc)
734391dff86SNathan Whitehorn {
735391dff86SNathan Whitehorn 	struct vscsi_crq crq;
736391dff86SNathan Whitehorn 	struct vscsi_xfer *xp;
737391dff86SNathan Whitehorn 	int error;
738391dff86SNathan Whitehorn 
739391dff86SNathan Whitehorn 	struct {
740391dff86SNathan Whitehorn 		uint32_t type;
741391dff86SNathan Whitehorn 		uint16_t status;
742391dff86SNathan Whitehorn 		uint16_t length;
743391dff86SNathan Whitehorn 		uint64_t tag;
744391dff86SNathan Whitehorn 		uint64_t buffer;
745391dff86SNathan Whitehorn 		struct {
746391dff86SNathan Whitehorn 			char srp_version[8];
747391dff86SNathan Whitehorn 			char partition_name[96];
748391dff86SNathan Whitehorn 			uint32_t partition_number;
749391dff86SNathan Whitehorn 			uint32_t mad_version;
750391dff86SNathan Whitehorn 			uint32_t os_type;
751391dff86SNathan Whitehorn 			uint32_t port_max_txu[8];
752391dff86SNathan Whitehorn 		} payload;
753391dff86SNathan Whitehorn 	} mad_adapter_info;
754391dff86SNathan Whitehorn 
755391dff86SNathan Whitehorn 	bzero(&crq, sizeof(crq));
756391dff86SNathan Whitehorn 
757391dff86SNathan Whitehorn 	/* Init message */
758391dff86SNathan Whitehorn 	crq.valid = 0xc0;
759391dff86SNathan Whitehorn 	crq.format = 0x01;
760391dff86SNathan Whitehorn 
761391dff86SNathan Whitehorn 	do {
762391dff86SNathan Whitehorn 		error = phyp_hcall(H_FREE_CRQ, sc->unit);
763391dff86SNathan Whitehorn 	} while (error == H_BUSY);
764391dff86SNathan Whitehorn 
765391dff86SNathan Whitehorn 	/* See initialization sequence page 757 */
766391dff86SNathan Whitehorn 	bzero(sc->crq_queue, sc->n_crqs*sizeof(sc->crq_queue[0]));
767391dff86SNathan Whitehorn 	sc->cur_crq = 0;
768391dff86SNathan Whitehorn 	sc->bus_initialized = 0;
769391dff86SNathan Whitehorn 	sc->bus_logged_in = 0;
770391dff86SNathan Whitehorn 	bus_dmamap_sync(sc->crq_tag, sc->crq_map, BUS_DMASYNC_PREWRITE);
771391dff86SNathan Whitehorn 	error = phyp_hcall(H_REG_CRQ, sc->unit, sc->crq_phys,
772391dff86SNathan Whitehorn 	    sc->n_crqs*sizeof(sc->crq_queue[0]));
773391dff86SNathan Whitehorn 	KASSERT(error == 0, ("CRQ registration success"));
774391dff86SNathan Whitehorn 
775c0290b3dSBrandon Bergren 	error = phyp_hcall(H_SEND_CRQ, sc->unit,
776c0290b3dSBrandon Bergren 	    be64toh(((uint64_t *)(&crq))[0]),
777c0290b3dSBrandon Bergren 	    be64toh(((uint64_t *)(&crq))[1]));
778391dff86SNathan Whitehorn 	if (error != 0)
779391dff86SNathan Whitehorn 		panic("CRQ setup failure (%d)", error);
780391dff86SNathan Whitehorn 
781391dff86SNathan Whitehorn 	while (sc->bus_initialized == 0)
782391dff86SNathan Whitehorn 		vscsi_check_response_queue(sc);
783391dff86SNathan Whitehorn 
784391dff86SNathan Whitehorn 	/* Send MAD adapter info */
785c0290b3dSBrandon Bergren 	mad_adapter_info.type = htobe32(MAD_ADAPTER_INFO_REQUEST);
786391dff86SNathan Whitehorn 	mad_adapter_info.status = 0;
787c0290b3dSBrandon Bergren 	mad_adapter_info.length = htobe16(sizeof(mad_adapter_info.payload));
788391dff86SNathan Whitehorn 
789391dff86SNathan Whitehorn 	strcpy(mad_adapter_info.payload.srp_version, "16.a");
790391dff86SNathan Whitehorn 	strcpy(mad_adapter_info.payload.partition_name, "UNKNOWN");
791391dff86SNathan Whitehorn 	mad_adapter_info.payload.partition_number = -1;
792c0290b3dSBrandon Bergren 	mad_adapter_info.payload.mad_version = htobe32(1);
793c0290b3dSBrandon Bergren 	mad_adapter_info.payload.os_type = htobe32(2); /* Claim we are Linux */
794391dff86SNathan Whitehorn 	mad_adapter_info.payload.port_max_txu[0] = 0;
795391dff86SNathan Whitehorn 	/* If this fails, we get the defaults above */
796391dff86SNathan Whitehorn 	OF_getprop(OF_finddevice("/"), "ibm,partition-name",
797391dff86SNathan Whitehorn 	    mad_adapter_info.payload.partition_name,
798391dff86SNathan Whitehorn 	    sizeof(mad_adapter_info.payload.partition_name));
799391dff86SNathan Whitehorn 	OF_getprop(OF_finddevice("/"), "ibm,partition-no",
800391dff86SNathan Whitehorn 	    &mad_adapter_info.payload.partition_number,
801391dff86SNathan Whitehorn 	    sizeof(mad_adapter_info.payload.partition_number));
802391dff86SNathan Whitehorn 
803391dff86SNathan Whitehorn 	xp = TAILQ_FIRST(&sc->free_xferq);
804391dff86SNathan Whitehorn 	xp->ccb = NULL;
805391dff86SNathan Whitehorn 	TAILQ_REMOVE(&sc->free_xferq, xp, queue);
806391dff86SNathan Whitehorn 	TAILQ_INSERT_TAIL(&sc->active_xferq, xp, queue);
807c0290b3dSBrandon Bergren 	xp->srp_iu_size = sizeof(mad_adapter_info);
808c0290b3dSBrandon Bergren 	crq.iu_length = htobe16(xp->srp_iu_size);
809391dff86SNathan Whitehorn 	vmem_alloc(xp->sc->srp_iu_arena, xp->srp_iu_size,
810391dff86SNathan Whitehorn 	    M_BESTFIT | M_NOWAIT, &xp->srp_iu_offset);
811c0290b3dSBrandon Bergren 	mad_adapter_info.buffer = htobe64(xp->sc->srp_iu_phys + xp->srp_iu_offset + 24);
812391dff86SNathan Whitehorn 	mad_adapter_info.tag = (uint64_t)xp;
813391dff86SNathan Whitehorn 	memcpy((uint8_t *)xp->sc->srp_iu_queue + (uintptr_t)xp->srp_iu_offset,
814391dff86SNathan Whitehorn 		&mad_adapter_info, sizeof(mad_adapter_info));
815391dff86SNathan Whitehorn 	crq.valid = 0x80;
816391dff86SNathan Whitehorn 	crq.format = 0x02;
817c0290b3dSBrandon Bergren 	crq.iu_data = htobe64(xp->sc->srp_iu_phys + xp->srp_iu_offset);
818391dff86SNathan Whitehorn 	bus_dmamap_sync(sc->crq_tag, sc->crq_map, BUS_DMASYNC_PREWRITE);
819c0290b3dSBrandon Bergren 	phyp_hcall(H_SEND_CRQ, xp->sc->unit,
820c0290b3dSBrandon Bergren 	    be64toh(((uint64_t *)(&crq))[0]),
821c0290b3dSBrandon Bergren 	    be64toh(((uint64_t *)(&crq))[1]));
822391dff86SNathan Whitehorn 
823391dff86SNathan Whitehorn 	while (TAILQ_EMPTY(&sc->free_xferq))
824391dff86SNathan Whitehorn 		vscsi_check_response_queue(sc);
825391dff86SNathan Whitehorn 
826391dff86SNathan Whitehorn 	/* Send SRP login */
827391dff86SNathan Whitehorn 	vscsi_srp_login(sc);
828391dff86SNathan Whitehorn 	while (sc->bus_logged_in == 0)
829391dff86SNathan Whitehorn 		vscsi_check_response_queue(sc);
830391dff86SNathan Whitehorn 
831391dff86SNathan Whitehorn 	error = phyp_hcall(H_VIO_SIGNAL, sc->unit, 1); /* Enable interrupts */
832391dff86SNathan Whitehorn }
833391dff86SNathan Whitehorn 
834391dff86SNathan Whitehorn static void
vscsi_intr(void * xsc)835391dff86SNathan Whitehorn vscsi_intr(void *xsc)
836391dff86SNathan Whitehorn {
837391dff86SNathan Whitehorn 	struct vscsi_softc *sc = xsc;
838391dff86SNathan Whitehorn 
839391dff86SNathan Whitehorn 	mtx_lock(&sc->io_lock);
840391dff86SNathan Whitehorn 	vscsi_check_response_queue(sc);
841391dff86SNathan Whitehorn 	mtx_unlock(&sc->io_lock);
842391dff86SNathan Whitehorn }
843391dff86SNathan Whitehorn 
844391dff86SNathan Whitehorn static void
vscsi_srp_response(struct vscsi_xfer * xp,struct vscsi_crq * crq)845391dff86SNathan Whitehorn vscsi_srp_response(struct vscsi_xfer *xp, struct vscsi_crq *crq)
846391dff86SNathan Whitehorn {
847391dff86SNathan Whitehorn 	union ccb *ccb = xp->ccb;
848391dff86SNathan Whitehorn 	struct vscsi_softc *sc = xp->sc;
849391dff86SNathan Whitehorn 	struct srp_rsp *rsp;
850391dff86SNathan Whitehorn 	uint32_t sense_len;
851391dff86SNathan Whitehorn 
852391dff86SNathan Whitehorn 	/* SRP response packet in original request */
853391dff86SNathan Whitehorn 	rsp = (struct srp_rsp *)((uint8_t *)sc->srp_iu_queue +
854391dff86SNathan Whitehorn 	    (uintptr_t)xp->srp_iu_offset);
855391dff86SNathan Whitehorn 	ccb->csio.scsi_status = rsp->status;
856391dff86SNathan Whitehorn 	if (ccb->csio.scsi_status == SCSI_STATUS_OK)
857391dff86SNathan Whitehorn 		ccb->ccb_h.status = CAM_REQ_CMP;
858391dff86SNathan Whitehorn 	else
859391dff86SNathan Whitehorn 		ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR;
860391dff86SNathan Whitehorn #ifdef NOTYET
861391dff86SNathan Whitehorn 	/* Collect fast fail codes */
862391dff86SNathan Whitehorn 	if (crq->status != 0)
863391dff86SNathan Whitehorn 		ccb->ccb_h.status = CAM_REQ_CMP_ERR;
864391dff86SNathan Whitehorn #endif
865391dff86SNathan Whitehorn 
866391dff86SNathan Whitehorn 	if (ccb->ccb_h.status != CAM_REQ_CMP) {
867391dff86SNathan Whitehorn 		ccb->ccb_h.status |= CAM_DEV_QFRZN;
868391dff86SNathan Whitehorn 		xpt_freeze_devq(ccb->ccb_h.path, /*count*/ 1);
869391dff86SNathan Whitehorn 	}
870391dff86SNathan Whitehorn 
871391dff86SNathan Whitehorn 	if (!(rsp->flags & SRP_RSPVALID))
872391dff86SNathan Whitehorn 		rsp->response_data_len = 0;
873391dff86SNathan Whitehorn 	if (!(rsp->flags & SRP_SNSVALID))
874391dff86SNathan Whitehorn 		rsp->sense_data_len = 0;
875391dff86SNathan Whitehorn 	if (!(rsp->flags & (SRP_DOOVER | SRP_DOUNDER)))
876391dff86SNathan Whitehorn 		rsp->data_out_resid = 0;
877391dff86SNathan Whitehorn 	if (!(rsp->flags & (SRP_DIOVER | SRP_DIUNDER)))
878391dff86SNathan Whitehorn 		rsp->data_in_resid = 0;
879391dff86SNathan Whitehorn 
880391dff86SNathan Whitehorn 	if (rsp->flags & SRP_SNSVALID) {
881391dff86SNathan Whitehorn 		bzero(&ccb->csio.sense_data, sizeof(struct scsi_sense_data));
882391dff86SNathan Whitehorn 		ccb->ccb_h.status |= CAM_AUTOSNS_VALID;
883391dff86SNathan Whitehorn 		sense_len = min(be32toh(rsp->sense_data_len),
884391dff86SNathan Whitehorn 		    ccb->csio.sense_len);
885391dff86SNathan Whitehorn 		memcpy(&ccb->csio.sense_data,
886391dff86SNathan Whitehorn 		    &rsp->data_payload[be32toh(rsp->response_data_len)],
887391dff86SNathan Whitehorn 		    sense_len);
888391dff86SNathan Whitehorn 		ccb->csio.sense_resid = ccb->csio.sense_len -
889391dff86SNathan Whitehorn 		    be32toh(rsp->sense_data_len);
890391dff86SNathan Whitehorn 	}
891391dff86SNathan Whitehorn 
892391dff86SNathan Whitehorn 	switch (ccb->ccb_h.flags & CAM_DIR_MASK) {
893391dff86SNathan Whitehorn 	case CAM_DIR_OUT:
894391dff86SNathan Whitehorn 		ccb->csio.resid = rsp->data_out_resid;
895391dff86SNathan Whitehorn 		break;
896391dff86SNathan Whitehorn 	case CAM_DIR_IN:
897391dff86SNathan Whitehorn 		ccb->csio.resid = rsp->data_in_resid;
898391dff86SNathan Whitehorn 		break;
899391dff86SNathan Whitehorn 	}
900391dff86SNathan Whitehorn 
901391dff86SNathan Whitehorn 	bus_dmamap_sync(sc->data_tag, xp->dmamap, BUS_DMASYNC_POSTREAD);
902391dff86SNathan Whitehorn 	bus_dmamap_unload(sc->data_tag, xp->dmamap);
903391dff86SNathan Whitehorn 	xpt_done(ccb);
904391dff86SNathan Whitehorn 	xp->ccb = NULL;
905391dff86SNathan Whitehorn }
906391dff86SNathan Whitehorn 
907391dff86SNathan Whitehorn static void
vscsi_login_response(struct vscsi_xfer * xp,struct vscsi_crq * crq)908391dff86SNathan Whitehorn vscsi_login_response(struct vscsi_xfer *xp, struct vscsi_crq *crq)
909391dff86SNathan Whitehorn {
910391dff86SNathan Whitehorn 	struct vscsi_softc *sc = xp->sc;
911391dff86SNathan Whitehorn 	struct srp_login_rsp *rsp;
912391dff86SNathan Whitehorn 
913391dff86SNathan Whitehorn 	/* SRP response packet in original request */
914391dff86SNathan Whitehorn 	rsp = (struct srp_login_rsp *)((uint8_t *)sc->srp_iu_queue +
915391dff86SNathan Whitehorn 	    (uintptr_t)xp->srp_iu_offset);
916391dff86SNathan Whitehorn 	KASSERT(be16toh(rsp->buffer_formats) & 0x3, ("Both direct and indirect "
917391dff86SNathan Whitehorn 	    "buffers supported"));
918391dff86SNathan Whitehorn 
919391dff86SNathan Whitehorn 	sc->max_transactions = be32toh(rsp->request_limit_delta);
920391dff86SNathan Whitehorn 	device_printf(sc->dev, "Queue depth %d commands\n",
921391dff86SNathan Whitehorn 	    sc->max_transactions);
922391dff86SNathan Whitehorn 	sc->bus_logged_in = 1;
923391dff86SNathan Whitehorn }
924391dff86SNathan Whitehorn 
925391dff86SNathan Whitehorn static void
vscsi_cam_poll(struct cam_sim * sim)926391dff86SNathan Whitehorn vscsi_cam_poll(struct cam_sim *sim)
927391dff86SNathan Whitehorn {
928391dff86SNathan Whitehorn 	struct vscsi_softc *sc = cam_sim_softc(sim);
929391dff86SNathan Whitehorn 
930391dff86SNathan Whitehorn 	vscsi_check_response_queue(sc);
931391dff86SNathan Whitehorn }
932391dff86SNathan Whitehorn 
933391dff86SNathan Whitehorn static void
vscsi_check_response_queue(struct vscsi_softc * sc)934391dff86SNathan Whitehorn vscsi_check_response_queue(struct vscsi_softc *sc)
935391dff86SNathan Whitehorn {
936391dff86SNathan Whitehorn 	struct vscsi_crq *crq;
937391dff86SNathan Whitehorn 	struct vscsi_xfer *xp;
938391dff86SNathan Whitehorn 	int code;
939391dff86SNathan Whitehorn 
940391dff86SNathan Whitehorn 	mtx_assert(&sc->io_lock, MA_OWNED);
941391dff86SNathan Whitehorn 
94209ae596bSNathan Whitehorn 	while (sc->crq_queue[sc->cur_crq].valid != 0) {
94309ae596bSNathan Whitehorn 		/* The hypercalls at both ends of this are not optimal */
944391dff86SNathan Whitehorn 		phyp_hcall(H_VIO_SIGNAL, sc->unit, 0);
945391dff86SNathan Whitehorn 		bus_dmamap_sync(sc->crq_tag, sc->crq_map, BUS_DMASYNC_POSTREAD);
946391dff86SNathan Whitehorn 
947391dff86SNathan Whitehorn 		crq = &sc->crq_queue[sc->cur_crq];
948391dff86SNathan Whitehorn 
949391dff86SNathan Whitehorn 		switch (crq->valid) {
950391dff86SNathan Whitehorn 		case 0xc0:
951391dff86SNathan Whitehorn 			if (crq->format == 0x02)
952391dff86SNathan Whitehorn 				sc->bus_initialized = 1;
953391dff86SNathan Whitehorn 			break;
954391dff86SNathan Whitehorn 		case 0x80:
955391dff86SNathan Whitehorn 			/* IU data is set to tag pointer (the XP) */
956391dff86SNathan Whitehorn 			xp = (struct vscsi_xfer *)crq->iu_data;
957391dff86SNathan Whitehorn 
958391dff86SNathan Whitehorn 			switch (crq->format) {
959391dff86SNathan Whitehorn 			case 0x01:
960391dff86SNathan Whitehorn 				code = *((uint8_t *)sc->srp_iu_queue +
961391dff86SNathan Whitehorn 	    			    (uintptr_t)xp->srp_iu_offset);
962391dff86SNathan Whitehorn 				switch (code) {
963391dff86SNathan Whitehorn 				case SRP_RSP:
964391dff86SNathan Whitehorn 					vscsi_srp_response(xp, crq);
965391dff86SNathan Whitehorn 					break;
966391dff86SNathan Whitehorn 				case SRP_LOGIN_RSP:
967391dff86SNathan Whitehorn 					vscsi_login_response(xp, crq);
968391dff86SNathan Whitehorn 					break;
969391dff86SNathan Whitehorn 				default:
970391dff86SNathan Whitehorn 					device_printf(sc->dev, "Unknown SRP "
971391dff86SNathan Whitehorn 					    "response code %d\n", code);
972391dff86SNathan Whitehorn 					break;
973391dff86SNathan Whitehorn 				}
974391dff86SNathan Whitehorn 				break;
975391dff86SNathan Whitehorn 			case 0x02:
976391dff86SNathan Whitehorn 				/* Ignore management datagrams */
977391dff86SNathan Whitehorn 				break;
978391dff86SNathan Whitehorn 			default:
979391dff86SNathan Whitehorn 				panic("Unknown CRQ format %d\n", crq->format);
980391dff86SNathan Whitehorn 				break;
981391dff86SNathan Whitehorn 			}
982391dff86SNathan Whitehorn 			vmem_free(sc->srp_iu_arena, xp->srp_iu_offset,
983391dff86SNathan Whitehorn 			    xp->srp_iu_size);
984391dff86SNathan Whitehorn 			TAILQ_REMOVE(&sc->active_xferq, xp, queue);
985391dff86SNathan Whitehorn 			TAILQ_INSERT_TAIL(&sc->free_xferq, xp, queue);
986391dff86SNathan Whitehorn 			break;
987391dff86SNathan Whitehorn 		default:
988391dff86SNathan Whitehorn 			device_printf(sc->dev,
989391dff86SNathan Whitehorn 			    "Unknown CRQ message type %d\n", crq->valid);
990391dff86SNathan Whitehorn 			break;
991391dff86SNathan Whitehorn 		}
992391dff86SNathan Whitehorn 
993391dff86SNathan Whitehorn 		crq->valid = 0;
994391dff86SNathan Whitehorn 		sc->cur_crq = (sc->cur_crq + 1) % sc->n_crqs;
995391dff86SNathan Whitehorn 
996391dff86SNathan Whitehorn 		bus_dmamap_sync(sc->crq_tag, sc->crq_map, BUS_DMASYNC_PREWRITE);
997391dff86SNathan Whitehorn 		phyp_hcall(H_VIO_SIGNAL, sc->unit, 1);
998391dff86SNathan Whitehorn 	}
99909ae596bSNathan Whitehorn }
1000