xref: /freebsd/sys/dev/firewire/sbp_targ.c (revision e9e688e24362baf97f9383904c7323b6fe94f5ef)
1e9e688e2SHidetoshi Shimokawa /*
2e9e688e2SHidetoshi Shimokawa  * Copyright (C) 2003
3e9e688e2SHidetoshi Shimokawa  * 	Hidetoshi Shimokawa. All rights reserved.
4e9e688e2SHidetoshi Shimokawa  *
5e9e688e2SHidetoshi Shimokawa  * Redistribution and use in source and binary forms, with or without
6e9e688e2SHidetoshi Shimokawa  * modification, are permitted provided that the following conditions
7e9e688e2SHidetoshi Shimokawa  * are met:
8e9e688e2SHidetoshi Shimokawa  * 1. Redistributions of source code must retain the above copyright
9e9e688e2SHidetoshi Shimokawa  *    notice, this list of conditions and the following disclaimer.
10e9e688e2SHidetoshi Shimokawa  * 2. Redistributions in binary form must reproduce the above copyright
11e9e688e2SHidetoshi Shimokawa  *    notice, this list of conditions and the following disclaimer in the
12e9e688e2SHidetoshi Shimokawa  *    documentation and/or other materials provided with the distribution.
13e9e688e2SHidetoshi Shimokawa  * 3. All advertising materials mentioning features or use of this software
14e9e688e2SHidetoshi Shimokawa  *    must display the following acknowledgement:
15e9e688e2SHidetoshi Shimokawa  *
16e9e688e2SHidetoshi Shimokawa  *	This product includes software developed by Hidetoshi Shimokawa.
17e9e688e2SHidetoshi Shimokawa  *
18e9e688e2SHidetoshi Shimokawa  * 4. Neither the name of the author nor the names of its contributors
19e9e688e2SHidetoshi Shimokawa  *    may be used to endorse or promote products derived from this software
20e9e688e2SHidetoshi Shimokawa  *    without specific prior written permission.
21e9e688e2SHidetoshi Shimokawa  *
22e9e688e2SHidetoshi Shimokawa  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23e9e688e2SHidetoshi Shimokawa  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24e9e688e2SHidetoshi Shimokawa  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25e9e688e2SHidetoshi Shimokawa  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26e9e688e2SHidetoshi Shimokawa  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27e9e688e2SHidetoshi Shimokawa  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28e9e688e2SHidetoshi Shimokawa  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29e9e688e2SHidetoshi Shimokawa  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30e9e688e2SHidetoshi Shimokawa  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31e9e688e2SHidetoshi Shimokawa  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32e9e688e2SHidetoshi Shimokawa  * SUCH DAMAGE.
33e9e688e2SHidetoshi Shimokawa  *
34e9e688e2SHidetoshi Shimokawa  * $FreeBSD$
35e9e688e2SHidetoshi Shimokawa  */
36e9e688e2SHidetoshi Shimokawa 
37e9e688e2SHidetoshi Shimokawa #include <sys/param.h>
38e9e688e2SHidetoshi Shimokawa #include <sys/kernel.h>
39e9e688e2SHidetoshi Shimokawa #include <sys/systm.h>
40e9e688e2SHidetoshi Shimokawa #include <sys/sysctl.h>
41e9e688e2SHidetoshi Shimokawa #include <sys/types.h>
42e9e688e2SHidetoshi Shimokawa #include <sys/conf.h>
43e9e688e2SHidetoshi Shimokawa #include <sys/malloc.h>
44e9e688e2SHidetoshi Shimokawa #if __FreeBSD_version < 500000
45e9e688e2SHidetoshi Shimokawa #include <sys/devicestat.h>
46e9e688e2SHidetoshi Shimokawa #endif
47e9e688e2SHidetoshi Shimokawa 
48e9e688e2SHidetoshi Shimokawa #include <sys/bus.h>
49e9e688e2SHidetoshi Shimokawa #include <machine/bus.h>
50e9e688e2SHidetoshi Shimokawa 
51e9e688e2SHidetoshi Shimokawa #include <dev/firewire/firewire.h>
52e9e688e2SHidetoshi Shimokawa #include <dev/firewire/firewirereg.h>
53e9e688e2SHidetoshi Shimokawa #include <dev/firewire/iec13213.h>
54e9e688e2SHidetoshi Shimokawa #include <dev/firewire/sbp.h>
55e9e688e2SHidetoshi Shimokawa #include <dev/firewire/fwmem.h>
56e9e688e2SHidetoshi Shimokawa 
57e9e688e2SHidetoshi Shimokawa #include <cam/cam.h>
58e9e688e2SHidetoshi Shimokawa #include <cam/cam_ccb.h>
59e9e688e2SHidetoshi Shimokawa #include <cam/cam_sim.h>
60e9e688e2SHidetoshi Shimokawa #include <cam/cam_xpt_sim.h>
61e9e688e2SHidetoshi Shimokawa #include <cam/cam_debug.h>
62e9e688e2SHidetoshi Shimokawa #include <cam/cam_periph.h>
63e9e688e2SHidetoshi Shimokawa #include <cam/scsi/scsi_all.h>
64e9e688e2SHidetoshi Shimokawa 
65e9e688e2SHidetoshi Shimokawa #define SBP_TARG_RECV_LEN (8)
66e9e688e2SHidetoshi Shimokawa #define MAX_LUN		63
67e9e688e2SHidetoshi Shimokawa /*
68e9e688e2SHidetoshi Shimokawa  * management/command block agent registers
69e9e688e2SHidetoshi Shimokawa  *
70e9e688e2SHidetoshi Shimokawa  * BASE 0xffff f001 0000 management port
71e9e688e2SHidetoshi Shimokawa  * BASE 0xffff f001 0020 command port for lun0
72e9e688e2SHidetoshi Shimokawa  * BASE 0xffff f001 0040 command port for lun1
73e9e688e2SHidetoshi Shimokawa  *
74e9e688e2SHidetoshi Shimokawa  */
75e9e688e2SHidetoshi Shimokawa #define SBP_TARG_MGM	 0x10000	/* offset from 0xffff f000 000 */
76e9e688e2SHidetoshi Shimokawa #define SBP_TARG_BIND_HI	0xffff
77e9e688e2SHidetoshi Shimokawa #define SBP_TARG_BIND_LO(l)	(0xf0000000 + SBP_TARG_MGM + 0x20 * ((l) + 1))
78e9e688e2SHidetoshi Shimokawa #define SBP_TARG_BIND_START	(((u_int64_t)SBP_TARG_BIND_HI << 32) | \
79e9e688e2SHidetoshi Shimokawa 				    SBP_TARG_BIND_LO(-1))
80e9e688e2SHidetoshi Shimokawa #define SBP_TARG_BIND_END	(((u_int64_t)SBP_TARG_BIND_HI << 32) | \
81e9e688e2SHidetoshi Shimokawa 				    SBP_TARG_BIND_LO(MAX_LUN))
82e9e688e2SHidetoshi Shimokawa #define SBP_TARG_LUN(lo)	(((lo) - SBP_TARG_BIND_LO(0))/0x20)
83e9e688e2SHidetoshi Shimokawa 
84e9e688e2SHidetoshi Shimokawa #define FETCH_MGM	0
85e9e688e2SHidetoshi Shimokawa #define FETCH_CMD	1
86e9e688e2SHidetoshi Shimokawa #define FETCH_POINTER	2
87e9e688e2SHidetoshi Shimokawa 
88e9e688e2SHidetoshi Shimokawa MALLOC_DEFINE(M_SBP_TARG, "sbp_targ", "SBP-II/FireWire target mode");
89e9e688e2SHidetoshi Shimokawa 
90e9e688e2SHidetoshi Shimokawa static int debug = 0;
91e9e688e2SHidetoshi Shimokawa 
92e9e688e2SHidetoshi Shimokawa SYSCTL_INT(_debug, OID_AUTO, sbp_targ_debug, CTLFLAG_RW, &debug, 0,
93e9e688e2SHidetoshi Shimokawa         "SBP target mode debug flag");
94e9e688e2SHidetoshi Shimokawa 
95e9e688e2SHidetoshi Shimokawa struct sbp_targ_softc {
96e9e688e2SHidetoshi Shimokawa         struct firewire_dev_comm fd;
97e9e688e2SHidetoshi Shimokawa 	struct cam_sim *sim;
98e9e688e2SHidetoshi Shimokawa 	struct cam_path *path;
99e9e688e2SHidetoshi Shimokawa 	struct fw_bind fwb;
100e9e688e2SHidetoshi Shimokawa 	int ndevs;
101e9e688e2SHidetoshi Shimokawa 	struct crom_chunk unit;
102e9e688e2SHidetoshi Shimokawa 	struct sbp_targ_lstate *lstate[MAX_LUN];
103e9e688e2SHidetoshi Shimokawa 	struct sbp_targ_lstate *black_hole;
104e9e688e2SHidetoshi Shimokawa };
105e9e688e2SHidetoshi Shimokawa 
106e9e688e2SHidetoshi Shimokawa struct sbp_targ_lstate {
107e9e688e2SHidetoshi Shimokawa 	struct sbp_targ_softc *sc;
108e9e688e2SHidetoshi Shimokawa 	struct cam_path *path;
109e9e688e2SHidetoshi Shimokawa 	struct ccb_hdr_slist accept_tios;
110e9e688e2SHidetoshi Shimokawa 	struct ccb_hdr_slist immed_notifies;
111e9e688e2SHidetoshi Shimokawa 	struct crom_chunk model;
112e9e688e2SHidetoshi Shimokawa 	/* XXX per initiater data */
113e9e688e2SHidetoshi Shimokawa 	struct fw_device *fwdev;
114e9e688e2SHidetoshi Shimokawa 	struct sbp_login_res loginres;
115e9e688e2SHidetoshi Shimokawa 	u_int32_t flags;
116e9e688e2SHidetoshi Shimokawa #define LINK_ACTIVE	1
117e9e688e2SHidetoshi Shimokawa #define ATIO_STARVED	2
118e9e688e2SHidetoshi Shimokawa 	u_int16_t fifo_hi;
119e9e688e2SHidetoshi Shimokawa 	u_int16_t last_hi;
120e9e688e2SHidetoshi Shimokawa 	u_int32_t fifo_lo;
121e9e688e2SHidetoshi Shimokawa 	u_int32_t last_lo;
122e9e688e2SHidetoshi Shimokawa 	STAILQ_HEAD(, orb_info) orbs;
123e9e688e2SHidetoshi Shimokawa 	u_int16_t login_id;
124e9e688e2SHidetoshi Shimokawa 	u_int16_t lun;
125e9e688e2SHidetoshi Shimokawa };
126e9e688e2SHidetoshi Shimokawa 
127e9e688e2SHidetoshi Shimokawa struct corb4 {
128e9e688e2SHidetoshi Shimokawa #if BYTE_ORDER == BIG_ENDIAN
129e9e688e2SHidetoshi Shimokawa 	u_int32_t n:1,
130e9e688e2SHidetoshi Shimokawa 		  rq_fmt:2,
131e9e688e2SHidetoshi Shimokawa 		  :1,
132e9e688e2SHidetoshi Shimokawa 		  dir:1,
133e9e688e2SHidetoshi Shimokawa 		  spd:3,
134e9e688e2SHidetoshi Shimokawa 		  max_payload:4,
135e9e688e2SHidetoshi Shimokawa 		  page_table_present:1,
136e9e688e2SHidetoshi Shimokawa 		  page_size:3,
137e9e688e2SHidetoshi Shimokawa 		  data_size:16;
138e9e688e2SHidetoshi Shimokawa #else
139e9e688e2SHidetoshi Shimokawa 	u_int32_t data_size:16,
140e9e688e2SHidetoshi Shimokawa 		  page_size:3,
141e9e688e2SHidetoshi Shimokawa 		  page_table_present:1,
142e9e688e2SHidetoshi Shimokawa 		  max_payload:4,
143e9e688e2SHidetoshi Shimokawa 		  spd:3,
144e9e688e2SHidetoshi Shimokawa 		  dir:1,
145e9e688e2SHidetoshi Shimokawa 		  :1,
146e9e688e2SHidetoshi Shimokawa 		  rq_fmt:2,
147e9e688e2SHidetoshi Shimokawa 		  n:1;
148e9e688e2SHidetoshi Shimokawa #endif
149e9e688e2SHidetoshi Shimokawa };
150e9e688e2SHidetoshi Shimokawa 
151e9e688e2SHidetoshi Shimokawa struct morb4 {
152e9e688e2SHidetoshi Shimokawa #if BYTE_ORDER == BIG_ENDIAN
153e9e688e2SHidetoshi Shimokawa 	u_int32_t n:1,
154e9e688e2SHidetoshi Shimokawa 		  rq_fmt:2,
155e9e688e2SHidetoshi Shimokawa 		  :9,
156e9e688e2SHidetoshi Shimokawa 		  fun:4,
157e9e688e2SHidetoshi Shimokawa 		  id:16;
158e9e688e2SHidetoshi Shimokawa #else
159e9e688e2SHidetoshi Shimokawa 	u_int32_t id:16,
160e9e688e2SHidetoshi Shimokawa 		  fun:4,
161e9e688e2SHidetoshi Shimokawa 		  :9,
162e9e688e2SHidetoshi Shimokawa 		  rq_fmt:2,
163e9e688e2SHidetoshi Shimokawa 		  n:1;
164e9e688e2SHidetoshi Shimokawa #endif
165e9e688e2SHidetoshi Shimokawa };
166e9e688e2SHidetoshi Shimokawa 
167e9e688e2SHidetoshi Shimokawa struct orb_info {
168e9e688e2SHidetoshi Shimokawa 	struct sbp_targ_softc *sc;
169e9e688e2SHidetoshi Shimokawa 	struct fw_device *fwdev;
170e9e688e2SHidetoshi Shimokawa 	struct sbp_targ_lstate *lstate;
171e9e688e2SHidetoshi Shimokawa 	union ccb *ccb;
172e9e688e2SHidetoshi Shimokawa 	struct ccb_accept_tio *atio;
173e9e688e2SHidetoshi Shimokawa 	u_int8_t state;
174e9e688e2SHidetoshi Shimokawa #define ORBI_STATUS_NONE	0
175e9e688e2SHidetoshi Shimokawa #define ORBI_STATUS_FETCH	1
176e9e688e2SHidetoshi Shimokawa #define ORBI_STATUS_ATIO	2
177e9e688e2SHidetoshi Shimokawa #define ORBI_STATUS_CTIO	3
178e9e688e2SHidetoshi Shimokawa #define ORBI_STATUS_STATUS	4
179e9e688e2SHidetoshi Shimokawa #define ORBI_STATUS_POINTER	5
180e9e688e2SHidetoshi Shimokawa #define ORBI_STATUS_ABORTED	7
181e9e688e2SHidetoshi Shimokawa 	u_int8_t refcount;
182e9e688e2SHidetoshi Shimokawa 	u_int16_t orb_hi;
183e9e688e2SHidetoshi Shimokawa 	u_int32_t orb_lo;
184e9e688e2SHidetoshi Shimokawa 	u_int32_t data_hi;
185e9e688e2SHidetoshi Shimokawa 	u_int32_t data_lo;
186e9e688e2SHidetoshi Shimokawa 	struct corb4 orb4;
187e9e688e2SHidetoshi Shimokawa 	STAILQ_ENTRY(orb_info) link;
188e9e688e2SHidetoshi Shimokawa 	u_int32_t orb[8];
189e9e688e2SHidetoshi Shimokawa 	u_int32_t *page_table;
190e9e688e2SHidetoshi Shimokawa 	struct sbp_status status;
191e9e688e2SHidetoshi Shimokawa };
192e9e688e2SHidetoshi Shimokawa 
193e9e688e2SHidetoshi Shimokawa static char *orb_fun_name[] = {
194e9e688e2SHidetoshi Shimokawa 	ORB_FUN_NAMES
195e9e688e2SHidetoshi Shimokawa };
196e9e688e2SHidetoshi Shimokawa 
197e9e688e2SHidetoshi Shimokawa static void sbp_targ_recv(struct fw_xfer *);
198e9e688e2SHidetoshi Shimokawa static void sbp_targ_fetch_orb(struct sbp_targ_softc *, struct fw_device *,
199e9e688e2SHidetoshi Shimokawa     u_int16_t, u_int32_t, struct sbp_targ_lstate *, int);
200e9e688e2SHidetoshi Shimokawa 
201e9e688e2SHidetoshi Shimokawa static void
202e9e688e2SHidetoshi Shimokawa sbp_targ_identify(driver_t *driver, device_t parent)
203e9e688e2SHidetoshi Shimokawa {
204e9e688e2SHidetoshi Shimokawa 	BUS_ADD_CHILD(parent, 0, "sbp_targ", device_get_unit(parent));
205e9e688e2SHidetoshi Shimokawa }
206e9e688e2SHidetoshi Shimokawa 
207e9e688e2SHidetoshi Shimokawa static int
208e9e688e2SHidetoshi Shimokawa sbp_targ_probe(device_t dev)
209e9e688e2SHidetoshi Shimokawa {
210e9e688e2SHidetoshi Shimokawa 	device_t pa;
211e9e688e2SHidetoshi Shimokawa 
212e9e688e2SHidetoshi Shimokawa 	pa = device_get_parent(dev);
213e9e688e2SHidetoshi Shimokawa 	if(device_get_unit(dev) != device_get_unit(pa)){
214e9e688e2SHidetoshi Shimokawa 		return(ENXIO);
215e9e688e2SHidetoshi Shimokawa 	}
216e9e688e2SHidetoshi Shimokawa 
217e9e688e2SHidetoshi Shimokawa 	device_set_desc(dev, "SBP-2/SCSI over FireWire target mode");
218e9e688e2SHidetoshi Shimokawa 	return (0);
219e9e688e2SHidetoshi Shimokawa }
220e9e688e2SHidetoshi Shimokawa 
221e9e688e2SHidetoshi Shimokawa static void
222e9e688e2SHidetoshi Shimokawa sbp_targ_post_busreset(void *arg)
223e9e688e2SHidetoshi Shimokawa {
224e9e688e2SHidetoshi Shimokawa 	struct sbp_targ_softc *sc;
225e9e688e2SHidetoshi Shimokawa 	struct crom_src *src;
226e9e688e2SHidetoshi Shimokawa 	struct crom_chunk *root;
227e9e688e2SHidetoshi Shimokawa 	struct crom_chunk *unit;
228e9e688e2SHidetoshi Shimokawa 	struct sbp_targ_lstate *lstate;
229e9e688e2SHidetoshi Shimokawa 	int i;
230e9e688e2SHidetoshi Shimokawa 
231e9e688e2SHidetoshi Shimokawa 	sc = (struct sbp_targ_softc *) arg;
232e9e688e2SHidetoshi Shimokawa 	src = sc->fd.fc->crom_src;
233e9e688e2SHidetoshi Shimokawa 	root = sc->fd.fc->crom_root;
234e9e688e2SHidetoshi Shimokawa 
235e9e688e2SHidetoshi Shimokawa 	unit = &sc->unit;
236e9e688e2SHidetoshi Shimokawa 
237e9e688e2SHidetoshi Shimokawa 	bzero(unit, sizeof(struct crom_chunk));
238e9e688e2SHidetoshi Shimokawa 
239e9e688e2SHidetoshi Shimokawa 	crom_add_chunk(src, root, unit, CROM_UDIR);
240e9e688e2SHidetoshi Shimokawa 	crom_add_entry(unit, CSRKEY_SPEC, CSRVAL_ANSIT10);
241e9e688e2SHidetoshi Shimokawa 	crom_add_entry(unit, CSRKEY_VER, CSRVAL_T10SBP2);
242e9e688e2SHidetoshi Shimokawa 	crom_add_entry(unit, CSRKEY_COM_SPEC, CSRVAL_ANSIT10);
243e9e688e2SHidetoshi Shimokawa 	crom_add_entry(unit, CSRKEY_COM_SET, CSRVAL_SCSI);
244e9e688e2SHidetoshi Shimokawa 
245e9e688e2SHidetoshi Shimokawa 	crom_add_entry(unit, CROM_MGM, SBP_TARG_MGM >> 2);
246e9e688e2SHidetoshi Shimokawa 	crom_add_entry(unit, CSRKEY_UNIT_CH, (10<<8) | 8);
247e9e688e2SHidetoshi Shimokawa 
248e9e688e2SHidetoshi Shimokawa 	for (i = 0; i < MAX_LUN; i ++) {
249e9e688e2SHidetoshi Shimokawa 		lstate = sc->lstate[i];
250e9e688e2SHidetoshi Shimokawa 		if (lstate == NULL)
251e9e688e2SHidetoshi Shimokawa 			continue;
252e9e688e2SHidetoshi Shimokawa 		crom_add_entry(unit, CSRKEY_FIRM_VER, 1);
253e9e688e2SHidetoshi Shimokawa 		crom_add_entry(unit, CROM_LUN, i);
254e9e688e2SHidetoshi Shimokawa 		crom_add_entry(unit, CSRKEY_MODEL, 1);
255e9e688e2SHidetoshi Shimokawa 		crom_add_simple_text(src, unit, &lstate->model, "TargetMode");
256e9e688e2SHidetoshi Shimokawa 	}
257e9e688e2SHidetoshi Shimokawa }
258e9e688e2SHidetoshi Shimokawa 
259e9e688e2SHidetoshi Shimokawa static cam_status
260e9e688e2SHidetoshi Shimokawa sbp_targ_find_devs(struct sbp_targ_softc *sc, union ccb *ccb,
261e9e688e2SHidetoshi Shimokawa     struct sbp_targ_lstate **lstate, int notfound_failure)
262e9e688e2SHidetoshi Shimokawa {
263e9e688e2SHidetoshi Shimokawa 	u_int lun;
264e9e688e2SHidetoshi Shimokawa 
265e9e688e2SHidetoshi Shimokawa 	/* XXX 0 is the only vaild target_id */
266e9e688e2SHidetoshi Shimokawa 	if (ccb->ccb_h.target_id == CAM_TARGET_WILDCARD &&
267e9e688e2SHidetoshi Shimokawa 	    ccb->ccb_h.target_lun == CAM_LUN_WILDCARD) {
268e9e688e2SHidetoshi Shimokawa 		*lstate = sc->black_hole;
269e9e688e2SHidetoshi Shimokawa 		return (CAM_REQ_CMP);
270e9e688e2SHidetoshi Shimokawa 	}
271e9e688e2SHidetoshi Shimokawa 
272e9e688e2SHidetoshi Shimokawa 	if (ccb->ccb_h.target_id != 0)
273e9e688e2SHidetoshi Shimokawa 		return (CAM_TID_INVALID);
274e9e688e2SHidetoshi Shimokawa 
275e9e688e2SHidetoshi Shimokawa 	lun = ccb->ccb_h.target_lun;
276e9e688e2SHidetoshi Shimokawa 	if (lun >= MAX_LUN)
277e9e688e2SHidetoshi Shimokawa 		return (CAM_LUN_INVALID);
278e9e688e2SHidetoshi Shimokawa 
279e9e688e2SHidetoshi Shimokawa 	*lstate = sc->lstate[lun];
280e9e688e2SHidetoshi Shimokawa 
281e9e688e2SHidetoshi Shimokawa 	if (notfound_failure != 0 && *lstate == NULL)
282e9e688e2SHidetoshi Shimokawa 		return (CAM_PATH_INVALID);
283e9e688e2SHidetoshi Shimokawa 
284e9e688e2SHidetoshi Shimokawa 	return (CAM_REQ_CMP);
285e9e688e2SHidetoshi Shimokawa }
286e9e688e2SHidetoshi Shimokawa 
287e9e688e2SHidetoshi Shimokawa static void
288e9e688e2SHidetoshi Shimokawa sbp_targ_en_lun(struct sbp_targ_softc *sc, union ccb *ccb)
289e9e688e2SHidetoshi Shimokawa {
290e9e688e2SHidetoshi Shimokawa 	struct ccb_en_lun *cel = &ccb->cel;
291e9e688e2SHidetoshi Shimokawa 	struct sbp_targ_lstate *lstate;
292e9e688e2SHidetoshi Shimokawa 	struct orb_info *orbi, *next;
293e9e688e2SHidetoshi Shimokawa 	cam_status status;
294e9e688e2SHidetoshi Shimokawa 
295e9e688e2SHidetoshi Shimokawa 	status = sbp_targ_find_devs(sc, ccb, &lstate, 0);
296e9e688e2SHidetoshi Shimokawa 	if (status != CAM_REQ_CMP) {
297e9e688e2SHidetoshi Shimokawa 		ccb->ccb_h.status = status;
298e9e688e2SHidetoshi Shimokawa 		return;
299e9e688e2SHidetoshi Shimokawa 	}
300e9e688e2SHidetoshi Shimokawa 
301e9e688e2SHidetoshi Shimokawa 	if (cel->enable != 0) {
302e9e688e2SHidetoshi Shimokawa 		if (lstate != NULL) {
303e9e688e2SHidetoshi Shimokawa 			xpt_print_path(ccb->ccb_h.path);
304e9e688e2SHidetoshi Shimokawa 			printf("Lun already enabled\n");
305e9e688e2SHidetoshi Shimokawa 			ccb->ccb_h.status = CAM_LUN_ALRDY_ENA;
306e9e688e2SHidetoshi Shimokawa 			return;
307e9e688e2SHidetoshi Shimokawa 		}
308e9e688e2SHidetoshi Shimokawa 		if (cel->grp6_len != 0 || cel->grp7_len != 0) {
309e9e688e2SHidetoshi Shimokawa 			ccb->ccb_h.status = CAM_REQ_INVALID;
310e9e688e2SHidetoshi Shimokawa 			printf("Non-zero Group Codes\n");
311e9e688e2SHidetoshi Shimokawa 			return;
312e9e688e2SHidetoshi Shimokawa 		}
313e9e688e2SHidetoshi Shimokawa 		lstate = (struct sbp_targ_lstate *)
314e9e688e2SHidetoshi Shimokawa 		    malloc(sizeof(*lstate), M_SBP_TARG, M_NOWAIT | M_ZERO);
315e9e688e2SHidetoshi Shimokawa 		if (lstate == NULL) {
316e9e688e2SHidetoshi Shimokawa 			xpt_print_path(ccb->ccb_h.path);
317e9e688e2SHidetoshi Shimokawa 			printf("Couldn't allocate lstate\n");
318e9e688e2SHidetoshi Shimokawa 			ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
319e9e688e2SHidetoshi Shimokawa 			return;
320e9e688e2SHidetoshi Shimokawa 		}
321e9e688e2SHidetoshi Shimokawa 		if (ccb->ccb_h.target_id == CAM_TARGET_WILDCARD)
322e9e688e2SHidetoshi Shimokawa 			sc->black_hole = lstate;
323e9e688e2SHidetoshi Shimokawa 		else
324e9e688e2SHidetoshi Shimokawa 			sc->lstate[ccb->ccb_h.target_lun] = lstate;
325e9e688e2SHidetoshi Shimokawa 		memset(lstate, 0, sizeof(*lstate));
326e9e688e2SHidetoshi Shimokawa 		lstate->sc = sc;
327e9e688e2SHidetoshi Shimokawa 		status = xpt_create_path(&lstate->path, /*periph*/NULL,
328e9e688e2SHidetoshi Shimokawa 					 xpt_path_path_id(ccb->ccb_h.path),
329e9e688e2SHidetoshi Shimokawa 					 xpt_path_target_id(ccb->ccb_h.path),
330e9e688e2SHidetoshi Shimokawa 					 xpt_path_lun_id(ccb->ccb_h.path));
331e9e688e2SHidetoshi Shimokawa 		if (status != CAM_REQ_CMP) {
332e9e688e2SHidetoshi Shimokawa 			free(lstate, M_SBP_TARG);
333e9e688e2SHidetoshi Shimokawa 			xpt_print_path(ccb->ccb_h.path);
334e9e688e2SHidetoshi Shimokawa 			printf("Couldn't allocate path\n");
335e9e688e2SHidetoshi Shimokawa 			ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
336e9e688e2SHidetoshi Shimokawa 			return;
337e9e688e2SHidetoshi Shimokawa 		}
338e9e688e2SHidetoshi Shimokawa 		SLIST_INIT(&lstate->accept_tios);
339e9e688e2SHidetoshi Shimokawa 		SLIST_INIT(&lstate->immed_notifies);
340e9e688e2SHidetoshi Shimokawa 		STAILQ_INIT(&lstate->orbs);
341e9e688e2SHidetoshi Shimokawa 		lstate->last_hi = 0xffff;
342e9e688e2SHidetoshi Shimokawa 		lstate->last_lo = 0xffffffff;
343e9e688e2SHidetoshi Shimokawa 
344e9e688e2SHidetoshi Shimokawa 		ccb->ccb_h.status = CAM_REQ_CMP;
345e9e688e2SHidetoshi Shimokawa 		xpt_print_path(ccb->ccb_h.path);
346e9e688e2SHidetoshi Shimokawa 		printf("Lun now enabled for target mode\n");
347e9e688e2SHidetoshi Shimokawa 		/* bus reset */
348e9e688e2SHidetoshi Shimokawa 		sc->fd.fc->ibr(sc->fd.fc);
349e9e688e2SHidetoshi Shimokawa 	} else {
350e9e688e2SHidetoshi Shimokawa 		if (lstate == NULL) {
351e9e688e2SHidetoshi Shimokawa 			ccb->ccb_h.status = CAM_LUN_INVALID;
352e9e688e2SHidetoshi Shimokawa 			return;
353e9e688e2SHidetoshi Shimokawa 		}
354e9e688e2SHidetoshi Shimokawa 		ccb->ccb_h.status = CAM_REQ_CMP;
355e9e688e2SHidetoshi Shimokawa 
356e9e688e2SHidetoshi Shimokawa 		if (SLIST_FIRST(&lstate->accept_tios) != NULL) {
357e9e688e2SHidetoshi Shimokawa 			printf("ATIOs pending\n");
358e9e688e2SHidetoshi Shimokawa 			ccb->ccb_h.status = CAM_REQ_INVALID;
359e9e688e2SHidetoshi Shimokawa 		}
360e9e688e2SHidetoshi Shimokawa 
361e9e688e2SHidetoshi Shimokawa 		if (SLIST_FIRST(&lstate->immed_notifies) != NULL) {
362e9e688e2SHidetoshi Shimokawa 			printf("INOTs pending\n");
363e9e688e2SHidetoshi Shimokawa 			ccb->ccb_h.status = CAM_REQ_INVALID;
364e9e688e2SHidetoshi Shimokawa 		}
365e9e688e2SHidetoshi Shimokawa 
366e9e688e2SHidetoshi Shimokawa 		if (ccb->ccb_h.status != CAM_REQ_CMP) {
367e9e688e2SHidetoshi Shimokawa 			return;
368e9e688e2SHidetoshi Shimokawa 		}
369e9e688e2SHidetoshi Shimokawa 
370e9e688e2SHidetoshi Shimokawa 		xpt_print_path(ccb->ccb_h.path);
371e9e688e2SHidetoshi Shimokawa 		printf("Target mode disabled\n");
372e9e688e2SHidetoshi Shimokawa 		xpt_free_path(lstate->path);
373e9e688e2SHidetoshi Shimokawa 
374e9e688e2SHidetoshi Shimokawa 		for (orbi = STAILQ_FIRST(&lstate->orbs); orbi != NULL;
375e9e688e2SHidetoshi Shimokawa 		    orbi = next) {
376e9e688e2SHidetoshi Shimokawa 			next = STAILQ_NEXT(orbi, link);
377e9e688e2SHidetoshi Shimokawa 			free(orbi, M_SBP_TARG);
378e9e688e2SHidetoshi Shimokawa 		}
379e9e688e2SHidetoshi Shimokawa 
380e9e688e2SHidetoshi Shimokawa 		if (ccb->ccb_h.target_id == CAM_TARGET_WILDCARD)
381e9e688e2SHidetoshi Shimokawa 			sc->black_hole = NULL;
382e9e688e2SHidetoshi Shimokawa 		else
383e9e688e2SHidetoshi Shimokawa 			sc->lstate[ccb->ccb_h.target_lun] = NULL;
384e9e688e2SHidetoshi Shimokawa 		free(lstate, M_SBP_TARG);
385e9e688e2SHidetoshi Shimokawa 
386e9e688e2SHidetoshi Shimokawa 		/* bus reset */
387e9e688e2SHidetoshi Shimokawa 		sc->fd.fc->ibr(sc->fd.fc);
388e9e688e2SHidetoshi Shimokawa 	}
389e9e688e2SHidetoshi Shimokawa }
390e9e688e2SHidetoshi Shimokawa 
391e9e688e2SHidetoshi Shimokawa static void
392e9e688e2SHidetoshi Shimokawa sbp_targ_send_lstate_events(struct sbp_targ_softc *sc,
393e9e688e2SHidetoshi Shimokawa     struct sbp_targ_lstate *lstate)
394e9e688e2SHidetoshi Shimokawa {
395e9e688e2SHidetoshi Shimokawa #if 0
396e9e688e2SHidetoshi Shimokawa 	struct ccb_hdr *ccbh;
397e9e688e2SHidetoshi Shimokawa 	struct ccb_immed_notify *inot;
398e9e688e2SHidetoshi Shimokawa 
399e9e688e2SHidetoshi Shimokawa 	printf("%s: not implemented yet\n", __FUNCTION__);
400e9e688e2SHidetoshi Shimokawa #endif
401e9e688e2SHidetoshi Shimokawa }
402e9e688e2SHidetoshi Shimokawa 
403e9e688e2SHidetoshi Shimokawa static __inline void
404e9e688e2SHidetoshi Shimokawa sbp_targ_remove_orb_info(struct sbp_targ_lstate *lstate, struct orb_info *orbi)
405e9e688e2SHidetoshi Shimokawa {
406e9e688e2SHidetoshi Shimokawa 	STAILQ_REMOVE(&lstate->orbs, orbi, orb_info, link);
407e9e688e2SHidetoshi Shimokawa }
408e9e688e2SHidetoshi Shimokawa 
409e9e688e2SHidetoshi Shimokawa /*
410e9e688e2SHidetoshi Shimokawa  * tag_id/init_id encoding
411e9e688e2SHidetoshi Shimokawa  *
412e9e688e2SHidetoshi Shimokawa  * tag_id and init_id has only 32bit for each.
413e9e688e2SHidetoshi Shimokawa  * scsi_target can handle very limited number(up to 15) of init_id.
414e9e688e2SHidetoshi Shimokawa  * we have to encode 48bit orb and 64bit EUI64 into these
415e9e688e2SHidetoshi Shimokawa  * variables.
416e9e688e2SHidetoshi Shimokawa  *
417e9e688e2SHidetoshi Shimokawa  * tag_id represents lower 32bit of ORB address.
418e9e688e2SHidetoshi Shimokawa  * init_id represents node_id now.
419e9e688e2SHidetoshi Shimokawa  *
420e9e688e2SHidetoshi Shimokawa  */
421e9e688e2SHidetoshi Shimokawa 
422e9e688e2SHidetoshi Shimokawa static struct orb_info *
423e9e688e2SHidetoshi Shimokawa sbp_targ_get_orb_info(struct sbp_targ_lstate *lstate,
424e9e688e2SHidetoshi Shimokawa     u_int tag_id, u_int init_id)
425e9e688e2SHidetoshi Shimokawa {
426e9e688e2SHidetoshi Shimokawa 	struct orb_info *orbi;
427e9e688e2SHidetoshi Shimokawa 
428e9e688e2SHidetoshi Shimokawa 	STAILQ_FOREACH(orbi, &lstate->orbs, link)
429e9e688e2SHidetoshi Shimokawa 		if (orbi->orb_lo == tag_id &&
430e9e688e2SHidetoshi Shimokawa #if 0
431e9e688e2SHidetoshi Shimokawa 		    orbi->orb_hi == (init_id & 0xffff) &&
432e9e688e2SHidetoshi Shimokawa 		    orbi->fwdev->dst == (init_id >> 16))
433e9e688e2SHidetoshi Shimokawa #else
434e9e688e2SHidetoshi Shimokawa 		    orbi->fwdev->dst == init_id)
435e9e688e2SHidetoshi Shimokawa #endif
436e9e688e2SHidetoshi Shimokawa 			goto found;
437e9e688e2SHidetoshi Shimokawa 	printf("%s: orb not found\n", __FUNCTION__);
438e9e688e2SHidetoshi Shimokawa 	return (NULL);
439e9e688e2SHidetoshi Shimokawa found:
440e9e688e2SHidetoshi Shimokawa 	return (orbi);
441e9e688e2SHidetoshi Shimokawa }
442e9e688e2SHidetoshi Shimokawa 
443e9e688e2SHidetoshi Shimokawa static void
444e9e688e2SHidetoshi Shimokawa sbp_targ_abort(struct orb_info *orbi)
445e9e688e2SHidetoshi Shimokawa {
446e9e688e2SHidetoshi Shimokawa 	struct orb_info *norbi;
447e9e688e2SHidetoshi Shimokawa 
448e9e688e2SHidetoshi Shimokawa 	for (; orbi != NULL; orbi = norbi) {
449e9e688e2SHidetoshi Shimokawa 		printf("%s: status=%d\n", __FUNCTION__, orbi->state);
450e9e688e2SHidetoshi Shimokawa 		norbi = STAILQ_NEXT(orbi, link);
451e9e688e2SHidetoshi Shimokawa 		if (orbi->state != ORBI_STATUS_ABORTED) {
452e9e688e2SHidetoshi Shimokawa 			if (orbi->ccb != NULL) {
453e9e688e2SHidetoshi Shimokawa 				orbi->ccb->ccb_h.status = CAM_REQ_ABORTED;
454e9e688e2SHidetoshi Shimokawa 				xpt_done(orbi->ccb);
455e9e688e2SHidetoshi Shimokawa 				orbi->ccb = NULL;
456e9e688e2SHidetoshi Shimokawa 			}
457e9e688e2SHidetoshi Shimokawa 			if (orbi->state <= ORBI_STATUS_ATIO) {
458e9e688e2SHidetoshi Shimokawa 				sbp_targ_remove_orb_info(orbi->lstate, orbi);
459e9e688e2SHidetoshi Shimokawa 				free(orbi, M_SBP_TARG);
460e9e688e2SHidetoshi Shimokawa 			} else
461e9e688e2SHidetoshi Shimokawa 				orbi->state = ORBI_STATUS_ABORTED;
462e9e688e2SHidetoshi Shimokawa 		}
463e9e688e2SHidetoshi Shimokawa 	}
464e9e688e2SHidetoshi Shimokawa }
465e9e688e2SHidetoshi Shimokawa 
466e9e688e2SHidetoshi Shimokawa static void
467e9e688e2SHidetoshi Shimokawa sbp_targ_free_orbi(struct fw_xfer *xfer)
468e9e688e2SHidetoshi Shimokawa {
469e9e688e2SHidetoshi Shimokawa 	struct orb_info *orbi;
470e9e688e2SHidetoshi Shimokawa 
471e9e688e2SHidetoshi Shimokawa 	orbi = (struct orb_info *)xfer->sc;
472e9e688e2SHidetoshi Shimokawa 	if (xfer->resp != 0) {
473e9e688e2SHidetoshi Shimokawa 		/* XXX */
474e9e688e2SHidetoshi Shimokawa 		printf("%s: xfer->resp != 0\n", __FUNCTION__);
475e9e688e2SHidetoshi Shimokawa 	}
476e9e688e2SHidetoshi Shimokawa 	free(orbi, M_SBP_TARG);
477e9e688e2SHidetoshi Shimokawa 	fw_xfer_free(xfer);
478e9e688e2SHidetoshi Shimokawa }
479e9e688e2SHidetoshi Shimokawa 
480e9e688e2SHidetoshi Shimokawa static void
481e9e688e2SHidetoshi Shimokawa sbp_targ_status_FIFO(struct orb_info *orbi,
482e9e688e2SHidetoshi Shimokawa     u_int32_t fifo_hi, u_int32_t fifo_lo, int dequeue)
483e9e688e2SHidetoshi Shimokawa {
484e9e688e2SHidetoshi Shimokawa 	struct fw_xfer *xfer;
485e9e688e2SHidetoshi Shimokawa 
486e9e688e2SHidetoshi Shimokawa 	if (dequeue)
487e9e688e2SHidetoshi Shimokawa 		sbp_targ_remove_orb_info(orbi->lstate, orbi);
488e9e688e2SHidetoshi Shimokawa 
489e9e688e2SHidetoshi Shimokawa 	xfer = fwmem_write_block(orbi->fwdev, (void *)orbi,
490e9e688e2SHidetoshi Shimokawa 	    /*spd*/2, fifo_hi, fifo_lo,
491e9e688e2SHidetoshi Shimokawa 	    sizeof(u_int32_t) * (orbi->status.len + 1), (char *)&orbi->status,
492e9e688e2SHidetoshi Shimokawa 	    sbp_targ_free_orbi);
493e9e688e2SHidetoshi Shimokawa 
494e9e688e2SHidetoshi Shimokawa 	if (xfer == NULL) {
495e9e688e2SHidetoshi Shimokawa 		/* XXX */
496e9e688e2SHidetoshi Shimokawa 		printf("%s: xfer == NULL\n", __FUNCTION__);
497e9e688e2SHidetoshi Shimokawa 	}
498e9e688e2SHidetoshi Shimokawa }
499e9e688e2SHidetoshi Shimokawa 
500e9e688e2SHidetoshi Shimokawa static void
501e9e688e2SHidetoshi Shimokawa sbp_targ_send_status(struct orb_info *orbi, union ccb *ccb)
502e9e688e2SHidetoshi Shimokawa {
503e9e688e2SHidetoshi Shimokawa 	struct sbp_status *sbp_status;
504e9e688e2SHidetoshi Shimokawa 
505e9e688e2SHidetoshi Shimokawa 	sbp_status = &orbi->status;
506e9e688e2SHidetoshi Shimokawa 
507e9e688e2SHidetoshi Shimokawa 	orbi->state = ORBI_STATUS_STATUS;
508e9e688e2SHidetoshi Shimokawa 
509e9e688e2SHidetoshi Shimokawa 	sbp_status->resp = 0; /* XXX */
510e9e688e2SHidetoshi Shimokawa 	sbp_status->status = 0; /* XXX */
511e9e688e2SHidetoshi Shimokawa 	sbp_status->dead = 0; /* XXX */
512e9e688e2SHidetoshi Shimokawa 
513e9e688e2SHidetoshi Shimokawa 	switch (ccb->csio.scsi_status) {
514e9e688e2SHidetoshi Shimokawa 	case SCSI_STATUS_OK:
515e9e688e2SHidetoshi Shimokawa 		if (debug)
516e9e688e2SHidetoshi Shimokawa 			printf("%s: STATUS_OK\n", __FUNCTION__);
517e9e688e2SHidetoshi Shimokawa 		sbp_status->len = 1;
518e9e688e2SHidetoshi Shimokawa 		break;
519e9e688e2SHidetoshi Shimokawa 	case SCSI_STATUS_CHECK_COND:
520e9e688e2SHidetoshi Shimokawa 	case SCSI_STATUS_BUSY:
521e9e688e2SHidetoshi Shimokawa 	case SCSI_STATUS_CMD_TERMINATED:
522e9e688e2SHidetoshi Shimokawa 	{
523e9e688e2SHidetoshi Shimokawa 		struct sbp_cmd_status *sbp_cmd_status;
524e9e688e2SHidetoshi Shimokawa 		struct scsi_sense_data *sense;
525e9e688e2SHidetoshi Shimokawa 
526e9e688e2SHidetoshi Shimokawa 		if (debug)
527e9e688e2SHidetoshi Shimokawa 			printf("%s: STATUS %d\n", __FUNCTION__,
528e9e688e2SHidetoshi Shimokawa 			    ccb->csio.scsi_status);
529e9e688e2SHidetoshi Shimokawa 		sbp_cmd_status = (struct sbp_cmd_status *)&sbp_status->data[0];
530e9e688e2SHidetoshi Shimokawa 		sbp_cmd_status->status = ccb->csio.scsi_status;
531e9e688e2SHidetoshi Shimokawa 		sense = &ccb->csio.sense_data;
532e9e688e2SHidetoshi Shimokawa 
533e9e688e2SHidetoshi Shimokawa 		sbp_targ_abort(STAILQ_NEXT(orbi, link));
534e9e688e2SHidetoshi Shimokawa 
535e9e688e2SHidetoshi Shimokawa 		if ((sense->error_code & SSD_ERRCODE) == SSD_CURRENT_ERROR)
536e9e688e2SHidetoshi Shimokawa 			sbp_cmd_status->sfmt = SBP_SFMT_CURR;
537e9e688e2SHidetoshi Shimokawa 		else
538e9e688e2SHidetoshi Shimokawa 			sbp_cmd_status->sfmt = SBP_SFMT_DEFER;
539e9e688e2SHidetoshi Shimokawa 
540e9e688e2SHidetoshi Shimokawa 		sbp_cmd_status->valid = (sense->error_code & SSD_ERRCODE_VALID)
541e9e688e2SHidetoshi Shimokawa 		    ? 1 : 0;
542e9e688e2SHidetoshi Shimokawa 		sbp_cmd_status->s_key = sense->flags & SSD_KEY;
543e9e688e2SHidetoshi Shimokawa 		sbp_cmd_status->mark = (sense->flags & SSD_FILEMARK)? 1 : 0;
544e9e688e2SHidetoshi Shimokawa 		sbp_cmd_status->eom = (sense->flags & SSD_EOM) ? 1 : 0;
545e9e688e2SHidetoshi Shimokawa 		sbp_cmd_status->ill_len = (sense->flags & SSD_ILI) ? 1 : 0;
546e9e688e2SHidetoshi Shimokawa 
547e9e688e2SHidetoshi Shimokawa 		bcopy(&sense->info[0], &sbp_cmd_status->info, 4);
548e9e688e2SHidetoshi Shimokawa 
549e9e688e2SHidetoshi Shimokawa 		if (sense->extra_len <= 6)
550e9e688e2SHidetoshi Shimokawa 			/* add_sense_code(_qual), info, cmd_spec_info */
551e9e688e2SHidetoshi Shimokawa 			sbp_status->len = 4;
552e9e688e2SHidetoshi Shimokawa 		else
553e9e688e2SHidetoshi Shimokawa 			/* fru, sense_key_spec */
554e9e688e2SHidetoshi Shimokawa 			sbp_status->len = 5;
555e9e688e2SHidetoshi Shimokawa 
556e9e688e2SHidetoshi Shimokawa 		bcopy(&sense->cmd_spec_info[0], &sbp_cmd_status->cdb, 4);
557e9e688e2SHidetoshi Shimokawa 
558e9e688e2SHidetoshi Shimokawa 		sbp_cmd_status->s_code = sense->add_sense_code;
559e9e688e2SHidetoshi Shimokawa 		sbp_cmd_status->s_qlfr = sense->add_sense_code_qual;
560e9e688e2SHidetoshi Shimokawa 		sbp_cmd_status->fru = sense->fru;
561e9e688e2SHidetoshi Shimokawa 
562e9e688e2SHidetoshi Shimokawa 		bcopy(&sense->sense_key_spec[0],
563e9e688e2SHidetoshi Shimokawa 		    &sbp_cmd_status->s_keydep[0], 3);
564e9e688e2SHidetoshi Shimokawa 
565e9e688e2SHidetoshi Shimokawa 		break;
566e9e688e2SHidetoshi Shimokawa 	}
567e9e688e2SHidetoshi Shimokawa 	default:
568e9e688e2SHidetoshi Shimokawa 		printf("%s: unknown scsi status 0x%x\n", __FUNCTION__,
569e9e688e2SHidetoshi Shimokawa 		    sbp_status->status);
570e9e688e2SHidetoshi Shimokawa 	}
571e9e688e2SHidetoshi Shimokawa 
572e9e688e2SHidetoshi Shimokawa 	sbp_targ_status_FIFO(orbi,
573e9e688e2SHidetoshi Shimokawa 	    orbi->lstate->fifo_hi, orbi->lstate->fifo_lo, /*dequeue*/1);
574e9e688e2SHidetoshi Shimokawa 
575e9e688e2SHidetoshi Shimokawa 	if (orbi->page_table != NULL)
576e9e688e2SHidetoshi Shimokawa 		free(orbi->page_table, M_SBP_TARG);
577e9e688e2SHidetoshi Shimokawa }
578e9e688e2SHidetoshi Shimokawa 
579e9e688e2SHidetoshi Shimokawa static void
580e9e688e2SHidetoshi Shimokawa sbp_targ_cam_done(struct fw_xfer *xfer)
581e9e688e2SHidetoshi Shimokawa {
582e9e688e2SHidetoshi Shimokawa 	struct orb_info *orbi;
583e9e688e2SHidetoshi Shimokawa 	union ccb *ccb;
584e9e688e2SHidetoshi Shimokawa 
585e9e688e2SHidetoshi Shimokawa 	orbi = (struct orb_info *)xfer->sc;
586e9e688e2SHidetoshi Shimokawa 
587e9e688e2SHidetoshi Shimokawa 	if (debug)
588e9e688e2SHidetoshi Shimokawa 		printf("%s: resp=%d refcount=%d\n", __FUNCTION__,
589e9e688e2SHidetoshi Shimokawa 			xfer->resp, orbi->refcount);
590e9e688e2SHidetoshi Shimokawa 
591e9e688e2SHidetoshi Shimokawa 	if (xfer->resp != 0) {
592e9e688e2SHidetoshi Shimokawa 		printf("%s: xfer->resp != 0\n", __FUNCTION__);
593e9e688e2SHidetoshi Shimokawa 		orbi->status.resp = SBP_TRANS_FAIL;
594e9e688e2SHidetoshi Shimokawa 		orbi->status.status = htonl(OBJ_DATA | SBE_TIMEOUT /*XXX*/);
595e9e688e2SHidetoshi Shimokawa 		orbi->status.dead = 1;
596e9e688e2SHidetoshi Shimokawa 		sbp_targ_abort(STAILQ_NEXT(orbi, link));
597e9e688e2SHidetoshi Shimokawa 	}
598e9e688e2SHidetoshi Shimokawa 
599e9e688e2SHidetoshi Shimokawa 	orbi->refcount --;
600e9e688e2SHidetoshi Shimokawa 
601e9e688e2SHidetoshi Shimokawa 	ccb = orbi->ccb;
602e9e688e2SHidetoshi Shimokawa 	if (orbi->refcount == 0) {
603e9e688e2SHidetoshi Shimokawa 		if (orbi->state == ORBI_STATUS_ABORTED) {
604e9e688e2SHidetoshi Shimokawa 			if (debug)
605e9e688e2SHidetoshi Shimokawa 				printf("%s: orbi aborted\n", __FUNCTION__);
606e9e688e2SHidetoshi Shimokawa 			sbp_targ_remove_orb_info(orbi->lstate, orbi);
607e9e688e2SHidetoshi Shimokawa 			if (orbi->page_table != NULL)
608e9e688e2SHidetoshi Shimokawa 				free(orbi->page_table, M_SBP_TARG);
609e9e688e2SHidetoshi Shimokawa 			free(orbi, M_SBP_TARG);
610e9e688e2SHidetoshi Shimokawa 		} else if (orbi->status.resp == 0) {
611e9e688e2SHidetoshi Shimokawa 			if ((ccb->ccb_h.flags & CAM_SEND_STATUS) != 0)
612e9e688e2SHidetoshi Shimokawa 				sbp_targ_send_status(orbi, ccb);
613e9e688e2SHidetoshi Shimokawa 			ccb->ccb_h.status = CAM_REQ_CMP;
614e9e688e2SHidetoshi Shimokawa 			xpt_done(ccb);
615e9e688e2SHidetoshi Shimokawa 		} else {
616e9e688e2SHidetoshi Shimokawa 			orbi->status.len = 1;
617e9e688e2SHidetoshi Shimokawa 			sbp_targ_status_FIFO(orbi,
618e9e688e2SHidetoshi Shimokawa 		    	    orbi->lstate->fifo_hi, orbi->lstate->fifo_lo,
619e9e688e2SHidetoshi Shimokawa 			    /*dequeue*/1);
620e9e688e2SHidetoshi Shimokawa 			ccb->ccb_h.status = CAM_REQ_ABORTED;
621e9e688e2SHidetoshi Shimokawa 			xpt_done(ccb);
622e9e688e2SHidetoshi Shimokawa 		}
623e9e688e2SHidetoshi Shimokawa 	}
624e9e688e2SHidetoshi Shimokawa 
625e9e688e2SHidetoshi Shimokawa 	fw_xfer_free(xfer);
626e9e688e2SHidetoshi Shimokawa }
627e9e688e2SHidetoshi Shimokawa 
628e9e688e2SHidetoshi Shimokawa static cam_status
629e9e688e2SHidetoshi Shimokawa sbp_targ_abort_ccb(struct sbp_targ_softc *sc, union ccb *ccb)
630e9e688e2SHidetoshi Shimokawa {
631e9e688e2SHidetoshi Shimokawa 	union ccb *accb;
632e9e688e2SHidetoshi Shimokawa 	struct sbp_targ_lstate *lstate;
633e9e688e2SHidetoshi Shimokawa 	struct ccb_hdr_slist *list;
634e9e688e2SHidetoshi Shimokawa 	struct ccb_hdr *curelm;
635e9e688e2SHidetoshi Shimokawa 	int found;
636e9e688e2SHidetoshi Shimokawa 	cam_status status;
637e9e688e2SHidetoshi Shimokawa 
638e9e688e2SHidetoshi Shimokawa 	status = sbp_targ_find_devs(sc, ccb, &lstate, 0);
639e9e688e2SHidetoshi Shimokawa 	if (status != CAM_REQ_CMP)
640e9e688e2SHidetoshi Shimokawa 		return (status);
641e9e688e2SHidetoshi Shimokawa 
642e9e688e2SHidetoshi Shimokawa 	accb = ccb->cab.abort_ccb;
643e9e688e2SHidetoshi Shimokawa 
644e9e688e2SHidetoshi Shimokawa 	if (accb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO)
645e9e688e2SHidetoshi Shimokawa 		list = &lstate->accept_tios;
646e9e688e2SHidetoshi Shimokawa 	else if (accb->ccb_h.func_code == XPT_IMMED_NOTIFY)
647e9e688e2SHidetoshi Shimokawa 		list = &lstate->immed_notifies;
648e9e688e2SHidetoshi Shimokawa 	else
649e9e688e2SHidetoshi Shimokawa 		return (CAM_UA_ABORT);
650e9e688e2SHidetoshi Shimokawa 
651e9e688e2SHidetoshi Shimokawa 	curelm = SLIST_FIRST(list);
652e9e688e2SHidetoshi Shimokawa 	found = 0;
653e9e688e2SHidetoshi Shimokawa 	if (curelm == &accb->ccb_h) {
654e9e688e2SHidetoshi Shimokawa 		found = 1;
655e9e688e2SHidetoshi Shimokawa 		SLIST_REMOVE_HEAD(list, sim_links.sle);
656e9e688e2SHidetoshi Shimokawa 	} else {
657e9e688e2SHidetoshi Shimokawa 		while(curelm != NULL) {
658e9e688e2SHidetoshi Shimokawa 			struct ccb_hdr *nextelm;
659e9e688e2SHidetoshi Shimokawa 
660e9e688e2SHidetoshi Shimokawa 			nextelm = SLIST_NEXT(curelm, sim_links.sle);
661e9e688e2SHidetoshi Shimokawa 			if (nextelm == &accb->ccb_h) {
662e9e688e2SHidetoshi Shimokawa 				found = 1;
663e9e688e2SHidetoshi Shimokawa 				SLIST_NEXT(curelm, sim_links.sle) =
664e9e688e2SHidetoshi Shimokawa 				    SLIST_NEXT(nextelm, sim_links.sle);
665e9e688e2SHidetoshi Shimokawa 				break;
666e9e688e2SHidetoshi Shimokawa 			}
667e9e688e2SHidetoshi Shimokawa 			curelm = nextelm;
668e9e688e2SHidetoshi Shimokawa 		}
669e9e688e2SHidetoshi Shimokawa 	}
670e9e688e2SHidetoshi Shimokawa 	if (found) {
671e9e688e2SHidetoshi Shimokawa 		accb->ccb_h.status = CAM_REQ_ABORTED;
672e9e688e2SHidetoshi Shimokawa 		xpt_done(accb);
673e9e688e2SHidetoshi Shimokawa 		return (CAM_REQ_CMP);
674e9e688e2SHidetoshi Shimokawa 	}
675e9e688e2SHidetoshi Shimokawa 	printf("%s: not found\n", __FUNCTION__);
676e9e688e2SHidetoshi Shimokawa 	return (CAM_PATH_INVALID);
677e9e688e2SHidetoshi Shimokawa }
678e9e688e2SHidetoshi Shimokawa 
679e9e688e2SHidetoshi Shimokawa static void
680e9e688e2SHidetoshi Shimokawa sbp_targ_xfer_buf(struct orb_info *orbi, u_int offset,
681e9e688e2SHidetoshi Shimokawa     u_int16_t dst_hi, u_int32_t dst_lo, u_int size,
682e9e688e2SHidetoshi Shimokawa     void (*hand)(struct fw_xfer *))
683e9e688e2SHidetoshi Shimokawa {
684e9e688e2SHidetoshi Shimokawa 	struct fw_xfer *xfer;
685e9e688e2SHidetoshi Shimokawa 	u_int len, ccb_dir, off = 0;
686e9e688e2SHidetoshi Shimokawa 	char *ptr;
687e9e688e2SHidetoshi Shimokawa 
688e9e688e2SHidetoshi Shimokawa 	if (debug)
689e9e688e2SHidetoshi Shimokawa 		printf("%s: offset=%d size=%d\n", __FUNCTION__, offset, size);
690e9e688e2SHidetoshi Shimokawa 	ccb_dir = orbi->ccb->ccb_h.flags & CAM_DIR_MASK;
691e9e688e2SHidetoshi Shimokawa 	ptr = (char *)orbi->ccb->csio.data_ptr + offset;
692e9e688e2SHidetoshi Shimokawa 
693e9e688e2SHidetoshi Shimokawa 	while (size > 0) {
694e9e688e2SHidetoshi Shimokawa 		/* XXX assume dst_lo + off doesn't overflow */
695e9e688e2SHidetoshi Shimokawa 		len = MIN(size, 2048 /* XXX */);
696e9e688e2SHidetoshi Shimokawa 		size -= len;
697e9e688e2SHidetoshi Shimokawa 		orbi->refcount ++;
698e9e688e2SHidetoshi Shimokawa 		if (ccb_dir == CAM_DIR_OUT)
699e9e688e2SHidetoshi Shimokawa 			xfer = fwmem_read_block(orbi->fwdev,
700e9e688e2SHidetoshi Shimokawa 			   (void *)orbi, /*spd*/2,
701e9e688e2SHidetoshi Shimokawa 			    dst_hi, dst_lo + off, len,
702e9e688e2SHidetoshi Shimokawa 			    ptr + off, hand);
703e9e688e2SHidetoshi Shimokawa 		else
704e9e688e2SHidetoshi Shimokawa 			xfer = fwmem_write_block(orbi->fwdev,
705e9e688e2SHidetoshi Shimokawa 			   (void *)orbi, /*spd*/2,
706e9e688e2SHidetoshi Shimokawa 			    dst_hi, dst_lo + off, len,
707e9e688e2SHidetoshi Shimokawa 			    ptr + off, hand);
708e9e688e2SHidetoshi Shimokawa 		if (xfer == NULL) {
709e9e688e2SHidetoshi Shimokawa 			printf("%s: xfer == NULL", __FUNCTION__);
710e9e688e2SHidetoshi Shimokawa 			/* XXX what should we do?? */
711e9e688e2SHidetoshi Shimokawa 			orbi->refcount --;
712e9e688e2SHidetoshi Shimokawa 		}
713e9e688e2SHidetoshi Shimokawa 		off += len;
714e9e688e2SHidetoshi Shimokawa 	}
715e9e688e2SHidetoshi Shimokawa }
716e9e688e2SHidetoshi Shimokawa 
717e9e688e2SHidetoshi Shimokawa static void
718e9e688e2SHidetoshi Shimokawa sbp_targ_pt_done(struct fw_xfer *xfer)
719e9e688e2SHidetoshi Shimokawa {
720e9e688e2SHidetoshi Shimokawa 	struct orb_info *orbi;
721e9e688e2SHidetoshi Shimokawa 	union ccb *ccb;
722e9e688e2SHidetoshi Shimokawa 	u_int i, offset, res, len;
723e9e688e2SHidetoshi Shimokawa 	u_int32_t t1, t2, *p;
724e9e688e2SHidetoshi Shimokawa 
725e9e688e2SHidetoshi Shimokawa 	orbi = (struct orb_info *)xfer->sc;
726e9e688e2SHidetoshi Shimokawa 	ccb = orbi->ccb;
727e9e688e2SHidetoshi Shimokawa 	if (orbi->state == ORBI_STATUS_ABORTED) {
728e9e688e2SHidetoshi Shimokawa 		if (debug)
729e9e688e2SHidetoshi Shimokawa 			printf("%s: orbi aborted\n", __FUNCTION__);
730e9e688e2SHidetoshi Shimokawa 		sbp_targ_remove_orb_info(orbi->lstate, orbi);
731e9e688e2SHidetoshi Shimokawa 		free(orbi->page_table, M_SBP_TARG);
732e9e688e2SHidetoshi Shimokawa 		free(orbi, M_SBP_TARG);
733e9e688e2SHidetoshi Shimokawa 		fw_xfer_free(xfer);
734e9e688e2SHidetoshi Shimokawa 		return;
735e9e688e2SHidetoshi Shimokawa 	}
736e9e688e2SHidetoshi Shimokawa 	if (xfer->resp != 0) {
737e9e688e2SHidetoshi Shimokawa 		printf("%s: xfer->resp != 0\n", __FUNCTION__);
738e9e688e2SHidetoshi Shimokawa 		orbi->status.resp = SBP_TRANS_FAIL;
739e9e688e2SHidetoshi Shimokawa 		orbi->status.status = htonl(OBJ_PT | SBE_TIMEOUT /*XXX*/);
740e9e688e2SHidetoshi Shimokawa 		orbi->status.dead = 1;
741e9e688e2SHidetoshi Shimokawa 		orbi->status.len = 1;
742e9e688e2SHidetoshi Shimokawa 		sbp_targ_abort(STAILQ_NEXT(orbi, link));
743e9e688e2SHidetoshi Shimokawa 
744e9e688e2SHidetoshi Shimokawa 		sbp_targ_status_FIFO(orbi,
745e9e688e2SHidetoshi Shimokawa 		    orbi->lstate->fifo_hi, orbi->lstate->fifo_lo, /*dequeue*/1);
746e9e688e2SHidetoshi Shimokawa 		free(orbi->page_table, M_SBP_TARG);
747e9e688e2SHidetoshi Shimokawa 		fw_xfer_free(xfer);
748e9e688e2SHidetoshi Shimokawa 		return;
749e9e688e2SHidetoshi Shimokawa 	}
750e9e688e2SHidetoshi Shimokawa 	res = ccb->csio.dxfer_len;
751e9e688e2SHidetoshi Shimokawa 	offset = 0;
752e9e688e2SHidetoshi Shimokawa 	if (debug)
753e9e688e2SHidetoshi Shimokawa 		printf("%s: dxfer_len=%d\n", __FUNCTION__, res);
754e9e688e2SHidetoshi Shimokawa 	orbi->refcount ++;
755e9e688e2SHidetoshi Shimokawa 	for (p = orbi->page_table, i = orbi->orb4.data_size; i > 0; i --) {
756e9e688e2SHidetoshi Shimokawa 		t1 = ntohl(*p++);
757e9e688e2SHidetoshi Shimokawa 		t2 = ntohl(*p++);
758e9e688e2SHidetoshi Shimokawa 		if (debug)
759e9e688e2SHidetoshi Shimokawa 			printf("page_table: %04x:%08x %d\n",
760e9e688e2SHidetoshi Shimokawa 			    t1 & 0xffff, t2, t1>>16);
761e9e688e2SHidetoshi Shimokawa 		len = MIN(t1 >> 16, res);
762e9e688e2SHidetoshi Shimokawa 		res -= len;
763e9e688e2SHidetoshi Shimokawa 		sbp_targ_xfer_buf(orbi, offset, t1 & 0xffff, t2, len,
764e9e688e2SHidetoshi Shimokawa 		    sbp_targ_cam_done);
765e9e688e2SHidetoshi Shimokawa 		offset += len;
766e9e688e2SHidetoshi Shimokawa 		if (res == 0)
767e9e688e2SHidetoshi Shimokawa 			break;
768e9e688e2SHidetoshi Shimokawa 	}
769e9e688e2SHidetoshi Shimokawa 	orbi->refcount --;
770e9e688e2SHidetoshi Shimokawa 	if (orbi->refcount == 0)
771e9e688e2SHidetoshi Shimokawa 		printf("%s: refcount == 0\n", __FUNCTION__);
772e9e688e2SHidetoshi Shimokawa 	if (res !=0)
773e9e688e2SHidetoshi Shimokawa 		/* XXX handle res != 0 case */
774e9e688e2SHidetoshi Shimokawa 		printf("%s: page table is too small(%d)\n", __FUNCTION__, res);
775e9e688e2SHidetoshi Shimokawa 
776e9e688e2SHidetoshi Shimokawa 	fw_xfer_free(xfer);
777e9e688e2SHidetoshi Shimokawa 	return;
778e9e688e2SHidetoshi Shimokawa }
779e9e688e2SHidetoshi Shimokawa 
780e9e688e2SHidetoshi Shimokawa static void
781e9e688e2SHidetoshi Shimokawa sbp_targ_fetch_pt(struct orb_info *orbi)
782e9e688e2SHidetoshi Shimokawa {
783e9e688e2SHidetoshi Shimokawa 	struct fw_xfer *xfer;
784e9e688e2SHidetoshi Shimokawa 
785e9e688e2SHidetoshi Shimokawa 	if (debug)
786e9e688e2SHidetoshi Shimokawa 		printf("%s: page_table_size=%d\n",
787e9e688e2SHidetoshi Shimokawa 		    __FUNCTION__, orbi->orb4.data_size);
788e9e688e2SHidetoshi Shimokawa 	orbi->page_table = malloc(orbi->orb4.data_size*8, M_SBP_TARG, M_NOWAIT);
789e9e688e2SHidetoshi Shimokawa 	if (orbi->page_table == NULL)
790e9e688e2SHidetoshi Shimokawa 		goto error;
791e9e688e2SHidetoshi Shimokawa 	xfer = fwmem_read_block(orbi->fwdev, (void *)orbi, /*spd*/2,
792e9e688e2SHidetoshi Shimokawa 		    orbi->data_hi, orbi->data_lo, orbi->orb4.data_size*8,
793e9e688e2SHidetoshi Shimokawa 			    (void *)orbi->page_table, sbp_targ_pt_done);
794e9e688e2SHidetoshi Shimokawa 	if (xfer != NULL)
795e9e688e2SHidetoshi Shimokawa 		return;
796e9e688e2SHidetoshi Shimokawa error:
797e9e688e2SHidetoshi Shimokawa 	orbi->ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
798e9e688e2SHidetoshi Shimokawa 	xpt_done(orbi->ccb);
799e9e688e2SHidetoshi Shimokawa 	return;
800e9e688e2SHidetoshi Shimokawa }
801e9e688e2SHidetoshi Shimokawa 
802e9e688e2SHidetoshi Shimokawa static void
803e9e688e2SHidetoshi Shimokawa sbp_targ_action1(struct cam_sim *sim, union ccb *ccb)
804e9e688e2SHidetoshi Shimokawa {
805e9e688e2SHidetoshi Shimokawa 	struct sbp_targ_softc *sc;
806e9e688e2SHidetoshi Shimokawa 	struct sbp_targ_lstate *lstate;
807e9e688e2SHidetoshi Shimokawa 	cam_status status;
808e9e688e2SHidetoshi Shimokawa 	u_int ccb_dir;
809e9e688e2SHidetoshi Shimokawa 
810e9e688e2SHidetoshi Shimokawa 	sc =  (struct sbp_targ_softc *)cam_sim_softc(sim);
811e9e688e2SHidetoshi Shimokawa 
812e9e688e2SHidetoshi Shimokawa 	status = sbp_targ_find_devs(sc, ccb, &lstate, TRUE);
813e9e688e2SHidetoshi Shimokawa 
814e9e688e2SHidetoshi Shimokawa 	switch (ccb->ccb_h.func_code) {
815e9e688e2SHidetoshi Shimokawa 	case XPT_CONT_TARGET_IO:
816e9e688e2SHidetoshi Shimokawa 	{
817e9e688e2SHidetoshi Shimokawa 		struct orb_info *orbi;
818e9e688e2SHidetoshi Shimokawa 
819e9e688e2SHidetoshi Shimokawa 		if (debug)
820e9e688e2SHidetoshi Shimokawa 			printf("%s: XPT_CONT_TARGET_IO\n", __FUNCTION__);
821e9e688e2SHidetoshi Shimokawa 
822e9e688e2SHidetoshi Shimokawa 		if (status != CAM_REQ_CMP) {
823e9e688e2SHidetoshi Shimokawa 			ccb->ccb_h.status = status;
824e9e688e2SHidetoshi Shimokawa 			xpt_done(ccb);
825e9e688e2SHidetoshi Shimokawa 			break;
826e9e688e2SHidetoshi Shimokawa 		}
827e9e688e2SHidetoshi Shimokawa 		/* XXX transfer from/to initiator */
828e9e688e2SHidetoshi Shimokawa 		orbi = sbp_targ_get_orb_info(lstate,
829e9e688e2SHidetoshi Shimokawa 		    ccb->csio.tag_id, ccb->csio.init_id);
830e9e688e2SHidetoshi Shimokawa 		if (orbi == NULL) {
831e9e688e2SHidetoshi Shimokawa 			printf("%s: no such ORB found, aborted?\n",
832e9e688e2SHidetoshi Shimokawa 				__FUNCTION__);
833e9e688e2SHidetoshi Shimokawa 			ccb->ccb_h.status = CAM_REQ_ABORTED; /* XXX */
834e9e688e2SHidetoshi Shimokawa 			xpt_done(ccb);
835e9e688e2SHidetoshi Shimokawa 			break;
836e9e688e2SHidetoshi Shimokawa 		}
837e9e688e2SHidetoshi Shimokawa 		if (orbi->state == ORBI_STATUS_ABORTED) {
838e9e688e2SHidetoshi Shimokawa 			if (debug)
839e9e688e2SHidetoshi Shimokawa 				printf("%s: ctio aborted\n", __FUNCTION__);
840e9e688e2SHidetoshi Shimokawa 			sbp_targ_remove_orb_info(orbi->lstate, orbi);
841e9e688e2SHidetoshi Shimokawa 			free(orbi, M_SBP_TARG);
842e9e688e2SHidetoshi Shimokawa 			break;
843e9e688e2SHidetoshi Shimokawa 		}
844e9e688e2SHidetoshi Shimokawa 		orbi->state = ORBI_STATUS_CTIO;
845e9e688e2SHidetoshi Shimokawa 
846e9e688e2SHidetoshi Shimokawa 		orbi->ccb = ccb;
847e9e688e2SHidetoshi Shimokawa 		ccb_dir = ccb->ccb_h.flags & CAM_DIR_MASK;
848e9e688e2SHidetoshi Shimokawa 
849e9e688e2SHidetoshi Shimokawa 		/* XXX */
850e9e688e2SHidetoshi Shimokawa 		if (ccb->csio.dxfer_len == 0)
851e9e688e2SHidetoshi Shimokawa 			ccb_dir = CAM_DIR_NONE;
852e9e688e2SHidetoshi Shimokawa 
853e9e688e2SHidetoshi Shimokawa 		/* Sanity check */
854e9e688e2SHidetoshi Shimokawa 		if (ccb_dir == CAM_DIR_IN && orbi->orb4.dir == 0)
855e9e688e2SHidetoshi Shimokawa 			printf("%s: direction mismatch\n", __FUNCTION__);
856e9e688e2SHidetoshi Shimokawa 
857e9e688e2SHidetoshi Shimokawa 		/* check page table */
858e9e688e2SHidetoshi Shimokawa 		if (ccb_dir != CAM_DIR_NONE && orbi->orb4.page_table_present) {
859e9e688e2SHidetoshi Shimokawa 			if (debug)
860e9e688e2SHidetoshi Shimokawa 				printf("%s: page_table_present\n",
861e9e688e2SHidetoshi Shimokawa 				    __FUNCTION__);
862e9e688e2SHidetoshi Shimokawa 			if (orbi->orb4.page_size != 0) {
863e9e688e2SHidetoshi Shimokawa 				printf("%s: unsupported pagesize %d != 0\n",
864e9e688e2SHidetoshi Shimokawa 			 	    __FUNCTION__, orbi->orb4.page_size);
865e9e688e2SHidetoshi Shimokawa 				ccb->ccb_h.status = CAM_REQ_INVALID;
866e9e688e2SHidetoshi Shimokawa 				xpt_done(ccb);
867e9e688e2SHidetoshi Shimokawa 				break;
868e9e688e2SHidetoshi Shimokawa 			}
869e9e688e2SHidetoshi Shimokawa 			sbp_targ_fetch_pt(orbi);
870e9e688e2SHidetoshi Shimokawa 			break;
871e9e688e2SHidetoshi Shimokawa 		}
872e9e688e2SHidetoshi Shimokawa 
873e9e688e2SHidetoshi Shimokawa 		/* Sanity check */
874e9e688e2SHidetoshi Shimokawa 		if (ccb_dir != CAM_DIR_NONE &&
875e9e688e2SHidetoshi Shimokawa 		    orbi->orb4.data_size != ccb->csio.dxfer_len)
876e9e688e2SHidetoshi Shimokawa 			printf("%s: data_size(%d) != dxfer_len(%d)\n",
877e9e688e2SHidetoshi Shimokawa 			    __FUNCTION__, orbi->orb4.data_size,
878e9e688e2SHidetoshi Shimokawa 			    ccb->csio.dxfer_len);
879e9e688e2SHidetoshi Shimokawa 
880e9e688e2SHidetoshi Shimokawa 		if (ccb_dir != CAM_DIR_NONE)
881e9e688e2SHidetoshi Shimokawa 			sbp_targ_xfer_buf(orbi, 0, orbi->data_hi,
882e9e688e2SHidetoshi Shimokawa 			    orbi->data_lo,
883e9e688e2SHidetoshi Shimokawa 			    MIN(orbi->orb4.data_size, ccb->csio.dxfer_len),
884e9e688e2SHidetoshi Shimokawa 			    sbp_targ_cam_done);
885e9e688e2SHidetoshi Shimokawa 
886e9e688e2SHidetoshi Shimokawa 		if (ccb_dir == CAM_DIR_NONE) {
887e9e688e2SHidetoshi Shimokawa 			if ((ccb->ccb_h.flags & CAM_SEND_STATUS) != 0)
888e9e688e2SHidetoshi Shimokawa 				sbp_targ_send_status(orbi, ccb);
889e9e688e2SHidetoshi Shimokawa 			ccb->ccb_h.status = CAM_REQ_CMP;
890e9e688e2SHidetoshi Shimokawa 			xpt_done(ccb);
891e9e688e2SHidetoshi Shimokawa 		}
892e9e688e2SHidetoshi Shimokawa 		break;
893e9e688e2SHidetoshi Shimokawa 	}
894e9e688e2SHidetoshi Shimokawa 	case XPT_ACCEPT_TARGET_IO:	/* Add Accept Target IO Resource */
895e9e688e2SHidetoshi Shimokawa 		if (status != CAM_REQ_CMP) {
896e9e688e2SHidetoshi Shimokawa 			ccb->ccb_h.status = status;
897e9e688e2SHidetoshi Shimokawa 			xpt_done(ccb);
898e9e688e2SHidetoshi Shimokawa 			break;
899e9e688e2SHidetoshi Shimokawa 		}
900e9e688e2SHidetoshi Shimokawa 		SLIST_INSERT_HEAD(&lstate->accept_tios, &ccb->ccb_h,
901e9e688e2SHidetoshi Shimokawa 		    sim_links.sle);
902e9e688e2SHidetoshi Shimokawa 		ccb->ccb_h.status = CAM_REQ_INPROG;
903e9e688e2SHidetoshi Shimokawa 		if ((lstate->flags & ATIO_STARVED) != 0) {
904e9e688e2SHidetoshi Shimokawa 			if (debug)
905e9e688e2SHidetoshi Shimokawa 				printf("%s: new atio arrived\n", __FUNCTION__);
906e9e688e2SHidetoshi Shimokawa 			lstate->flags &= ~ATIO_STARVED;
907e9e688e2SHidetoshi Shimokawa 			sbp_targ_fetch_orb(lstate->sc, lstate->fwdev,
908e9e688e2SHidetoshi Shimokawa 			    lstate->last_hi, lstate->last_lo,
909e9e688e2SHidetoshi Shimokawa 			    lstate, FETCH_CMD);
910e9e688e2SHidetoshi Shimokawa 		}
911e9e688e2SHidetoshi Shimokawa 		break;
912e9e688e2SHidetoshi Shimokawa 	case XPT_NOTIFY_ACK:		/* recycle notify ack */
913e9e688e2SHidetoshi Shimokawa 	case XPT_IMMED_NOTIFY:		/* Add Immediate Notify Resource */
914e9e688e2SHidetoshi Shimokawa 		if (status != CAM_REQ_CMP) {
915e9e688e2SHidetoshi Shimokawa 			ccb->ccb_h.status = status;
916e9e688e2SHidetoshi Shimokawa 			xpt_done(ccb);
917e9e688e2SHidetoshi Shimokawa 			break;
918e9e688e2SHidetoshi Shimokawa 		}
919e9e688e2SHidetoshi Shimokawa 		SLIST_INSERT_HEAD(&lstate->immed_notifies, &ccb->ccb_h,
920e9e688e2SHidetoshi Shimokawa 		    sim_links.sle);
921e9e688e2SHidetoshi Shimokawa 		ccb->ccb_h.status = CAM_REQ_INPROG;
922e9e688e2SHidetoshi Shimokawa 		sbp_targ_send_lstate_events(sc, lstate);
923e9e688e2SHidetoshi Shimokawa 		break;
924e9e688e2SHidetoshi Shimokawa 	case XPT_EN_LUN:
925e9e688e2SHidetoshi Shimokawa 		sbp_targ_en_lun(sc, ccb);
926e9e688e2SHidetoshi Shimokawa 		xpt_done(ccb);
927e9e688e2SHidetoshi Shimokawa 		break;
928e9e688e2SHidetoshi Shimokawa 	case XPT_PATH_INQ:
929e9e688e2SHidetoshi Shimokawa 	{
930e9e688e2SHidetoshi Shimokawa 		struct ccb_pathinq *cpi = &ccb->cpi;
931e9e688e2SHidetoshi Shimokawa 
932e9e688e2SHidetoshi Shimokawa 		cpi->version_num = 1; /* XXX??? */
933e9e688e2SHidetoshi Shimokawa 		cpi->hba_inquiry = PI_TAG_ABLE;
934e9e688e2SHidetoshi Shimokawa 		cpi->target_sprt = PIT_PROCESSOR
935e9e688e2SHidetoshi Shimokawa 				 | PIT_DISCONNECT
936e9e688e2SHidetoshi Shimokawa 				 | PIT_TERM_IO;
937e9e688e2SHidetoshi Shimokawa 		cpi->hba_misc = PIM_NOBUSRESET | PIM_NO_6_BYTE;
938e9e688e2SHidetoshi Shimokawa 		cpi->hba_eng_cnt = 0;
939e9e688e2SHidetoshi Shimokawa 		cpi->max_target = 7; /* XXX */
940e9e688e2SHidetoshi Shimokawa 		cpi->max_lun = MAX_LUN - 1;
941e9e688e2SHidetoshi Shimokawa 		cpi->initiator_id = 7; /* XXX */
942e9e688e2SHidetoshi Shimokawa 		cpi->bus_id = sim->bus_id;
943e9e688e2SHidetoshi Shimokawa 		cpi->base_transfer_speed = 400 * 1000 / 8;
944e9e688e2SHidetoshi Shimokawa 		strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
945e9e688e2SHidetoshi Shimokawa 		strncpy(cpi->hba_vid, "SBP_TARG", HBA_IDLEN);
946e9e688e2SHidetoshi Shimokawa 		strncpy(cpi->dev_name, sim->sim_name, DEV_IDLEN);
947e9e688e2SHidetoshi Shimokawa 		cpi->unit_number = sim->unit_number;
948e9e688e2SHidetoshi Shimokawa 
949e9e688e2SHidetoshi Shimokawa 		cpi->ccb_h.status = CAM_REQ_CMP;
950e9e688e2SHidetoshi Shimokawa 		xpt_done(ccb);
951e9e688e2SHidetoshi Shimokawa 		break;
952e9e688e2SHidetoshi Shimokawa 	}
953e9e688e2SHidetoshi Shimokawa 	case XPT_ABORT:
954e9e688e2SHidetoshi Shimokawa 	{
955e9e688e2SHidetoshi Shimokawa 		union ccb *accb = ccb->cab.abort_ccb;
956e9e688e2SHidetoshi Shimokawa 
957e9e688e2SHidetoshi Shimokawa 		switch (accb->ccb_h.func_code) {
958e9e688e2SHidetoshi Shimokawa 		case XPT_ACCEPT_TARGET_IO:
959e9e688e2SHidetoshi Shimokawa 		case XPT_IMMED_NOTIFY:
960e9e688e2SHidetoshi Shimokawa 			ccb->ccb_h.status = sbp_targ_abort_ccb(sc, ccb);
961e9e688e2SHidetoshi Shimokawa 			break;
962e9e688e2SHidetoshi Shimokawa 		case XPT_CONT_TARGET_IO:
963e9e688e2SHidetoshi Shimokawa 			/* XXX */
964e9e688e2SHidetoshi Shimokawa 			ccb->ccb_h.status = CAM_UA_ABORT;
965e9e688e2SHidetoshi Shimokawa 			break;
966e9e688e2SHidetoshi Shimokawa 		default:
967e9e688e2SHidetoshi Shimokawa 			printf("%s: aborting unknown function %d\n",
968e9e688e2SHidetoshi Shimokawa 				__FUNCTION__, accb->ccb_h.func_code);
969e9e688e2SHidetoshi Shimokawa 			ccb->ccb_h.status = CAM_REQ_INVALID;
970e9e688e2SHidetoshi Shimokawa 			break;
971e9e688e2SHidetoshi Shimokawa 		}
972e9e688e2SHidetoshi Shimokawa 		xpt_done(ccb);
973e9e688e2SHidetoshi Shimokawa 		break;
974e9e688e2SHidetoshi Shimokawa 	}
975e9e688e2SHidetoshi Shimokawa 	default:
976e9e688e2SHidetoshi Shimokawa 		printf("%s: unknown function %d\n",
977e9e688e2SHidetoshi Shimokawa 		    __FUNCTION__, ccb->ccb_h.func_code);
978e9e688e2SHidetoshi Shimokawa 		ccb->ccb_h.status = CAM_REQ_INVALID;
979e9e688e2SHidetoshi Shimokawa 		xpt_done(ccb);
980e9e688e2SHidetoshi Shimokawa 		break;
981e9e688e2SHidetoshi Shimokawa 	}
982e9e688e2SHidetoshi Shimokawa 	return;
983e9e688e2SHidetoshi Shimokawa }
984e9e688e2SHidetoshi Shimokawa 
985e9e688e2SHidetoshi Shimokawa static void
986e9e688e2SHidetoshi Shimokawa sbp_targ_action(struct cam_sim *sim, union ccb *ccb)
987e9e688e2SHidetoshi Shimokawa {
988e9e688e2SHidetoshi Shimokawa 	int s;
989e9e688e2SHidetoshi Shimokawa 
990e9e688e2SHidetoshi Shimokawa 	s = splfw();
991e9e688e2SHidetoshi Shimokawa 	sbp_targ_action1(sim, ccb);
992e9e688e2SHidetoshi Shimokawa 	splx(s);
993e9e688e2SHidetoshi Shimokawa }
994e9e688e2SHidetoshi Shimokawa 
995e9e688e2SHidetoshi Shimokawa static void
996e9e688e2SHidetoshi Shimokawa sbp_targ_poll(struct cam_sim *sim)
997e9e688e2SHidetoshi Shimokawa {
998e9e688e2SHidetoshi Shimokawa 	/* XXX */
999e9e688e2SHidetoshi Shimokawa 	return;
1000e9e688e2SHidetoshi Shimokawa }
1001e9e688e2SHidetoshi Shimokawa 
1002e9e688e2SHidetoshi Shimokawa static void
1003e9e688e2SHidetoshi Shimokawa sbp_targ_cmd_handler(struct fw_xfer *xfer)
1004e9e688e2SHidetoshi Shimokawa {
1005e9e688e2SHidetoshi Shimokawa 	struct fw_pkt *fp;
1006e9e688e2SHidetoshi Shimokawa 	u_int32_t *orb;
1007e9e688e2SHidetoshi Shimokawa 	struct corb4 *orb4;
1008e9e688e2SHidetoshi Shimokawa 	struct orb_info *orbi;
1009e9e688e2SHidetoshi Shimokawa 	struct ccb_accept_tio *atio;
1010e9e688e2SHidetoshi Shimokawa 	struct sbp_targ_lstate *lstate;
1011e9e688e2SHidetoshi Shimokawa 	u_char *bytes;
1012e9e688e2SHidetoshi Shimokawa 	int i;
1013e9e688e2SHidetoshi Shimokawa 
1014e9e688e2SHidetoshi Shimokawa 	orbi = (struct orb_info *)xfer->sc;
1015e9e688e2SHidetoshi Shimokawa 	if (xfer->resp != 0) {
1016e9e688e2SHidetoshi Shimokawa 		printf("%s: xfer->resp != 0\n", __FUNCTION__);
1017e9e688e2SHidetoshi Shimokawa 		orbi->status.resp = SBP_TRANS_FAIL;
1018e9e688e2SHidetoshi Shimokawa 		orbi->status.status = htonl(OBJ_ORB | SBE_TIMEOUT /*XXX*/);
1019e9e688e2SHidetoshi Shimokawa 		orbi->status.dead = 1;
1020e9e688e2SHidetoshi Shimokawa 		orbi->status.len = 1;
1021e9e688e2SHidetoshi Shimokawa 		sbp_targ_abort(STAILQ_NEXT(orbi, link));
1022e9e688e2SHidetoshi Shimokawa 
1023e9e688e2SHidetoshi Shimokawa 		sbp_targ_status_FIFO(orbi,
1024e9e688e2SHidetoshi Shimokawa 		    orbi->lstate->fifo_hi, orbi->lstate->fifo_lo, /*dequeue*/1);
1025e9e688e2SHidetoshi Shimokawa 		fw_xfer_free(xfer);
1026e9e688e2SHidetoshi Shimokawa 		return;
1027e9e688e2SHidetoshi Shimokawa 	}
1028e9e688e2SHidetoshi Shimokawa 	fp = &xfer->recv.hdr;
1029e9e688e2SHidetoshi Shimokawa 
1030e9e688e2SHidetoshi Shimokawa 	if (orbi->state == ORBI_STATUS_ABORTED) {
1031e9e688e2SHidetoshi Shimokawa 		printf("%s: aborted\n", __FUNCTION__);
1032e9e688e2SHidetoshi Shimokawa 		sbp_targ_remove_orb_info(orbi->lstate, orbi);
1033e9e688e2SHidetoshi Shimokawa 		free(orbi, M_SBP_TARG);
1034e9e688e2SHidetoshi Shimokawa 		goto done0;
1035e9e688e2SHidetoshi Shimokawa 	}
1036e9e688e2SHidetoshi Shimokawa 	orbi->state = ORBI_STATUS_ATIO;
1037e9e688e2SHidetoshi Shimokawa 
1038e9e688e2SHidetoshi Shimokawa 	lstate = orbi->lstate;
1039e9e688e2SHidetoshi Shimokawa 
1040e9e688e2SHidetoshi Shimokawa 	orb = orbi->orb;
1041e9e688e2SHidetoshi Shimokawa 	/* swap payload except SCSI command */
1042e9e688e2SHidetoshi Shimokawa 	for (i = 0; i < 5; i ++)
1043e9e688e2SHidetoshi Shimokawa 		orb[i] = ntohl(orb[i]);
1044e9e688e2SHidetoshi Shimokawa 
1045e9e688e2SHidetoshi Shimokawa 	orb4 = (struct corb4 *)&orb[4];
1046e9e688e2SHidetoshi Shimokawa 	if (orb4->rq_fmt != 0) {
1047e9e688e2SHidetoshi Shimokawa 		/* XXX */
1048e9e688e2SHidetoshi Shimokawa 		printf("%s: rq_fmt(%d) != 0\n", __FUNCTION__, orb4->rq_fmt);
1049e9e688e2SHidetoshi Shimokawa 	}
1050e9e688e2SHidetoshi Shimokawa 
1051e9e688e2SHidetoshi Shimokawa 	atio = orbi->atio;
1052e9e688e2SHidetoshi Shimokawa 	atio->ccb_h.target_id = 0; /* XXX */
1053e9e688e2SHidetoshi Shimokawa 	atio->ccb_h.target_lun = lstate->lun;
1054e9e688e2SHidetoshi Shimokawa 	atio->sense_len = 0;
1055e9e688e2SHidetoshi Shimokawa 	atio->tag_action = 1; /* XXX */
1056e9e688e2SHidetoshi Shimokawa 	atio->tag_id = orbi->orb_lo;
1057e9e688e2SHidetoshi Shimokawa #if 0
1058e9e688e2SHidetoshi Shimokawa 	atio->init_id = (orbi->fwdev->dst << 16) | (orbi->orb_hi & 0xffff);
1059e9e688e2SHidetoshi Shimokawa #else
1060e9e688e2SHidetoshi Shimokawa 	atio->init_id = orbi->fwdev->dst;
1061e9e688e2SHidetoshi Shimokawa #endif
1062e9e688e2SHidetoshi Shimokawa 	atio->ccb_h.flags = CAM_TAG_ACTION_VALID;
1063e9e688e2SHidetoshi Shimokawa 	bytes = (char *)&orb[5];
1064e9e688e2SHidetoshi Shimokawa 	if (debug)
1065e9e688e2SHidetoshi Shimokawa 		printf("%s: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
1066e9e688e2SHidetoshi Shimokawa 		    __FUNCTION__,
1067e9e688e2SHidetoshi Shimokawa 		    bytes[0], bytes[1], bytes[2], bytes[3], bytes[4],
1068e9e688e2SHidetoshi Shimokawa 		    bytes[5], bytes[6], bytes[7], bytes[8], bytes[9]);
1069e9e688e2SHidetoshi Shimokawa 	switch (bytes[0] >> 5) {
1070e9e688e2SHidetoshi Shimokawa 	case 0:
1071e9e688e2SHidetoshi Shimokawa 		atio->cdb_len = 6;
1072e9e688e2SHidetoshi Shimokawa 		break;
1073e9e688e2SHidetoshi Shimokawa 	case 1:
1074e9e688e2SHidetoshi Shimokawa 	case 2:
1075e9e688e2SHidetoshi Shimokawa 		atio->cdb_len = 10;
1076e9e688e2SHidetoshi Shimokawa 		break;
1077e9e688e2SHidetoshi Shimokawa 	case 4:
1078e9e688e2SHidetoshi Shimokawa 		atio->cdb_len = 16;
1079e9e688e2SHidetoshi Shimokawa 		break;
1080e9e688e2SHidetoshi Shimokawa 	case 5:
1081e9e688e2SHidetoshi Shimokawa 		atio->cdb_len = 12;
1082e9e688e2SHidetoshi Shimokawa 		break;
1083e9e688e2SHidetoshi Shimokawa 	case 3:
1084e9e688e2SHidetoshi Shimokawa 	default:
1085e9e688e2SHidetoshi Shimokawa 		/* Only copy the opcode. */
1086e9e688e2SHidetoshi Shimokawa 		atio->cdb_len = 1;
1087e9e688e2SHidetoshi Shimokawa 		printf("Reserved or VU command code type encountered\n");
1088e9e688e2SHidetoshi Shimokawa 		break;
1089e9e688e2SHidetoshi Shimokawa 	}
1090e9e688e2SHidetoshi Shimokawa 
1091e9e688e2SHidetoshi Shimokawa 	memcpy(atio->cdb_io.cdb_bytes, bytes, atio->cdb_len);
1092e9e688e2SHidetoshi Shimokawa 
1093e9e688e2SHidetoshi Shimokawa 	atio->ccb_h.status |= CAM_CDB_RECVD;
1094e9e688e2SHidetoshi Shimokawa 
1095e9e688e2SHidetoshi Shimokawa 	/* next ORB */
1096e9e688e2SHidetoshi Shimokawa 	if ((orb[0] & (1<<31)) == 0) {
1097e9e688e2SHidetoshi Shimokawa 		if (debug)
1098e9e688e2SHidetoshi Shimokawa 			printf("%s: fetch next orb\n", __FUNCTION__);
1099e9e688e2SHidetoshi Shimokawa 		orbi->status.src = SRC_NEXT_EXISTS;
1100e9e688e2SHidetoshi Shimokawa 		sbp_targ_fetch_orb(orbi->sc, orbi->fwdev,
1101e9e688e2SHidetoshi Shimokawa 		    orb[0], orb[1], orbi->lstate, FETCH_CMD);
1102e9e688e2SHidetoshi Shimokawa 	} else {
1103e9e688e2SHidetoshi Shimokawa 		orbi->status.src = SRC_NO_NEXT;
1104e9e688e2SHidetoshi Shimokawa 		orbi->lstate->flags &= ~LINK_ACTIVE;
1105e9e688e2SHidetoshi Shimokawa 	}
1106e9e688e2SHidetoshi Shimokawa 
1107e9e688e2SHidetoshi Shimokawa 	orbi->data_hi = orb[2];
1108e9e688e2SHidetoshi Shimokawa 	orbi->data_lo = orb[3];
1109e9e688e2SHidetoshi Shimokawa 	orbi->orb4 = *orb4;
1110e9e688e2SHidetoshi Shimokawa 
1111e9e688e2SHidetoshi Shimokawa 	xpt_done((union ccb*)atio);
1112e9e688e2SHidetoshi Shimokawa done0:
1113e9e688e2SHidetoshi Shimokawa 	fw_xfer_free(xfer);
1114e9e688e2SHidetoshi Shimokawa 	return;
1115e9e688e2SHidetoshi Shimokawa }
1116e9e688e2SHidetoshi Shimokawa 
1117e9e688e2SHidetoshi Shimokawa static void
1118e9e688e2SHidetoshi Shimokawa sbp_targ_mgm_handler(struct fw_xfer *xfer)
1119e9e688e2SHidetoshi Shimokawa {
1120e9e688e2SHidetoshi Shimokawa 	struct sbp_targ_lstate *lstate;
1121e9e688e2SHidetoshi Shimokawa 	struct fw_pkt *fp;
1122e9e688e2SHidetoshi Shimokawa 	u_int32_t *orb;
1123e9e688e2SHidetoshi Shimokawa 	struct morb4 *orb4;
1124e9e688e2SHidetoshi Shimokawa 	struct orb_info *orbi;
1125e9e688e2SHidetoshi Shimokawa 	int i;
1126e9e688e2SHidetoshi Shimokawa 
1127e9e688e2SHidetoshi Shimokawa 	orbi = (struct orb_info *)xfer->sc;
1128e9e688e2SHidetoshi Shimokawa 	if (xfer->resp != 0) {
1129e9e688e2SHidetoshi Shimokawa 		printf("%s: xfer->resp != 0\n", __FUNCTION__);
1130e9e688e2SHidetoshi Shimokawa 		orbi->status.resp = SBP_TRANS_FAIL;
1131e9e688e2SHidetoshi Shimokawa 		orbi->status.status = htonl(OBJ_ORB | SBE_TIMEOUT /*XXX*/);
1132e9e688e2SHidetoshi Shimokawa 		orbi->status.dead = 1;
1133e9e688e2SHidetoshi Shimokawa 		orbi->status.len = 1;
1134e9e688e2SHidetoshi Shimokawa 		sbp_targ_abort(STAILQ_NEXT(orbi, link));
1135e9e688e2SHidetoshi Shimokawa 
1136e9e688e2SHidetoshi Shimokawa 		sbp_targ_status_FIFO(orbi,
1137e9e688e2SHidetoshi Shimokawa 		    orbi->lstate->fifo_hi, orbi->lstate->fifo_lo, /*dequeue*/0);
1138e9e688e2SHidetoshi Shimokawa 		fw_xfer_free(xfer);
1139e9e688e2SHidetoshi Shimokawa 		return;
1140e9e688e2SHidetoshi Shimokawa 	}
1141e9e688e2SHidetoshi Shimokawa 	fp = &xfer->recv.hdr;
1142e9e688e2SHidetoshi Shimokawa 
1143e9e688e2SHidetoshi Shimokawa 	orb = orbi->orb;
1144e9e688e2SHidetoshi Shimokawa 	/* swap payload */
1145e9e688e2SHidetoshi Shimokawa 	for (i = 0; i < 8; i ++) {
1146e9e688e2SHidetoshi Shimokawa 		orb[i] = ntohl(orb[i]);
1147e9e688e2SHidetoshi Shimokawa 	}
1148e9e688e2SHidetoshi Shimokawa 	orb4 = (struct morb4 *)&orb[4];
1149e9e688e2SHidetoshi Shimokawa 	if (debug)
1150e9e688e2SHidetoshi Shimokawa 		printf("%s: %s\n", __FUNCTION__, orb_fun_name[orb4->fun]);
1151e9e688e2SHidetoshi Shimokawa 
1152e9e688e2SHidetoshi Shimokawa 	orbi->status.src = SRC_NO_NEXT;
1153e9e688e2SHidetoshi Shimokawa 
1154e9e688e2SHidetoshi Shimokawa 	switch (orb4->fun << 16) {
1155e9e688e2SHidetoshi Shimokawa 	case ORB_FUN_LGI:
1156e9e688e2SHidetoshi Shimokawa 	{
1157e9e688e2SHidetoshi Shimokawa 
1158e9e688e2SHidetoshi Shimokawa 		if (orb4->id >= MAX_LUN || orbi->sc->lstate[orb4->id] == NULL) {
1159e9e688e2SHidetoshi Shimokawa 			/* error */
1160e9e688e2SHidetoshi Shimokawa 			orbi->status.dead = 1;
1161e9e688e2SHidetoshi Shimokawa 			orbi->status.status = STATUS_ACCESS_DENY;
1162e9e688e2SHidetoshi Shimokawa 			orbi->status.len = 1;
1163e9e688e2SHidetoshi Shimokawa 			sbp_targ_status_FIFO(orbi, orb[6], orb[7],
1164e9e688e2SHidetoshi Shimokawa 			    /*dequeue*/0);
1165e9e688e2SHidetoshi Shimokawa 			break;
1166e9e688e2SHidetoshi Shimokawa 		}
1167e9e688e2SHidetoshi Shimokawa 		/* XXX check exclusive login */
1168e9e688e2SHidetoshi Shimokawa 		lstate = orbi->sc->lstate[orb4->id];
1169e9e688e2SHidetoshi Shimokawa 		lstate->fifo_hi = orb[6];
1170e9e688e2SHidetoshi Shimokawa 		lstate->fifo_lo = orb[7];
1171e9e688e2SHidetoshi Shimokawa 		lstate->login_id = 0; /* XXX random number? */
1172e9e688e2SHidetoshi Shimokawa 		lstate->lun = orb4->id;
1173e9e688e2SHidetoshi Shimokawa 		lstate->loginres.len = htons(sizeof(u_int32_t) * 4);
1174e9e688e2SHidetoshi Shimokawa 		lstate->loginres.id = htons(lstate->login_id);
1175e9e688e2SHidetoshi Shimokawa 		lstate->loginres.cmd_hi = htons(SBP_TARG_BIND_HI);
1176e9e688e2SHidetoshi Shimokawa 		lstate->loginres.cmd_lo = htonl(SBP_TARG_BIND_LO(orb4->id));
1177e9e688e2SHidetoshi Shimokawa 		lstate->loginres.recon_hold = htons(0); /* XXX */
1178e9e688e2SHidetoshi Shimokawa 		fwmem_write_block(orbi->fwdev, NULL, /*spd*/2, orb[2], orb[3],
1179e9e688e2SHidetoshi Shimokawa 		    sizeof(struct sbp_login_res), (void *)&lstate->loginres,
1180e9e688e2SHidetoshi Shimokawa 		    fw_asy_callback_free);
1181e9e688e2SHidetoshi Shimokawa 		break;
1182e9e688e2SHidetoshi Shimokawa 	}
1183e9e688e2SHidetoshi Shimokawa 	case ORB_FUN_RCN:
1184e9e688e2SHidetoshi Shimokawa 		orbi->status.dead = 1;
1185e9e688e2SHidetoshi Shimokawa 		orbi->status.status = STATUS_ACCESS_DENY;
1186e9e688e2SHidetoshi Shimokawa 		break;
1187e9e688e2SHidetoshi Shimokawa 	default:
1188e9e688e2SHidetoshi Shimokawa 		printf("%s: %s not implemented yet\n",
1189e9e688e2SHidetoshi Shimokawa 		    __FUNCTION__, orb_fun_name[orb4->fun]);
1190e9e688e2SHidetoshi Shimokawa 		break;
1191e9e688e2SHidetoshi Shimokawa 	}
1192e9e688e2SHidetoshi Shimokawa 	orbi->status.len = 1;
1193e9e688e2SHidetoshi Shimokawa 	sbp_targ_status_FIFO(orbi, orb[6], orb[7], /*dequeue*/0);
1194e9e688e2SHidetoshi Shimokawa 	fw_xfer_free(xfer);
1195e9e688e2SHidetoshi Shimokawa 	return;
1196e9e688e2SHidetoshi Shimokawa }
1197e9e688e2SHidetoshi Shimokawa 
1198e9e688e2SHidetoshi Shimokawa static void
1199e9e688e2SHidetoshi Shimokawa sbp_targ_pointer_handler(struct fw_xfer *xfer)
1200e9e688e2SHidetoshi Shimokawa {
1201e9e688e2SHidetoshi Shimokawa 	struct orb_info *orbi;
1202e9e688e2SHidetoshi Shimokawa 	u_int32_t orb0, orb1;
1203e9e688e2SHidetoshi Shimokawa 
1204e9e688e2SHidetoshi Shimokawa 	orbi = (struct orb_info *)xfer->sc;
1205e9e688e2SHidetoshi Shimokawa 	if (xfer->resp != 0) {
1206e9e688e2SHidetoshi Shimokawa 		printf("%s: xfer->resp != 0\n", __FUNCTION__);
1207e9e688e2SHidetoshi Shimokawa 		goto done;
1208e9e688e2SHidetoshi Shimokawa 	}
1209e9e688e2SHidetoshi Shimokawa 
1210e9e688e2SHidetoshi Shimokawa 	orb0 = ntohl(orbi->orb[0]);
1211e9e688e2SHidetoshi Shimokawa 	orb1 = ntohl(orbi->orb[1]);
1212e9e688e2SHidetoshi Shimokawa 	if ((orb0 & (1 << 31)) != 0) {
1213e9e688e2SHidetoshi Shimokawa 		printf("%s: invalid pointer\n", __FUNCTION__);
1214e9e688e2SHidetoshi Shimokawa 		goto done;
1215e9e688e2SHidetoshi Shimokawa 	}
1216e9e688e2SHidetoshi Shimokawa 	sbp_targ_fetch_orb(orbi->lstate->sc, orbi->fwdev,
1217e9e688e2SHidetoshi Shimokawa 	    (u_int16_t)orb0, orb1, orbi->lstate, FETCH_CMD);
1218e9e688e2SHidetoshi Shimokawa done:
1219e9e688e2SHidetoshi Shimokawa 	free(orbi, M_SBP_TARG);
1220e9e688e2SHidetoshi Shimokawa 	fw_xfer_free(xfer);
1221e9e688e2SHidetoshi Shimokawa 	return;
1222e9e688e2SHidetoshi Shimokawa }
1223e9e688e2SHidetoshi Shimokawa 
1224e9e688e2SHidetoshi Shimokawa static void
1225e9e688e2SHidetoshi Shimokawa sbp_targ_fetch_orb(struct sbp_targ_softc *sc, struct fw_device *fwdev,
1226e9e688e2SHidetoshi Shimokawa     u_int16_t orb_hi, u_int32_t orb_lo, struct sbp_targ_lstate *lstate,
1227e9e688e2SHidetoshi Shimokawa     int mode)
1228e9e688e2SHidetoshi Shimokawa {
1229e9e688e2SHidetoshi Shimokawa 	struct orb_info *orbi;
1230e9e688e2SHidetoshi Shimokawa 
1231e9e688e2SHidetoshi Shimokawa 	if (debug)
1232e9e688e2SHidetoshi Shimokawa 		printf("%s: fetch orb %04x:%08x\n", __FUNCTION__, orb_hi, orb_lo);
1233e9e688e2SHidetoshi Shimokawa 	orbi = malloc(sizeof(struct orb_info), M_SBP_TARG, M_NOWAIT | M_ZERO);
1234e9e688e2SHidetoshi Shimokawa 	if (orbi == NULL) {
1235e9e688e2SHidetoshi Shimokawa 		printf("%s: malloc failed\n", __FUNCTION__);
1236e9e688e2SHidetoshi Shimokawa 		return;
1237e9e688e2SHidetoshi Shimokawa 	}
1238e9e688e2SHidetoshi Shimokawa 	orbi->sc = sc;
1239e9e688e2SHidetoshi Shimokawa 	orbi->fwdev = fwdev;
1240e9e688e2SHidetoshi Shimokawa 	orbi->lstate = lstate;
1241e9e688e2SHidetoshi Shimokawa 	orbi->orb_hi = orb_hi;
1242e9e688e2SHidetoshi Shimokawa 	orbi->orb_lo = orb_lo;
1243e9e688e2SHidetoshi Shimokawa 	orbi->status.orb_hi = htons(orb_hi);
1244e9e688e2SHidetoshi Shimokawa 	orbi->status.orb_lo = htonl(orb_lo);
1245e9e688e2SHidetoshi Shimokawa 
1246e9e688e2SHidetoshi Shimokawa 	switch (mode) {
1247e9e688e2SHidetoshi Shimokawa 	case FETCH_MGM:
1248e9e688e2SHidetoshi Shimokawa 		fwmem_read_block(fwdev, (void *)orbi, /*spd*/2, orb_hi, orb_lo,
1249e9e688e2SHidetoshi Shimokawa 		    sizeof(u_int32_t) * 8, &orbi->orb[0],
1250e9e688e2SHidetoshi Shimokawa 		    sbp_targ_mgm_handler);
1251e9e688e2SHidetoshi Shimokawa 		break;
1252e9e688e2SHidetoshi Shimokawa 	case FETCH_CMD:
1253e9e688e2SHidetoshi Shimokawa 		orbi->state = ORBI_STATUS_FETCH;
1254e9e688e2SHidetoshi Shimokawa 		lstate->last_hi = orb_hi;
1255e9e688e2SHidetoshi Shimokawa 		lstate->last_lo = orb_lo;
1256e9e688e2SHidetoshi Shimokawa 		lstate->flags |= LINK_ACTIVE;
1257e9e688e2SHidetoshi Shimokawa 		/* dequeue */
1258e9e688e2SHidetoshi Shimokawa 		orbi->atio = (struct ccb_accept_tio *)
1259e9e688e2SHidetoshi Shimokawa 		    SLIST_FIRST(&lstate->accept_tios);
1260e9e688e2SHidetoshi Shimokawa 		if (orbi->atio == NULL) {
1261e9e688e2SHidetoshi Shimokawa 			printf("%s: no free atio\n", __FUNCTION__);
1262e9e688e2SHidetoshi Shimokawa 			lstate->flags |= ATIO_STARVED;
1263e9e688e2SHidetoshi Shimokawa 			lstate->fwdev = fwdev;
1264e9e688e2SHidetoshi Shimokawa 			break;
1265e9e688e2SHidetoshi Shimokawa 		}
1266e9e688e2SHidetoshi Shimokawa 		SLIST_REMOVE_HEAD(&lstate->accept_tios, sim_links.sle);
1267e9e688e2SHidetoshi Shimokawa 		fwmem_read_block(fwdev, (void *)orbi, /*spd*/2, orb_hi, orb_lo,
1268e9e688e2SHidetoshi Shimokawa 		    sizeof(u_int32_t) * 8, &orbi->orb[0],
1269e9e688e2SHidetoshi Shimokawa 		    sbp_targ_cmd_handler);
1270e9e688e2SHidetoshi Shimokawa 		STAILQ_INSERT_TAIL(&lstate->orbs, orbi, link);
1271e9e688e2SHidetoshi Shimokawa 		break;
1272e9e688e2SHidetoshi Shimokawa 	case FETCH_POINTER:
1273e9e688e2SHidetoshi Shimokawa 		orbi->state = ORBI_STATUS_POINTER;
1274e9e688e2SHidetoshi Shimokawa 		fwmem_read_block(fwdev, (void *)orbi, /*spd*/2, orb_hi, orb_lo,
1275e9e688e2SHidetoshi Shimokawa 		    sizeof(u_int32_t) * 2, &orbi->orb[0],
1276e9e688e2SHidetoshi Shimokawa 		    sbp_targ_pointer_handler);
1277e9e688e2SHidetoshi Shimokawa 		break;
1278e9e688e2SHidetoshi Shimokawa 	default:
1279e9e688e2SHidetoshi Shimokawa 		printf("%s: invalid mode %d\n", __FUNCTION__, mode);
1280e9e688e2SHidetoshi Shimokawa 	}
1281e9e688e2SHidetoshi Shimokawa }
1282e9e688e2SHidetoshi Shimokawa 
1283e9e688e2SHidetoshi Shimokawa static void
1284e9e688e2SHidetoshi Shimokawa sbp_targ_resp_callback(struct fw_xfer *xfer)
1285e9e688e2SHidetoshi Shimokawa {
1286e9e688e2SHidetoshi Shimokawa 	struct sbp_targ_softc *sc;
1287e9e688e2SHidetoshi Shimokawa 	int s;
1288e9e688e2SHidetoshi Shimokawa 
1289e9e688e2SHidetoshi Shimokawa 	if (debug)
1290e9e688e2SHidetoshi Shimokawa 		printf("%s: xfer=%p\n", __FUNCTION__, xfer);
1291e9e688e2SHidetoshi Shimokawa 	sc = (struct sbp_targ_softc *)xfer->sc;
1292e9e688e2SHidetoshi Shimokawa 	fw_xfer_unload(xfer);
1293e9e688e2SHidetoshi Shimokawa 	xfer->recv.pay_len = SBP_TARG_RECV_LEN;
1294e9e688e2SHidetoshi Shimokawa 	xfer->act.hand = sbp_targ_recv;
1295e9e688e2SHidetoshi Shimokawa 	s = splfw();
1296e9e688e2SHidetoshi Shimokawa 	STAILQ_INSERT_TAIL(&sc->fwb.xferlist, xfer, link);
1297e9e688e2SHidetoshi Shimokawa 	splx(s);
1298e9e688e2SHidetoshi Shimokawa }
1299e9e688e2SHidetoshi Shimokawa 
1300e9e688e2SHidetoshi Shimokawa static int
1301e9e688e2SHidetoshi Shimokawa sbp_targ_cmd(struct fw_xfer *xfer, struct fw_device *fwdev, int lun, int reg)
1302e9e688e2SHidetoshi Shimokawa {
1303e9e688e2SHidetoshi Shimokawa 	struct sbp_targ_lstate *lstate;
1304e9e688e2SHidetoshi Shimokawa 	struct sbp_targ_softc *sc;
1305e9e688e2SHidetoshi Shimokawa 	int rtcode = 0;
1306e9e688e2SHidetoshi Shimokawa 
1307e9e688e2SHidetoshi Shimokawa 	if (lun < 0 || lun >= MAX_LUN)
1308e9e688e2SHidetoshi Shimokawa 		return(RESP_ADDRESS_ERROR);
1309e9e688e2SHidetoshi Shimokawa 
1310e9e688e2SHidetoshi Shimokawa 	sc = (struct sbp_targ_softc *)xfer->sc;
1311e9e688e2SHidetoshi Shimokawa 	lstate = sc->lstate[lun];
1312e9e688e2SHidetoshi Shimokawa 	if (lstate == NULL)
1313e9e688e2SHidetoshi Shimokawa 		return(RESP_ADDRESS_ERROR);
1314e9e688e2SHidetoshi Shimokawa 
1315e9e688e2SHidetoshi Shimokawa 	/* XXX check logined? */
1316e9e688e2SHidetoshi Shimokawa 	switch (reg) {
1317e9e688e2SHidetoshi Shimokawa 	case 0x08:	/* ORB_POINTER */
1318e9e688e2SHidetoshi Shimokawa 		if (debug)
1319e9e688e2SHidetoshi Shimokawa 			printf("%s: ORB_POINTER\n", __FUNCTION__);
1320e9e688e2SHidetoshi Shimokawa 		sbp_targ_fetch_orb(lstate->sc, fwdev,
1321e9e688e2SHidetoshi Shimokawa 		    ntohl(xfer->recv.payload[0]),
1322e9e688e2SHidetoshi Shimokawa 		    ntohl(xfer->recv.payload[1]),
1323e9e688e2SHidetoshi Shimokawa 		    lstate, FETCH_CMD);
1324e9e688e2SHidetoshi Shimokawa 		break;
1325e9e688e2SHidetoshi Shimokawa 	case 0x04:	/* AGENT_RESET */
1326e9e688e2SHidetoshi Shimokawa 		if (debug)
1327e9e688e2SHidetoshi Shimokawa 			printf("%s: AGENT RESET\n", __FUNCTION__);
1328e9e688e2SHidetoshi Shimokawa 		lstate->last_hi = 0xffff;
1329e9e688e2SHidetoshi Shimokawa 		lstate->last_lo = 0xffffffff;
1330e9e688e2SHidetoshi Shimokawa 		sbp_targ_abort(STAILQ_FIRST(&lstate->orbs));
1331e9e688e2SHidetoshi Shimokawa 		break;
1332e9e688e2SHidetoshi Shimokawa 	case 0x10:	/* DOORBELL */
1333e9e688e2SHidetoshi Shimokawa 		if (debug)
1334e9e688e2SHidetoshi Shimokawa 			printf("%s: DOORBELL\n", __FUNCTION__);
1335e9e688e2SHidetoshi Shimokawa 		if (lstate->last_hi == 0xffff &&
1336e9e688e2SHidetoshi Shimokawa 		    lstate->last_lo == 0xffffffff) {
1337e9e688e2SHidetoshi Shimokawa 			printf("%s: no previous pointer(DOORBELL)\n",
1338e9e688e2SHidetoshi Shimokawa 			    __FUNCTION__);
1339e9e688e2SHidetoshi Shimokawa 			break;
1340e9e688e2SHidetoshi Shimokawa 		}
1341e9e688e2SHidetoshi Shimokawa 		if ((lstate->flags & LINK_ACTIVE) != 0) {
1342e9e688e2SHidetoshi Shimokawa 			if (debug)
1343e9e688e2SHidetoshi Shimokawa 				printf("link active (DOORBELL)\n");
1344e9e688e2SHidetoshi Shimokawa 			break;
1345e9e688e2SHidetoshi Shimokawa 		}
1346e9e688e2SHidetoshi Shimokawa 		lstate->flags |= LINK_ACTIVE;
1347e9e688e2SHidetoshi Shimokawa 		sbp_targ_fetch_orb(lstate->sc, fwdev,
1348e9e688e2SHidetoshi Shimokawa 		    lstate->last_hi, lstate->last_lo,
1349e9e688e2SHidetoshi Shimokawa 		    lstate, FETCH_POINTER);
1350e9e688e2SHidetoshi Shimokawa 		break;
1351e9e688e2SHidetoshi Shimokawa 	case 0x00:	/* AGENT_STATE */
1352e9e688e2SHidetoshi Shimokawa 		printf("%s: AGENT_STATE (ignore)\n", __FUNCTION__);
1353e9e688e2SHidetoshi Shimokawa 		break;
1354e9e688e2SHidetoshi Shimokawa 	case 0x14:	/* UNSOLICITED_STATE_ENABLE */
1355e9e688e2SHidetoshi Shimokawa 		printf("%s: UNSOLICITED_STATE_ENABLE (ignore)\n", __FUNCTION__);
1356e9e688e2SHidetoshi Shimokawa 		break;
1357e9e688e2SHidetoshi Shimokawa 	default:
1358e9e688e2SHidetoshi Shimokawa 		printf("%s: invalid register %d\n", __FUNCTION__, reg);
1359e9e688e2SHidetoshi Shimokawa 		rtcode = RESP_ADDRESS_ERROR;
1360e9e688e2SHidetoshi Shimokawa 	}
1361e9e688e2SHidetoshi Shimokawa 
1362e9e688e2SHidetoshi Shimokawa 	return (rtcode);
1363e9e688e2SHidetoshi Shimokawa }
1364e9e688e2SHidetoshi Shimokawa 
1365e9e688e2SHidetoshi Shimokawa static int
1366e9e688e2SHidetoshi Shimokawa sbp_targ_mgm(struct fw_xfer *xfer, struct fw_device *fwdev)
1367e9e688e2SHidetoshi Shimokawa {
1368e9e688e2SHidetoshi Shimokawa 	struct sbp_targ_softc *sc;
1369e9e688e2SHidetoshi Shimokawa 	struct fw_pkt *fp;
1370e9e688e2SHidetoshi Shimokawa 
1371e9e688e2SHidetoshi Shimokawa 	sc = (struct sbp_targ_softc *)xfer->sc;
1372e9e688e2SHidetoshi Shimokawa 
1373e9e688e2SHidetoshi Shimokawa 	fp = &xfer->recv.hdr;
1374e9e688e2SHidetoshi Shimokawa 	if (fp->mode.wreqb.tcode != FWTCODE_WREQB){
1375e9e688e2SHidetoshi Shimokawa 		printf("%s: tcode = %d\n", __FUNCTION__, fp->mode.wreqb.tcode);
1376e9e688e2SHidetoshi Shimokawa 		return(RESP_TYPE_ERROR);
1377e9e688e2SHidetoshi Shimokawa         }
1378e9e688e2SHidetoshi Shimokawa 
1379e9e688e2SHidetoshi Shimokawa 	sbp_targ_fetch_orb(sc, fwdev,
1380e9e688e2SHidetoshi Shimokawa 	    ntohl(xfer->recv.payload[0]),
1381e9e688e2SHidetoshi Shimokawa 	    ntohl(xfer->recv.payload[1]),
1382e9e688e2SHidetoshi Shimokawa 	    NULL, FETCH_MGM);
1383e9e688e2SHidetoshi Shimokawa 
1384e9e688e2SHidetoshi Shimokawa 	return(0);
1385e9e688e2SHidetoshi Shimokawa }
1386e9e688e2SHidetoshi Shimokawa 
1387e9e688e2SHidetoshi Shimokawa 
1388e9e688e2SHidetoshi Shimokawa static void
1389e9e688e2SHidetoshi Shimokawa sbp_targ_recv(struct fw_xfer *xfer)
1390e9e688e2SHidetoshi Shimokawa {
1391e9e688e2SHidetoshi Shimokawa 	struct fw_pkt *fp, *sfp;
1392e9e688e2SHidetoshi Shimokawa 	struct fw_device *fwdev;
1393e9e688e2SHidetoshi Shimokawa 	u_int32_t lo;
1394e9e688e2SHidetoshi Shimokawa 	int s, rtcode;
1395e9e688e2SHidetoshi Shimokawa 	struct sbp_targ_softc *sc;
1396e9e688e2SHidetoshi Shimokawa 
1397e9e688e2SHidetoshi Shimokawa 	s = splfw();
1398e9e688e2SHidetoshi Shimokawa 	sc = (struct sbp_targ_softc *)xfer->sc;
1399e9e688e2SHidetoshi Shimokawa 	fp = &xfer->recv.hdr;
1400e9e688e2SHidetoshi Shimokawa 	fwdev = fw_noderesolve_nodeid(sc->fd.fc, fp->mode.wreqb.src & 0x3f);
1401e9e688e2SHidetoshi Shimokawa 	if (fwdev == NULL) {
1402e9e688e2SHidetoshi Shimokawa 		printf("%s: cannot resolve nodeid=%d\n",
1403e9e688e2SHidetoshi Shimokawa 		    __FUNCTION__, fp->mode.wreqb.src & 0x3f);
1404e9e688e2SHidetoshi Shimokawa 		rtcode = RESP_TYPE_ERROR; /* XXX */
1405e9e688e2SHidetoshi Shimokawa 		goto done;
1406e9e688e2SHidetoshi Shimokawa 	}
1407e9e688e2SHidetoshi Shimokawa 	lo = fp->mode.wreqb.dest_lo;
1408e9e688e2SHidetoshi Shimokawa 	if (lo == SBP_TARG_BIND_LO(-1))
1409e9e688e2SHidetoshi Shimokawa 		rtcode = sbp_targ_mgm(xfer, fwdev);
1410e9e688e2SHidetoshi Shimokawa 	else if (lo >= SBP_TARG_BIND_LO(0))
1411e9e688e2SHidetoshi Shimokawa 		rtcode = sbp_targ_cmd(xfer, fwdev, SBP_TARG_LUN(lo), lo % 0x20);
1412e9e688e2SHidetoshi Shimokawa 	else
1413e9e688e2SHidetoshi Shimokawa 		rtcode = RESP_ADDRESS_ERROR;
1414e9e688e2SHidetoshi Shimokawa 
1415e9e688e2SHidetoshi Shimokawa done:
1416e9e688e2SHidetoshi Shimokawa 	if (rtcode != 0)
1417e9e688e2SHidetoshi Shimokawa 		printf("%s: rtcode = %d\n", __FUNCTION__, rtcode);
1418e9e688e2SHidetoshi Shimokawa 	sfp = &xfer->send.hdr;
1419e9e688e2SHidetoshi Shimokawa 	xfer->send.spd = 2; /* XXX */
1420e9e688e2SHidetoshi Shimokawa 	xfer->act.hand = sbp_targ_resp_callback;
1421e9e688e2SHidetoshi Shimokawa 	xfer->retry_req = fw_asybusy;
1422e9e688e2SHidetoshi Shimokawa 	sfp->mode.wres.dst = fp->mode.wreqb.src;
1423e9e688e2SHidetoshi Shimokawa 	sfp->mode.wres.tlrt = fp->mode.wreqb.tlrt;
1424e9e688e2SHidetoshi Shimokawa 	sfp->mode.wres.tcode = FWTCODE_WRES;
1425e9e688e2SHidetoshi Shimokawa 	sfp->mode.wres.rtcode = rtcode;
1426e9e688e2SHidetoshi Shimokawa 	sfp->mode.wres.pri = 0;
1427e9e688e2SHidetoshi Shimokawa 
1428e9e688e2SHidetoshi Shimokawa 	fw_asyreq(xfer->fc, -1, xfer);
1429e9e688e2SHidetoshi Shimokawa 	splx(s);
1430e9e688e2SHidetoshi Shimokawa }
1431e9e688e2SHidetoshi Shimokawa 
1432e9e688e2SHidetoshi Shimokawa static int
1433e9e688e2SHidetoshi Shimokawa sbp_targ_attach(device_t dev)
1434e9e688e2SHidetoshi Shimokawa {
1435e9e688e2SHidetoshi Shimokawa 	struct sbp_targ_softc *sc;
1436e9e688e2SHidetoshi Shimokawa 	struct cam_devq *devq;
1437e9e688e2SHidetoshi Shimokawa 	struct fw_xfer *xfer;
1438e9e688e2SHidetoshi Shimokawa 	int i;
1439e9e688e2SHidetoshi Shimokawa 
1440e9e688e2SHidetoshi Shimokawa         sc = (struct sbp_targ_softc *) device_get_softc(dev);
1441e9e688e2SHidetoshi Shimokawa 	bzero((void *)sc, sizeof(struct sbp_targ_softc));
1442e9e688e2SHidetoshi Shimokawa 
1443e9e688e2SHidetoshi Shimokawa 	sc->fd.fc = device_get_ivars(dev);
1444e9e688e2SHidetoshi Shimokawa 	sc->fd.dev = dev;
1445e9e688e2SHidetoshi Shimokawa 	sc->fd.post_explore = NULL;
1446e9e688e2SHidetoshi Shimokawa 	sc->fd.post_busreset = (void *) sbp_targ_post_busreset;
1447e9e688e2SHidetoshi Shimokawa 
1448e9e688e2SHidetoshi Shimokawa         devq = cam_simq_alloc(/*maxopenings*/1);
1449e9e688e2SHidetoshi Shimokawa 	if (devq == NULL)
1450e9e688e2SHidetoshi Shimokawa 		return (ENXIO);
1451e9e688e2SHidetoshi Shimokawa 
1452e9e688e2SHidetoshi Shimokawa 	sc->sim = cam_sim_alloc(sbp_targ_action, sbp_targ_poll,
1453e9e688e2SHidetoshi Shimokawa 	    "sbp_targ", sc, device_get_unit(dev),
1454e9e688e2SHidetoshi Shimokawa 	    /*untagged*/ 1, /*tagged*/ 1, devq);
1455e9e688e2SHidetoshi Shimokawa 	if (sc->sim == NULL) {
1456e9e688e2SHidetoshi Shimokawa 		cam_simq_free(devq);
1457e9e688e2SHidetoshi Shimokawa 		return (ENXIO);
1458e9e688e2SHidetoshi Shimokawa 	}
1459e9e688e2SHidetoshi Shimokawa 
1460e9e688e2SHidetoshi Shimokawa 	if (xpt_bus_register(sc->sim, /*bus*/0) != CAM_SUCCESS)
1461e9e688e2SHidetoshi Shimokawa 		goto fail;
1462e9e688e2SHidetoshi Shimokawa 
1463e9e688e2SHidetoshi Shimokawa 	if (xpt_create_path(&sc->path, /*periph*/ NULL, cam_sim_path(sc->sim),
1464e9e688e2SHidetoshi Shimokawa 	    CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
1465e9e688e2SHidetoshi Shimokawa 		xpt_bus_deregister(cam_sim_path(sc->sim));
1466e9e688e2SHidetoshi Shimokawa 		goto fail;
1467e9e688e2SHidetoshi Shimokawa 	}
1468e9e688e2SHidetoshi Shimokawa 
1469e9e688e2SHidetoshi Shimokawa 	sc->fwb.start = SBP_TARG_BIND_START;
1470e9e688e2SHidetoshi Shimokawa 	sc->fwb.end = SBP_TARG_BIND_END;
1471e9e688e2SHidetoshi Shimokawa 	sc->fwb.act_type = FWACT_XFER;
1472e9e688e2SHidetoshi Shimokawa 
1473e9e688e2SHidetoshi Shimokawa 	/* pre-allocate xfer */
1474e9e688e2SHidetoshi Shimokawa 	STAILQ_INIT(&sc->fwb.xferlist);
1475e9e688e2SHidetoshi Shimokawa 	for (i = 0; i < MAX_LUN /* XXX */; i ++) {
1476e9e688e2SHidetoshi Shimokawa 		xfer = fw_xfer_alloc_buf(M_SBP_TARG,
1477e9e688e2SHidetoshi Shimokawa 			/* send */ 0,
1478e9e688e2SHidetoshi Shimokawa 			/* recv */ SBP_TARG_RECV_LEN);
1479e9e688e2SHidetoshi Shimokawa 		xfer->act.hand = sbp_targ_recv;
1480e9e688e2SHidetoshi Shimokawa 		xfer->fc = sc->fd.fc;
1481e9e688e2SHidetoshi Shimokawa 		xfer->sc = (caddr_t)sc;
1482e9e688e2SHidetoshi Shimokawa 		STAILQ_INSERT_TAIL(&sc->fwb.xferlist, xfer, link);
1483e9e688e2SHidetoshi Shimokawa 	}
1484e9e688e2SHidetoshi Shimokawa 	fw_bindadd(sc->fd.fc, &sc->fwb);
1485e9e688e2SHidetoshi Shimokawa 	return 0;
1486e9e688e2SHidetoshi Shimokawa 
1487e9e688e2SHidetoshi Shimokawa fail:
1488e9e688e2SHidetoshi Shimokawa 	cam_sim_free(sc->sim, /*free_devq*/TRUE);
1489e9e688e2SHidetoshi Shimokawa 	return (ENXIO);
1490e9e688e2SHidetoshi Shimokawa }
1491e9e688e2SHidetoshi Shimokawa 
1492e9e688e2SHidetoshi Shimokawa static int
1493e9e688e2SHidetoshi Shimokawa sbp_targ_detach(device_t dev)
1494e9e688e2SHidetoshi Shimokawa {
1495e9e688e2SHidetoshi Shimokawa 	struct sbp_targ_softc *sc;
1496e9e688e2SHidetoshi Shimokawa 	struct sbp_targ_lstate *lstate;
1497e9e688e2SHidetoshi Shimokawa 	struct fw_xfer *xfer, *next;
1498e9e688e2SHidetoshi Shimokawa 	int i;
1499e9e688e2SHidetoshi Shimokawa 
1500e9e688e2SHidetoshi Shimokawa 	sc = (struct sbp_targ_softc *)device_get_softc(dev);
1501e9e688e2SHidetoshi Shimokawa 	sc->fd.post_busreset = NULL;
1502e9e688e2SHidetoshi Shimokawa 
1503e9e688e2SHidetoshi Shimokawa 	xpt_free_path(sc->path);
1504e9e688e2SHidetoshi Shimokawa 	xpt_bus_deregister(cam_sim_path(sc->sim));
1505e9e688e2SHidetoshi Shimokawa 	cam_sim_free(sc->sim, /*free_devq*/TRUE);
1506e9e688e2SHidetoshi Shimokawa 
1507e9e688e2SHidetoshi Shimokawa 	for (i = 0; i < MAX_LUN; i ++) {
1508e9e688e2SHidetoshi Shimokawa 		lstate = sc->lstate[i];
1509e9e688e2SHidetoshi Shimokawa 		if (lstate != NULL) {
1510e9e688e2SHidetoshi Shimokawa 			xpt_free_path(lstate->path);
1511e9e688e2SHidetoshi Shimokawa 			free(lstate, M_SBP_TARG);
1512e9e688e2SHidetoshi Shimokawa 		}
1513e9e688e2SHidetoshi Shimokawa 	}
1514e9e688e2SHidetoshi Shimokawa 	if (sc->black_hole != NULL) {
1515e9e688e2SHidetoshi Shimokawa 		xpt_free_path(sc->black_hole->path);
1516e9e688e2SHidetoshi Shimokawa 		free(sc->black_hole, M_SBP_TARG);
1517e9e688e2SHidetoshi Shimokawa 	}
1518e9e688e2SHidetoshi Shimokawa 
1519e9e688e2SHidetoshi Shimokawa 	for (xfer = STAILQ_FIRST(&sc->fwb.xferlist);
1520e9e688e2SHidetoshi Shimokawa 	    xfer != NULL; xfer = next) {
1521e9e688e2SHidetoshi Shimokawa 		next = STAILQ_NEXT(xfer, link);
1522e9e688e2SHidetoshi Shimokawa 		fw_xfer_free_buf(xfer);
1523e9e688e2SHidetoshi Shimokawa 	}
1524e9e688e2SHidetoshi Shimokawa 	STAILQ_INIT(&sc->fwb.xferlist);
1525e9e688e2SHidetoshi Shimokawa 	fw_bindremove(sc->fd.fc, &sc->fwb);
1526e9e688e2SHidetoshi Shimokawa 
1527e9e688e2SHidetoshi Shimokawa 	return 0;
1528e9e688e2SHidetoshi Shimokawa }
1529e9e688e2SHidetoshi Shimokawa 
1530e9e688e2SHidetoshi Shimokawa static devclass_t sbp_targ_devclass;
1531e9e688e2SHidetoshi Shimokawa 
1532e9e688e2SHidetoshi Shimokawa static device_method_t sbp_targ_methods[] = {
1533e9e688e2SHidetoshi Shimokawa 	/* device interface */
1534e9e688e2SHidetoshi Shimokawa 	DEVMETHOD(device_identify,	sbp_targ_identify),
1535e9e688e2SHidetoshi Shimokawa 	DEVMETHOD(device_probe,		sbp_targ_probe),
1536e9e688e2SHidetoshi Shimokawa 	DEVMETHOD(device_attach,	sbp_targ_attach),
1537e9e688e2SHidetoshi Shimokawa 	DEVMETHOD(device_detach,	sbp_targ_detach),
1538e9e688e2SHidetoshi Shimokawa 	{ 0, 0 }
1539e9e688e2SHidetoshi Shimokawa };
1540e9e688e2SHidetoshi Shimokawa 
1541e9e688e2SHidetoshi Shimokawa static driver_t sbp_targ_driver = {
1542e9e688e2SHidetoshi Shimokawa 	"sbp_targ",
1543e9e688e2SHidetoshi Shimokawa 	sbp_targ_methods,
1544e9e688e2SHidetoshi Shimokawa 	sizeof(struct sbp_targ_softc),
1545e9e688e2SHidetoshi Shimokawa };
1546e9e688e2SHidetoshi Shimokawa 
1547e9e688e2SHidetoshi Shimokawa DRIVER_MODULE(sbp_targ, firewire, sbp_targ_driver, sbp_targ_devclass, 0, 0);
1548e9e688e2SHidetoshi Shimokawa MODULE_VERSION(sbp_targ, 1);
1549e9e688e2SHidetoshi Shimokawa MODULE_DEPEND(sbp_targ, firewire, 1, 1, 1);
1550e9e688e2SHidetoshi Shimokawa MODULE_DEPEND(sbp_targ, cam, 1, 1, 1);
1551