xref: /freebsd/sys/dev/firewire/sbp_targ.c (revision 1cc052e80fd45ab48416357521ed570077c418b9)
1098ca2bdSWarner Losh /*-
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>
44*1cc052e8SKenneth D. Merry #include <sys/endian.h>
45e9e688e2SHidetoshi Shimokawa #if __FreeBSD_version < 500000
46e9e688e2SHidetoshi Shimokawa #include <sys/devicestat.h>
47e9e688e2SHidetoshi Shimokawa #endif
48e9e688e2SHidetoshi Shimokawa 
49e9e688e2SHidetoshi Shimokawa #include <sys/bus.h>
50e9e688e2SHidetoshi Shimokawa #include <machine/bus.h>
51e9e688e2SHidetoshi Shimokawa 
52e9e688e2SHidetoshi Shimokawa #include <dev/firewire/firewire.h>
53e9e688e2SHidetoshi Shimokawa #include <dev/firewire/firewirereg.h>
54e9e688e2SHidetoshi Shimokawa #include <dev/firewire/iec13213.h>
55e9e688e2SHidetoshi Shimokawa #include <dev/firewire/sbp.h>
56e9e688e2SHidetoshi Shimokawa #include <dev/firewire/fwmem.h>
57e9e688e2SHidetoshi Shimokawa 
58e9e688e2SHidetoshi Shimokawa #include <cam/cam.h>
59e9e688e2SHidetoshi Shimokawa #include <cam/cam_ccb.h>
60e9e688e2SHidetoshi Shimokawa #include <cam/cam_sim.h>
61e9e688e2SHidetoshi Shimokawa #include <cam/cam_xpt_sim.h>
62e9e688e2SHidetoshi Shimokawa #include <cam/cam_debug.h>
63e9e688e2SHidetoshi Shimokawa #include <cam/cam_periph.h>
64e9e688e2SHidetoshi Shimokawa #include <cam/scsi/scsi_all.h>
65e9e688e2SHidetoshi Shimokawa 
66a73ff510SHidetoshi Shimokawa #define SBP_TARG_RECV_LEN	8
67a73ff510SHidetoshi Shimokawa #define MAX_INITIATORS		8
68e9e688e2SHidetoshi Shimokawa #define MAX_LUN			63
69a73ff510SHidetoshi Shimokawa #define MAX_LOGINS		63
70a73ff510SHidetoshi Shimokawa #define MAX_NODES		63
71e9e688e2SHidetoshi Shimokawa /*
72e9e688e2SHidetoshi Shimokawa  * management/command block agent registers
73e9e688e2SHidetoshi Shimokawa  *
74e9e688e2SHidetoshi Shimokawa  * BASE 0xffff f001 0000 management port
75a73ff510SHidetoshi Shimokawa  * BASE 0xffff f001 0020 command port for login id 0
76a73ff510SHidetoshi Shimokawa  * BASE 0xffff f001 0040 command port for login id 1
77e9e688e2SHidetoshi Shimokawa  *
78e9e688e2SHidetoshi Shimokawa  */
79e9e688e2SHidetoshi Shimokawa #define SBP_TARG_MGM	 0x10000	/* offset from 0xffff f000 000 */
80e9e688e2SHidetoshi Shimokawa #define SBP_TARG_BIND_HI	0xffff
81e9e688e2SHidetoshi Shimokawa #define SBP_TARG_BIND_LO(l)	(0xf0000000 + SBP_TARG_MGM + 0x20 * ((l) + 1))
82e9e688e2SHidetoshi Shimokawa #define SBP_TARG_BIND_START	(((u_int64_t)SBP_TARG_BIND_HI << 32) | \
83e9e688e2SHidetoshi Shimokawa 				    SBP_TARG_BIND_LO(-1))
84e9e688e2SHidetoshi Shimokawa #define SBP_TARG_BIND_END	(((u_int64_t)SBP_TARG_BIND_HI << 32) | \
85a73ff510SHidetoshi Shimokawa 				    SBP_TARG_BIND_LO(MAX_LOGINS))
86a73ff510SHidetoshi Shimokawa #define SBP_TARG_LOGIN_ID(lo)	(((lo) - SBP_TARG_BIND_LO(0))/0x20)
87e9e688e2SHidetoshi Shimokawa 
88e9e688e2SHidetoshi Shimokawa #define FETCH_MGM	0
89e9e688e2SHidetoshi Shimokawa #define FETCH_CMD	1
90e9e688e2SHidetoshi Shimokawa #define FETCH_POINTER	2
91e9e688e2SHidetoshi Shimokawa 
92a73ff510SHidetoshi Shimokawa #define F_LINK_ACTIVE	(1 << 0)
93a73ff510SHidetoshi Shimokawa #define F_ATIO_STARVED	(1 << 1)
94a73ff510SHidetoshi Shimokawa #define F_LOGIN		(1 << 2)
95a73ff510SHidetoshi Shimokawa #define F_HOLD		(1 << 3)
96a73ff510SHidetoshi Shimokawa #define F_FREEZED	(1 << 4)
97a73ff510SHidetoshi Shimokawa 
98e9e688e2SHidetoshi Shimokawa MALLOC_DEFINE(M_SBP_TARG, "sbp_targ", "SBP-II/FireWire target mode");
99e9e688e2SHidetoshi Shimokawa 
100e9e688e2SHidetoshi Shimokawa static int debug = 0;
101e9e688e2SHidetoshi Shimokawa 
102e9e688e2SHidetoshi Shimokawa SYSCTL_INT(_debug, OID_AUTO, sbp_targ_debug, CTLFLAG_RW, &debug, 0,
103e9e688e2SHidetoshi Shimokawa         "SBP target mode debug flag");
104e9e688e2SHidetoshi Shimokawa 
105a73ff510SHidetoshi Shimokawa struct sbp_targ_login {
106a73ff510SHidetoshi Shimokawa 	struct sbp_targ_lstate *lstate;
107a73ff510SHidetoshi Shimokawa 	struct fw_device *fwdev;
108a73ff510SHidetoshi Shimokawa 	struct sbp_login_res loginres;
10903161bbcSDoug Rabson 	uint16_t fifo_hi;
11003161bbcSDoug Rabson 	uint16_t last_hi;
11103161bbcSDoug Rabson 	uint32_t fifo_lo;
11203161bbcSDoug Rabson 	uint32_t last_lo;
113a73ff510SHidetoshi Shimokawa 	STAILQ_HEAD(, orb_info) orbs;
114a73ff510SHidetoshi Shimokawa 	STAILQ_ENTRY(sbp_targ_login) link;
11503161bbcSDoug Rabson 	uint16_t hold_sec;
11603161bbcSDoug Rabson 	uint16_t id;
11703161bbcSDoug Rabson 	uint8_t flags;
11803161bbcSDoug Rabson 	uint8_t spd;
119a73ff510SHidetoshi Shimokawa 	struct callout hold_callout;
120a73ff510SHidetoshi Shimokawa };
121a73ff510SHidetoshi Shimokawa 
122a73ff510SHidetoshi Shimokawa struct sbp_targ_lstate {
12303161bbcSDoug Rabson 	uint16_t lun;
124a73ff510SHidetoshi Shimokawa 	struct sbp_targ_softc *sc;
125a73ff510SHidetoshi Shimokawa 	struct cam_path *path;
126a73ff510SHidetoshi Shimokawa 	struct ccb_hdr_slist accept_tios;
127a73ff510SHidetoshi Shimokawa 	struct ccb_hdr_slist immed_notifies;
128a73ff510SHidetoshi Shimokawa 	struct crom_chunk model;
12903161bbcSDoug Rabson 	uint32_t flags;
130a73ff510SHidetoshi Shimokawa 	STAILQ_HEAD(, sbp_targ_login) logins;
131a73ff510SHidetoshi Shimokawa };
132a73ff510SHidetoshi Shimokawa 
133e9e688e2SHidetoshi Shimokawa struct sbp_targ_softc {
134e9e688e2SHidetoshi Shimokawa         struct firewire_dev_comm fd;
135e9e688e2SHidetoshi Shimokawa 	struct cam_sim *sim;
136e9e688e2SHidetoshi Shimokawa 	struct cam_path *path;
137e9e688e2SHidetoshi Shimokawa 	struct fw_bind fwb;
138e9e688e2SHidetoshi Shimokawa 	int ndevs;
139a73ff510SHidetoshi Shimokawa 	int flags;
140e9e688e2SHidetoshi Shimokawa 	struct crom_chunk unit;
141e9e688e2SHidetoshi Shimokawa 	struct sbp_targ_lstate *lstate[MAX_LUN];
142e9e688e2SHidetoshi Shimokawa 	struct sbp_targ_lstate *black_hole;
143a73ff510SHidetoshi Shimokawa 	struct sbp_targ_login *logins[MAX_LOGINS];
1449950b741SHidetoshi Shimokawa 	struct mtx mtx;
145e9e688e2SHidetoshi Shimokawa };
1469950b741SHidetoshi Shimokawa #define SBP_LOCK(sc) mtx_lock(&(sc)->mtx)
1479950b741SHidetoshi Shimokawa #define SBP_UNLOCK(sc) mtx_unlock(&(sc)->mtx)
148e9e688e2SHidetoshi Shimokawa 
149e9e688e2SHidetoshi Shimokawa struct corb4 {
150e9e688e2SHidetoshi Shimokawa #if BYTE_ORDER == BIG_ENDIAN
15103161bbcSDoug Rabson 	uint32_t n:1,
152e9e688e2SHidetoshi Shimokawa 		  rq_fmt:2,
153e9e688e2SHidetoshi Shimokawa 		  :1,
154e9e688e2SHidetoshi Shimokawa 		  dir:1,
155e9e688e2SHidetoshi Shimokawa 		  spd:3,
156e9e688e2SHidetoshi Shimokawa 		  max_payload:4,
157e9e688e2SHidetoshi Shimokawa 		  page_table_present:1,
158e9e688e2SHidetoshi Shimokawa 		  page_size:3,
159e9e688e2SHidetoshi Shimokawa 		  data_size:16;
160e9e688e2SHidetoshi Shimokawa #else
16103161bbcSDoug Rabson 	uint32_t data_size:16,
162e9e688e2SHidetoshi Shimokawa 		  page_size:3,
163e9e688e2SHidetoshi Shimokawa 		  page_table_present:1,
164e9e688e2SHidetoshi Shimokawa 		  max_payload:4,
165e9e688e2SHidetoshi Shimokawa 		  spd:3,
166e9e688e2SHidetoshi Shimokawa 		  dir:1,
167e9e688e2SHidetoshi Shimokawa 		  :1,
168e9e688e2SHidetoshi Shimokawa 		  rq_fmt:2,
169e9e688e2SHidetoshi Shimokawa 		  n:1;
170e9e688e2SHidetoshi Shimokawa #endif
171e9e688e2SHidetoshi Shimokawa };
172e9e688e2SHidetoshi Shimokawa 
173e9e688e2SHidetoshi Shimokawa struct morb4 {
174e9e688e2SHidetoshi Shimokawa #if BYTE_ORDER == BIG_ENDIAN
17503161bbcSDoug Rabson 	uint32_t n:1,
176e9e688e2SHidetoshi Shimokawa 		  rq_fmt:2,
177e9e688e2SHidetoshi Shimokawa 		  :9,
178e9e688e2SHidetoshi Shimokawa 		  fun:4,
179e9e688e2SHidetoshi Shimokawa 		  id:16;
180e9e688e2SHidetoshi Shimokawa #else
18103161bbcSDoug Rabson 	uint32_t id:16,
182e9e688e2SHidetoshi Shimokawa 		  fun:4,
183e9e688e2SHidetoshi Shimokawa 		  :9,
184e9e688e2SHidetoshi Shimokawa 		  rq_fmt:2,
185e9e688e2SHidetoshi Shimokawa 		  n:1;
186e9e688e2SHidetoshi Shimokawa #endif
187e9e688e2SHidetoshi Shimokawa };
188e9e688e2SHidetoshi Shimokawa 
189e9e688e2SHidetoshi Shimokawa struct orb_info {
190e9e688e2SHidetoshi Shimokawa 	struct sbp_targ_softc *sc;
191e9e688e2SHidetoshi Shimokawa 	struct fw_device *fwdev;
192a73ff510SHidetoshi Shimokawa 	struct sbp_targ_login *login;
193e9e688e2SHidetoshi Shimokawa 	union ccb *ccb;
194e9e688e2SHidetoshi Shimokawa 	struct ccb_accept_tio *atio;
19503161bbcSDoug Rabson 	uint8_t state;
196e9e688e2SHidetoshi Shimokawa #define ORBI_STATUS_NONE	0
197e9e688e2SHidetoshi Shimokawa #define ORBI_STATUS_FETCH	1
198e9e688e2SHidetoshi Shimokawa #define ORBI_STATUS_ATIO	2
199e9e688e2SHidetoshi Shimokawa #define ORBI_STATUS_CTIO	3
200e9e688e2SHidetoshi Shimokawa #define ORBI_STATUS_STATUS	4
201e9e688e2SHidetoshi Shimokawa #define ORBI_STATUS_POINTER	5
202e9e688e2SHidetoshi Shimokawa #define ORBI_STATUS_ABORTED	7
20303161bbcSDoug Rabson 	uint8_t refcount;
20403161bbcSDoug Rabson 	uint16_t orb_hi;
20503161bbcSDoug Rabson 	uint32_t orb_lo;
20603161bbcSDoug Rabson 	uint32_t data_hi;
20703161bbcSDoug Rabson 	uint32_t data_lo;
208e9e688e2SHidetoshi Shimokawa 	struct corb4 orb4;
209e9e688e2SHidetoshi Shimokawa 	STAILQ_ENTRY(orb_info) link;
21003161bbcSDoug Rabson 	uint32_t orb[8];
21103161bbcSDoug Rabson 	uint32_t *page_table;
212e9e688e2SHidetoshi Shimokawa 	struct sbp_status status;
213e9e688e2SHidetoshi Shimokawa };
214e9e688e2SHidetoshi Shimokawa 
215e9e688e2SHidetoshi Shimokawa static char *orb_fun_name[] = {
216e9e688e2SHidetoshi Shimokawa 	ORB_FUN_NAMES
217e9e688e2SHidetoshi Shimokawa };
218e9e688e2SHidetoshi Shimokawa 
219e9e688e2SHidetoshi Shimokawa static void sbp_targ_recv(struct fw_xfer *);
220e9e688e2SHidetoshi Shimokawa static void sbp_targ_fetch_orb(struct sbp_targ_softc *, struct fw_device *,
22103161bbcSDoug Rabson     uint16_t, uint32_t, struct sbp_targ_login *, int);
2229950b741SHidetoshi Shimokawa static void sbp_targ_abort(struct sbp_targ_softc *, struct orb_info *);
223e9e688e2SHidetoshi Shimokawa 
224e9e688e2SHidetoshi Shimokawa static void
225e9e688e2SHidetoshi Shimokawa sbp_targ_identify(driver_t *driver, device_t parent)
226e9e688e2SHidetoshi Shimokawa {
227e9e688e2SHidetoshi Shimokawa 	BUS_ADD_CHILD(parent, 0, "sbp_targ", device_get_unit(parent));
228e9e688e2SHidetoshi Shimokawa }
229e9e688e2SHidetoshi Shimokawa 
230e9e688e2SHidetoshi Shimokawa static int
231e9e688e2SHidetoshi Shimokawa sbp_targ_probe(device_t dev)
232e9e688e2SHidetoshi Shimokawa {
233e9e688e2SHidetoshi Shimokawa 	device_t pa;
234e9e688e2SHidetoshi Shimokawa 
235e9e688e2SHidetoshi Shimokawa 	pa = device_get_parent(dev);
236e9e688e2SHidetoshi Shimokawa 	if(device_get_unit(dev) != device_get_unit(pa)){
237e9e688e2SHidetoshi Shimokawa 		return(ENXIO);
238e9e688e2SHidetoshi Shimokawa 	}
239e9e688e2SHidetoshi Shimokawa 
240e9e688e2SHidetoshi Shimokawa 	device_set_desc(dev, "SBP-2/SCSI over FireWire target mode");
241e9e688e2SHidetoshi Shimokawa 	return (0);
242e9e688e2SHidetoshi Shimokawa }
243e9e688e2SHidetoshi Shimokawa 
244a73ff510SHidetoshi Shimokawa static void
245a73ff510SHidetoshi Shimokawa sbp_targ_dealloc_login(struct sbp_targ_login *login)
246a73ff510SHidetoshi Shimokawa {
247a73ff510SHidetoshi Shimokawa 	struct orb_info *orbi, *next;
248a73ff510SHidetoshi Shimokawa 
249a73ff510SHidetoshi Shimokawa 	if (login == NULL) {
25010d3ed64SHidetoshi Shimokawa 		printf("%s: login = NULL\n", __func__);
251a73ff510SHidetoshi Shimokawa 		return;
252a73ff510SHidetoshi Shimokawa 	}
253a73ff510SHidetoshi Shimokawa 	for (orbi = STAILQ_FIRST(&login->orbs); orbi != NULL; orbi = next) {
254a73ff510SHidetoshi Shimokawa 		next = STAILQ_NEXT(orbi, link);
255a73ff510SHidetoshi Shimokawa 		free(orbi, M_SBP_TARG);
256a73ff510SHidetoshi Shimokawa 	}
257a73ff510SHidetoshi Shimokawa 	callout_stop(&login->hold_callout);
258a73ff510SHidetoshi Shimokawa 
259a73ff510SHidetoshi Shimokawa 	STAILQ_REMOVE(&login->lstate->logins, login, sbp_targ_login, link);
260a73ff510SHidetoshi Shimokawa 	login->lstate->sc->logins[login->id] = NULL;
261a73ff510SHidetoshi Shimokawa 	free((void *)login, M_SBP_TARG);
262a73ff510SHidetoshi Shimokawa }
263a73ff510SHidetoshi Shimokawa 
264a73ff510SHidetoshi Shimokawa static void
265a73ff510SHidetoshi Shimokawa sbp_targ_hold_expire(void *arg)
266a73ff510SHidetoshi Shimokawa {
267a73ff510SHidetoshi Shimokawa 	struct sbp_targ_login *login;
268a73ff510SHidetoshi Shimokawa 
269a73ff510SHidetoshi Shimokawa 	login = (struct sbp_targ_login *)arg;
270a73ff510SHidetoshi Shimokawa 
271a73ff510SHidetoshi Shimokawa 	if (login->flags & F_HOLD) {
27210d3ed64SHidetoshi Shimokawa 		printf("%s: login_id=%d expired\n", __func__, login->id);
273a73ff510SHidetoshi Shimokawa 		sbp_targ_dealloc_login(login);
274a73ff510SHidetoshi Shimokawa 	} else {
27510d3ed64SHidetoshi Shimokawa 		printf("%s: login_id=%d not hold\n", __func__, login->id);
276a73ff510SHidetoshi Shimokawa 	}
277a73ff510SHidetoshi Shimokawa }
278a73ff510SHidetoshi Shimokawa 
279e9e688e2SHidetoshi Shimokawa static void
280e9e688e2SHidetoshi Shimokawa sbp_targ_post_busreset(void *arg)
281e9e688e2SHidetoshi Shimokawa {
282e9e688e2SHidetoshi Shimokawa 	struct sbp_targ_softc *sc;
283e9e688e2SHidetoshi Shimokawa 	struct crom_src *src;
284e9e688e2SHidetoshi Shimokawa 	struct crom_chunk *root;
285e9e688e2SHidetoshi Shimokawa 	struct crom_chunk *unit;
286e9e688e2SHidetoshi Shimokawa 	struct sbp_targ_lstate *lstate;
287a73ff510SHidetoshi Shimokawa 	struct sbp_targ_login *login;
288e9e688e2SHidetoshi Shimokawa 	int i;
289e9e688e2SHidetoshi Shimokawa 
290e9e688e2SHidetoshi Shimokawa 	sc = (struct sbp_targ_softc *)arg;
291e9e688e2SHidetoshi Shimokawa 	src = sc->fd.fc->crom_src;
292e9e688e2SHidetoshi Shimokawa 	root = sc->fd.fc->crom_root;
293e9e688e2SHidetoshi Shimokawa 
294e9e688e2SHidetoshi Shimokawa 	unit = &sc->unit;
295e9e688e2SHidetoshi Shimokawa 
296a73ff510SHidetoshi Shimokawa 	if ((sc->flags & F_FREEZED) == 0) {
2979950b741SHidetoshi Shimokawa 		SBP_LOCK(sc);
298a73ff510SHidetoshi Shimokawa 		sc->flags |= F_FREEZED;
299a73ff510SHidetoshi Shimokawa 		xpt_freeze_simq(sc->sim, /*count*/1);
3009950b741SHidetoshi Shimokawa 		SBP_UNLOCK(sc);
301a73ff510SHidetoshi Shimokawa 	} else {
30210d3ed64SHidetoshi Shimokawa 		printf("%s: already freezed\n", __func__);
303a73ff510SHidetoshi Shimokawa 	}
304a73ff510SHidetoshi Shimokawa 
305e9e688e2SHidetoshi Shimokawa 	bzero(unit, sizeof(struct crom_chunk));
306e9e688e2SHidetoshi Shimokawa 
307e9e688e2SHidetoshi Shimokawa 	crom_add_chunk(src, root, unit, CROM_UDIR);
308e9e688e2SHidetoshi Shimokawa 	crom_add_entry(unit, CSRKEY_SPEC, CSRVAL_ANSIT10);
309e9e688e2SHidetoshi Shimokawa 	crom_add_entry(unit, CSRKEY_VER, CSRVAL_T10SBP2);
310e9e688e2SHidetoshi Shimokawa 	crom_add_entry(unit, CSRKEY_COM_SPEC, CSRVAL_ANSIT10);
311e9e688e2SHidetoshi Shimokawa 	crom_add_entry(unit, CSRKEY_COM_SET, CSRVAL_SCSI);
312e9e688e2SHidetoshi Shimokawa 
313e9e688e2SHidetoshi Shimokawa 	crom_add_entry(unit, CROM_MGM, SBP_TARG_MGM >> 2);
314e9e688e2SHidetoshi Shimokawa 	crom_add_entry(unit, CSRKEY_UNIT_CH, (10<<8) | 8);
315e9e688e2SHidetoshi Shimokawa 
316e9e688e2SHidetoshi Shimokawa 	for (i = 0; i < MAX_LUN; i ++) {
317e9e688e2SHidetoshi Shimokawa 		lstate = sc->lstate[i];
318e9e688e2SHidetoshi Shimokawa 		if (lstate == NULL)
319e9e688e2SHidetoshi Shimokawa 			continue;
320e9e688e2SHidetoshi Shimokawa 		crom_add_entry(unit, CSRKEY_FIRM_VER, 1);
321e9e688e2SHidetoshi Shimokawa 		crom_add_entry(unit, CROM_LUN, i);
322e9e688e2SHidetoshi Shimokawa 		crom_add_entry(unit, CSRKEY_MODEL, 1);
323e9e688e2SHidetoshi Shimokawa 		crom_add_simple_text(src, unit, &lstate->model, "TargetMode");
324e9e688e2SHidetoshi Shimokawa 	}
325a73ff510SHidetoshi Shimokawa 
326a73ff510SHidetoshi Shimokawa 	/* Process for reconnection hold time */
327a73ff510SHidetoshi Shimokawa 	for (i = 0; i < MAX_LOGINS; i ++) {
328a73ff510SHidetoshi Shimokawa 		login = sc->logins[i];
329a73ff510SHidetoshi Shimokawa 		if (login == NULL)
330a73ff510SHidetoshi Shimokawa 			continue;
3319950b741SHidetoshi Shimokawa 		sbp_targ_abort(sc, STAILQ_FIRST(&login->orbs));
332a73ff510SHidetoshi Shimokawa 		if (login->flags & F_LOGIN) {
333a73ff510SHidetoshi Shimokawa 			login->flags |= F_HOLD;
334a73ff510SHidetoshi Shimokawa 			callout_reset(&login->hold_callout,
335a73ff510SHidetoshi Shimokawa 			    hz * login->hold_sec,
336a73ff510SHidetoshi Shimokawa 			    sbp_targ_hold_expire, (void *)login);
337a73ff510SHidetoshi Shimokawa 		}
338a73ff510SHidetoshi Shimokawa 	}
339a73ff510SHidetoshi Shimokawa }
340a73ff510SHidetoshi Shimokawa 
341a73ff510SHidetoshi Shimokawa static void
342a73ff510SHidetoshi Shimokawa sbp_targ_post_explore(void *arg)
343a73ff510SHidetoshi Shimokawa {
344a73ff510SHidetoshi Shimokawa 	struct sbp_targ_softc *sc;
345a73ff510SHidetoshi Shimokawa 
346a73ff510SHidetoshi Shimokawa 	sc = (struct sbp_targ_softc *)arg;
3479950b741SHidetoshi Shimokawa 	SBP_LOCK(sc);
348a73ff510SHidetoshi Shimokawa 	sc->flags &= ~F_FREEZED;
349a73ff510SHidetoshi Shimokawa 	xpt_release_simq(sc->sim, /*run queue*/TRUE);
3509950b741SHidetoshi Shimokawa 	SBP_UNLOCK(sc);
351a73ff510SHidetoshi Shimokawa 	return;
352e9e688e2SHidetoshi Shimokawa }
353e9e688e2SHidetoshi Shimokawa 
354e9e688e2SHidetoshi Shimokawa static cam_status
355e9e688e2SHidetoshi Shimokawa sbp_targ_find_devs(struct sbp_targ_softc *sc, union ccb *ccb,
356e9e688e2SHidetoshi Shimokawa     struct sbp_targ_lstate **lstate, int notfound_failure)
357e9e688e2SHidetoshi Shimokawa {
358e9e688e2SHidetoshi Shimokawa 	u_int lun;
359e9e688e2SHidetoshi Shimokawa 
360e9e688e2SHidetoshi Shimokawa 	/* XXX 0 is the only vaild target_id */
361e9e688e2SHidetoshi Shimokawa 	if (ccb->ccb_h.target_id == CAM_TARGET_WILDCARD &&
362e9e688e2SHidetoshi Shimokawa 	    ccb->ccb_h.target_lun == CAM_LUN_WILDCARD) {
363e9e688e2SHidetoshi Shimokawa 		*lstate = sc->black_hole;
364e9e688e2SHidetoshi Shimokawa 		return (CAM_REQ_CMP);
365e9e688e2SHidetoshi Shimokawa 	}
366e9e688e2SHidetoshi Shimokawa 
367e9e688e2SHidetoshi Shimokawa 	if (ccb->ccb_h.target_id != 0)
368e9e688e2SHidetoshi Shimokawa 		return (CAM_TID_INVALID);
369e9e688e2SHidetoshi Shimokawa 
370e9e688e2SHidetoshi Shimokawa 	lun = ccb->ccb_h.target_lun;
371e9e688e2SHidetoshi Shimokawa 	if (lun >= MAX_LUN)
372e9e688e2SHidetoshi Shimokawa 		return (CAM_LUN_INVALID);
373e9e688e2SHidetoshi Shimokawa 
374e9e688e2SHidetoshi Shimokawa 	*lstate = sc->lstate[lun];
375e9e688e2SHidetoshi Shimokawa 
376e9e688e2SHidetoshi Shimokawa 	if (notfound_failure != 0 && *lstate == NULL)
377e9e688e2SHidetoshi Shimokawa 		return (CAM_PATH_INVALID);
378e9e688e2SHidetoshi Shimokawa 
379e9e688e2SHidetoshi Shimokawa 	return (CAM_REQ_CMP);
380e9e688e2SHidetoshi Shimokawa }
381e9e688e2SHidetoshi Shimokawa 
382e9e688e2SHidetoshi Shimokawa static void
383e9e688e2SHidetoshi Shimokawa sbp_targ_en_lun(struct sbp_targ_softc *sc, union ccb *ccb)
384e9e688e2SHidetoshi Shimokawa {
385e9e688e2SHidetoshi Shimokawa 	struct ccb_en_lun *cel = &ccb->cel;
386e9e688e2SHidetoshi Shimokawa 	struct sbp_targ_lstate *lstate;
387e9e688e2SHidetoshi Shimokawa 	cam_status status;
388e9e688e2SHidetoshi Shimokawa 
389e9e688e2SHidetoshi Shimokawa 	status = sbp_targ_find_devs(sc, ccb, &lstate, 0);
390e9e688e2SHidetoshi Shimokawa 	if (status != CAM_REQ_CMP) {
391e9e688e2SHidetoshi Shimokawa 		ccb->ccb_h.status = status;
392e9e688e2SHidetoshi Shimokawa 		return;
393e9e688e2SHidetoshi Shimokawa 	}
394e9e688e2SHidetoshi Shimokawa 
395e9e688e2SHidetoshi Shimokawa 	if (cel->enable != 0) {
396e9e688e2SHidetoshi Shimokawa 		if (lstate != NULL) {
397e9e688e2SHidetoshi Shimokawa 			xpt_print_path(ccb->ccb_h.path);
398e9e688e2SHidetoshi Shimokawa 			printf("Lun already enabled\n");
399e9e688e2SHidetoshi Shimokawa 			ccb->ccb_h.status = CAM_LUN_ALRDY_ENA;
400e9e688e2SHidetoshi Shimokawa 			return;
401e9e688e2SHidetoshi Shimokawa 		}
402e9e688e2SHidetoshi Shimokawa 		if (cel->grp6_len != 0 || cel->grp7_len != 0) {
403e9e688e2SHidetoshi Shimokawa 			ccb->ccb_h.status = CAM_REQ_INVALID;
404e9e688e2SHidetoshi Shimokawa 			printf("Non-zero Group Codes\n");
405e9e688e2SHidetoshi Shimokawa 			return;
406e9e688e2SHidetoshi Shimokawa 		}
407e9e688e2SHidetoshi Shimokawa 		lstate = (struct sbp_targ_lstate *)
408e9e688e2SHidetoshi Shimokawa 		    malloc(sizeof(*lstate), M_SBP_TARG, M_NOWAIT | M_ZERO);
409e9e688e2SHidetoshi Shimokawa 		if (lstate == NULL) {
410e9e688e2SHidetoshi Shimokawa 			xpt_print_path(ccb->ccb_h.path);
411e9e688e2SHidetoshi Shimokawa 			printf("Couldn't allocate lstate\n");
412e9e688e2SHidetoshi Shimokawa 			ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
413e9e688e2SHidetoshi Shimokawa 			return;
414e9e688e2SHidetoshi Shimokawa 		}
415e9e688e2SHidetoshi Shimokawa 		if (ccb->ccb_h.target_id == CAM_TARGET_WILDCARD)
416e9e688e2SHidetoshi Shimokawa 			sc->black_hole = lstate;
417e9e688e2SHidetoshi Shimokawa 		else
418e9e688e2SHidetoshi Shimokawa 			sc->lstate[ccb->ccb_h.target_lun] = lstate;
419e9e688e2SHidetoshi Shimokawa 		memset(lstate, 0, sizeof(*lstate));
420e9e688e2SHidetoshi Shimokawa 		lstate->sc = sc;
421e9e688e2SHidetoshi Shimokawa 		status = xpt_create_path(&lstate->path, /*periph*/NULL,
422e9e688e2SHidetoshi Shimokawa 					 xpt_path_path_id(ccb->ccb_h.path),
423e9e688e2SHidetoshi Shimokawa 					 xpt_path_target_id(ccb->ccb_h.path),
424e9e688e2SHidetoshi Shimokawa 					 xpt_path_lun_id(ccb->ccb_h.path));
425e9e688e2SHidetoshi Shimokawa 		if (status != CAM_REQ_CMP) {
426e9e688e2SHidetoshi Shimokawa 			free(lstate, M_SBP_TARG);
427e9e688e2SHidetoshi Shimokawa 			xpt_print_path(ccb->ccb_h.path);
428e9e688e2SHidetoshi Shimokawa 			printf("Couldn't allocate path\n");
429e9e688e2SHidetoshi Shimokawa 			ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
430e9e688e2SHidetoshi Shimokawa 			return;
431e9e688e2SHidetoshi Shimokawa 		}
432e9e688e2SHidetoshi Shimokawa 		SLIST_INIT(&lstate->accept_tios);
433e9e688e2SHidetoshi Shimokawa 		SLIST_INIT(&lstate->immed_notifies);
434a73ff510SHidetoshi Shimokawa 		STAILQ_INIT(&lstate->logins);
435e9e688e2SHidetoshi Shimokawa 
436e9e688e2SHidetoshi Shimokawa 		ccb->ccb_h.status = CAM_REQ_CMP;
437e9e688e2SHidetoshi Shimokawa 		xpt_print_path(ccb->ccb_h.path);
438e9e688e2SHidetoshi Shimokawa 		printf("Lun now enabled for target mode\n");
439e9e688e2SHidetoshi Shimokawa 		/* bus reset */
440e9e688e2SHidetoshi Shimokawa 		sc->fd.fc->ibr(sc->fd.fc);
441e9e688e2SHidetoshi Shimokawa 	} else {
442a73ff510SHidetoshi Shimokawa 		struct sbp_targ_login *login, *next;
443a73ff510SHidetoshi Shimokawa 
444e9e688e2SHidetoshi Shimokawa 		if (lstate == NULL) {
445e9e688e2SHidetoshi Shimokawa 			ccb->ccb_h.status = CAM_LUN_INVALID;
446e9e688e2SHidetoshi Shimokawa 			return;
447e9e688e2SHidetoshi Shimokawa 		}
448e9e688e2SHidetoshi Shimokawa 		ccb->ccb_h.status = CAM_REQ_CMP;
449e9e688e2SHidetoshi Shimokawa 
450e9e688e2SHidetoshi Shimokawa 		if (SLIST_FIRST(&lstate->accept_tios) != NULL) {
451e9e688e2SHidetoshi Shimokawa 			printf("ATIOs pending\n");
452e9e688e2SHidetoshi Shimokawa 			ccb->ccb_h.status = CAM_REQ_INVALID;
453e9e688e2SHidetoshi Shimokawa 		}
454e9e688e2SHidetoshi Shimokawa 
455e9e688e2SHidetoshi Shimokawa 		if (SLIST_FIRST(&lstate->immed_notifies) != NULL) {
456e9e688e2SHidetoshi Shimokawa 			printf("INOTs pending\n");
457e9e688e2SHidetoshi Shimokawa 			ccb->ccb_h.status = CAM_REQ_INVALID;
458e9e688e2SHidetoshi Shimokawa 		}
459e9e688e2SHidetoshi Shimokawa 
460e9e688e2SHidetoshi Shimokawa 		if (ccb->ccb_h.status != CAM_REQ_CMP) {
461e9e688e2SHidetoshi Shimokawa 			return;
462e9e688e2SHidetoshi Shimokawa 		}
463e9e688e2SHidetoshi Shimokawa 
464e9e688e2SHidetoshi Shimokawa 		xpt_print_path(ccb->ccb_h.path);
465e9e688e2SHidetoshi Shimokawa 		printf("Target mode disabled\n");
466e9e688e2SHidetoshi Shimokawa 		xpt_free_path(lstate->path);
467e9e688e2SHidetoshi Shimokawa 
468a73ff510SHidetoshi Shimokawa 		for (login = STAILQ_FIRST(&lstate->logins); login != NULL;
469a73ff510SHidetoshi Shimokawa 		    login = next) {
470a73ff510SHidetoshi Shimokawa 			next = STAILQ_NEXT(login, link);
471a73ff510SHidetoshi Shimokawa 			sbp_targ_dealloc_login(login);
472e9e688e2SHidetoshi Shimokawa 		}
473e9e688e2SHidetoshi Shimokawa 
474e9e688e2SHidetoshi Shimokawa 		if (ccb->ccb_h.target_id == CAM_TARGET_WILDCARD)
475e9e688e2SHidetoshi Shimokawa 			sc->black_hole = NULL;
476e9e688e2SHidetoshi Shimokawa 		else
477e9e688e2SHidetoshi Shimokawa 			sc->lstate[ccb->ccb_h.target_lun] = NULL;
478e9e688e2SHidetoshi Shimokawa 		free(lstate, M_SBP_TARG);
479e9e688e2SHidetoshi Shimokawa 
480e9e688e2SHidetoshi Shimokawa 		/* bus reset */
481e9e688e2SHidetoshi Shimokawa 		sc->fd.fc->ibr(sc->fd.fc);
482e9e688e2SHidetoshi Shimokawa 	}
483e9e688e2SHidetoshi Shimokawa }
484e9e688e2SHidetoshi Shimokawa 
485e9e688e2SHidetoshi Shimokawa static void
486e9e688e2SHidetoshi Shimokawa sbp_targ_send_lstate_events(struct sbp_targ_softc *sc,
487e9e688e2SHidetoshi Shimokawa     struct sbp_targ_lstate *lstate)
488e9e688e2SHidetoshi Shimokawa {
489e9e688e2SHidetoshi Shimokawa #if 0
490e9e688e2SHidetoshi Shimokawa 	struct ccb_hdr *ccbh;
491e9e688e2SHidetoshi Shimokawa 	struct ccb_immed_notify *inot;
492e9e688e2SHidetoshi Shimokawa 
49310d3ed64SHidetoshi Shimokawa 	printf("%s: not implemented yet\n", __func__);
494e9e688e2SHidetoshi Shimokawa #endif
495e9e688e2SHidetoshi Shimokawa }
496e9e688e2SHidetoshi Shimokawa 
4979950b741SHidetoshi Shimokawa 
4989950b741SHidetoshi Shimokawa static __inline void
4999950b741SHidetoshi Shimokawa sbp_targ_remove_orb_info_locked(struct sbp_targ_login *login, struct orb_info *orbi)
5009950b741SHidetoshi Shimokawa {
5019950b741SHidetoshi Shimokawa 	STAILQ_REMOVE(&login->orbs, orbi, orb_info, link);
5029950b741SHidetoshi Shimokawa }
5039950b741SHidetoshi Shimokawa 
504e9e688e2SHidetoshi Shimokawa static __inline void
505a73ff510SHidetoshi Shimokawa sbp_targ_remove_orb_info(struct sbp_targ_login *login, struct orb_info *orbi)
506e9e688e2SHidetoshi Shimokawa {
5079950b741SHidetoshi Shimokawa 	SBP_LOCK(orbi->sc);
508a73ff510SHidetoshi Shimokawa 	STAILQ_REMOVE(&login->orbs, orbi, orb_info, link);
5099950b741SHidetoshi Shimokawa 	SBP_UNLOCK(orbi->sc);
510e9e688e2SHidetoshi Shimokawa }
511e9e688e2SHidetoshi Shimokawa 
512e9e688e2SHidetoshi Shimokawa /*
513e9e688e2SHidetoshi Shimokawa  * tag_id/init_id encoding
514e9e688e2SHidetoshi Shimokawa  *
515e9e688e2SHidetoshi Shimokawa  * tag_id and init_id has only 32bit for each.
516e9e688e2SHidetoshi Shimokawa  * scsi_target can handle very limited number(up to 15) of init_id.
517e9e688e2SHidetoshi Shimokawa  * we have to encode 48bit orb and 64bit EUI64 into these
518e9e688e2SHidetoshi Shimokawa  * variables.
519e9e688e2SHidetoshi Shimokawa  *
520e9e688e2SHidetoshi Shimokawa  * tag_id represents lower 32bit of ORB address.
521a73ff510SHidetoshi Shimokawa  * init_id represents login_id.
522e9e688e2SHidetoshi Shimokawa  *
523e9e688e2SHidetoshi Shimokawa  */
524e9e688e2SHidetoshi Shimokawa 
525e9e688e2SHidetoshi Shimokawa static struct orb_info *
526e9e688e2SHidetoshi Shimokawa sbp_targ_get_orb_info(struct sbp_targ_lstate *lstate,
527e9e688e2SHidetoshi Shimokawa     u_int tag_id, u_int init_id)
528e9e688e2SHidetoshi Shimokawa {
529a73ff510SHidetoshi Shimokawa 	struct sbp_targ_login *login;
530e9e688e2SHidetoshi Shimokawa 	struct orb_info *orbi;
531e9e688e2SHidetoshi Shimokawa 
532a73ff510SHidetoshi Shimokawa 	login = lstate->sc->logins[init_id];
533a73ff510SHidetoshi Shimokawa 	if (login == NULL) {
53410d3ed64SHidetoshi Shimokawa 		printf("%s: no such login\n", __func__);
535a73ff510SHidetoshi Shimokawa 		return (NULL);
536a73ff510SHidetoshi Shimokawa 	}
537a73ff510SHidetoshi Shimokawa 	STAILQ_FOREACH(orbi, &login->orbs, link)
538a73ff510SHidetoshi Shimokawa 		if (orbi->orb_lo == tag_id)
539e9e688e2SHidetoshi Shimokawa 			goto found;
5409950b741SHidetoshi Shimokawa 	printf("%s: orb not found tag_id=0x%08x init_id=%d\n",
5419950b741SHidetoshi Shimokawa 				 __func__, tag_id, init_id);
542e9e688e2SHidetoshi Shimokawa 	return (NULL);
543e9e688e2SHidetoshi Shimokawa found:
544e9e688e2SHidetoshi Shimokawa 	return (orbi);
545e9e688e2SHidetoshi Shimokawa }
546e9e688e2SHidetoshi Shimokawa 
547e9e688e2SHidetoshi Shimokawa static void
5489950b741SHidetoshi Shimokawa sbp_targ_abort(struct sbp_targ_softc *sc, struct orb_info *orbi)
549e9e688e2SHidetoshi Shimokawa {
550e9e688e2SHidetoshi Shimokawa 	struct orb_info *norbi;
551e9e688e2SHidetoshi Shimokawa 
5529950b741SHidetoshi Shimokawa 	SBP_LOCK(sc);
553e9e688e2SHidetoshi Shimokawa 	for (; orbi != NULL; orbi = norbi) {
5549950b741SHidetoshi Shimokawa 		printf("%s: status=%d ccb=%p\n", __func__, orbi->state, orbi->ccb);
555e9e688e2SHidetoshi Shimokawa 		norbi = STAILQ_NEXT(orbi, link);
556e9e688e2SHidetoshi Shimokawa 		if (orbi->state != ORBI_STATUS_ABORTED) {
557e9e688e2SHidetoshi Shimokawa 			if (orbi->ccb != NULL) {
558e9e688e2SHidetoshi Shimokawa 				orbi->ccb->ccb_h.status = CAM_REQ_ABORTED;
559e9e688e2SHidetoshi Shimokawa 				xpt_done(orbi->ccb);
560e9e688e2SHidetoshi Shimokawa 				orbi->ccb = NULL;
561e9e688e2SHidetoshi Shimokawa 			}
5629950b741SHidetoshi Shimokawa #if 0
563e9e688e2SHidetoshi Shimokawa 			if (orbi->state <= ORBI_STATUS_ATIO) {
5649950b741SHidetoshi Shimokawa 				sbp_targ_remove_orb_info_locked(orbi->login, orbi);
565e9e688e2SHidetoshi Shimokawa 				free(orbi, M_SBP_TARG);
566e9e688e2SHidetoshi Shimokawa 			} else
5679950b741SHidetoshi Shimokawa #endif
568e9e688e2SHidetoshi Shimokawa 				orbi->state = ORBI_STATUS_ABORTED;
569e9e688e2SHidetoshi Shimokawa 		}
570e9e688e2SHidetoshi Shimokawa 	}
5719950b741SHidetoshi Shimokawa 	SBP_UNLOCK(sc);
572e9e688e2SHidetoshi Shimokawa }
573e9e688e2SHidetoshi Shimokawa 
574e9e688e2SHidetoshi Shimokawa static void
575e9e688e2SHidetoshi Shimokawa sbp_targ_free_orbi(struct fw_xfer *xfer)
576e9e688e2SHidetoshi Shimokawa {
577e9e688e2SHidetoshi Shimokawa 	struct orb_info *orbi;
578e9e688e2SHidetoshi Shimokawa 
579e9e688e2SHidetoshi Shimokawa 	orbi = (struct orb_info *)xfer->sc;
580e9e688e2SHidetoshi Shimokawa 	if (xfer->resp != 0) {
581e9e688e2SHidetoshi Shimokawa 		/* XXX */
58210d3ed64SHidetoshi Shimokawa 		printf("%s: xfer->resp = %d\n", __func__, xfer->resp);
583e9e688e2SHidetoshi Shimokawa 	}
584e9e688e2SHidetoshi Shimokawa 	free(orbi, M_SBP_TARG);
585e9e688e2SHidetoshi Shimokawa 	fw_xfer_free(xfer);
586e9e688e2SHidetoshi Shimokawa }
587e9e688e2SHidetoshi Shimokawa 
588e9e688e2SHidetoshi Shimokawa static void
589e9e688e2SHidetoshi Shimokawa sbp_targ_status_FIFO(struct orb_info *orbi,
59003161bbcSDoug Rabson     uint32_t fifo_hi, uint32_t fifo_lo, int dequeue)
591e9e688e2SHidetoshi Shimokawa {
592e9e688e2SHidetoshi Shimokawa 	struct fw_xfer *xfer;
593e9e688e2SHidetoshi Shimokawa 
594e9e688e2SHidetoshi Shimokawa 	if (dequeue)
595a73ff510SHidetoshi Shimokawa 		sbp_targ_remove_orb_info(orbi->login, orbi);
596e9e688e2SHidetoshi Shimokawa 
597e9e688e2SHidetoshi Shimokawa 	xfer = fwmem_write_block(orbi->fwdev, (void *)orbi,
598e9e688e2SHidetoshi Shimokawa 	    /*spd*/2, fifo_hi, fifo_lo,
59903161bbcSDoug Rabson 	    sizeof(uint32_t) * (orbi->status.len + 1), (char *)&orbi->status,
600e9e688e2SHidetoshi Shimokawa 	    sbp_targ_free_orbi);
601e9e688e2SHidetoshi Shimokawa 
602e9e688e2SHidetoshi Shimokawa 	if (xfer == NULL) {
603e9e688e2SHidetoshi Shimokawa 		/* XXX */
60410d3ed64SHidetoshi Shimokawa 		printf("%s: xfer == NULL\n", __func__);
605e9e688e2SHidetoshi Shimokawa 	}
606e9e688e2SHidetoshi Shimokawa }
607e9e688e2SHidetoshi Shimokawa 
608e9e688e2SHidetoshi Shimokawa static void
609e9e688e2SHidetoshi Shimokawa sbp_targ_send_status(struct orb_info *orbi, union ccb *ccb)
610e9e688e2SHidetoshi Shimokawa {
611e9e688e2SHidetoshi Shimokawa 	struct sbp_status *sbp_status;
612ea47b6c8SMatt Jacob #if	0
6139950b741SHidetoshi Shimokawa 	struct orb_info *norbi;
614ea47b6c8SMatt Jacob #endif
615e9e688e2SHidetoshi Shimokawa 
616e9e688e2SHidetoshi Shimokawa 	sbp_status = &orbi->status;
617e9e688e2SHidetoshi Shimokawa 
618e9e688e2SHidetoshi Shimokawa 	orbi->state = ORBI_STATUS_STATUS;
619e9e688e2SHidetoshi Shimokawa 
620e9e688e2SHidetoshi Shimokawa 	sbp_status->resp = 0; /* XXX */
621e9e688e2SHidetoshi Shimokawa 	sbp_status->status = 0; /* XXX */
622e9e688e2SHidetoshi Shimokawa 	sbp_status->dead = 0; /* XXX */
623e9e688e2SHidetoshi Shimokawa 
624e9e688e2SHidetoshi Shimokawa 	switch (ccb->csio.scsi_status) {
625e9e688e2SHidetoshi Shimokawa 	case SCSI_STATUS_OK:
626e9e688e2SHidetoshi Shimokawa 		if (debug)
62710d3ed64SHidetoshi Shimokawa 			printf("%s: STATUS_OK\n", __func__);
628e9e688e2SHidetoshi Shimokawa 		sbp_status->len = 1;
629e9e688e2SHidetoshi Shimokawa 		break;
630e9e688e2SHidetoshi Shimokawa 	case SCSI_STATUS_CHECK_COND:
631e9e688e2SHidetoshi Shimokawa 	case SCSI_STATUS_BUSY:
632e9e688e2SHidetoshi Shimokawa 	case SCSI_STATUS_CMD_TERMINATED:
633e9e688e2SHidetoshi Shimokawa 	{
634e9e688e2SHidetoshi Shimokawa 		struct sbp_cmd_status *sbp_cmd_status;
635e9e688e2SHidetoshi Shimokawa 		struct scsi_sense_data *sense;
636*1cc052e8SKenneth D. Merry 		int error_code, sense_key, asc, ascq;
637*1cc052e8SKenneth D. Merry 		uint8_t stream_bits;
638*1cc052e8SKenneth D. Merry 		uint8_t sks[3];
639*1cc052e8SKenneth D. Merry 		uint64_t info;
640*1cc052e8SKenneth D. Merry 		int64_t sinfo;
641*1cc052e8SKenneth D. Merry 		int sense_len;
642e9e688e2SHidetoshi Shimokawa 
643e9e688e2SHidetoshi Shimokawa 		if (debug)
64410d3ed64SHidetoshi Shimokawa 			printf("%s: STATUS %d\n", __func__,
645e9e688e2SHidetoshi Shimokawa 			    ccb->csio.scsi_status);
646e9e688e2SHidetoshi Shimokawa 		sbp_cmd_status = (struct sbp_cmd_status *)&sbp_status->data[0];
647e9e688e2SHidetoshi Shimokawa 		sbp_cmd_status->status = ccb->csio.scsi_status;
648e9e688e2SHidetoshi Shimokawa 		sense = &ccb->csio.sense_data;
649e9e688e2SHidetoshi Shimokawa 
6509950b741SHidetoshi Shimokawa #if 0		/* XXX What we should do? */
6519950b741SHidetoshi Shimokawa #if 0
6529950b741SHidetoshi Shimokawa 		sbp_targ_abort(orbi->sc, STAILQ_NEXT(orbi, link));
6539950b741SHidetoshi Shimokawa #else
6549950b741SHidetoshi Shimokawa 		norbi = STAILQ_NEXT(orbi, link);
6559950b741SHidetoshi Shimokawa 		while (norbi) {
6569950b741SHidetoshi Shimokawa 			printf("%s: status=%d\n", __func__, norbi->state);
6579950b741SHidetoshi Shimokawa 			if (norbi->ccb != NULL) {
6589950b741SHidetoshi Shimokawa 				norbi->ccb->ccb_h.status = CAM_REQ_ABORTED;
6599950b741SHidetoshi Shimokawa 				xpt_done(norbi->ccb);
6609950b741SHidetoshi Shimokawa 				norbi->ccb = NULL;
6619950b741SHidetoshi Shimokawa 			}
6629950b741SHidetoshi Shimokawa 			sbp_targ_remove_orb_info_locked(orbi->login, norbi);
6639950b741SHidetoshi Shimokawa 			norbi = STAILQ_NEXT(norbi, link);
6649950b741SHidetoshi Shimokawa 			free(norbi, M_SBP_TARG);
6659950b741SHidetoshi Shimokawa 		}
6669950b741SHidetoshi Shimokawa #endif
6679950b741SHidetoshi Shimokawa #endif
668e9e688e2SHidetoshi Shimokawa 
669*1cc052e8SKenneth D. Merry 		sense_len = ccb->csio.sense_len - ccb->csio.sense_resid;
670*1cc052e8SKenneth D. Merry 		scsi_extract_sense_len(sense, sense_len, &error_code,
671*1cc052e8SKenneth D. Merry 		    &sense_key, &asc, &ascq, /*show_errors*/ 0);
672*1cc052e8SKenneth D. Merry 
673*1cc052e8SKenneth D. Merry 		switch (error_code) {
674*1cc052e8SKenneth D. Merry 		case SSD_CURRENT_ERROR:
675*1cc052e8SKenneth D. Merry 		case SSD_DESC_CURRENT_ERROR:
676e9e688e2SHidetoshi Shimokawa 			sbp_cmd_status->sfmt = SBP_SFMT_CURR;
677*1cc052e8SKenneth D. Merry 			break;
678*1cc052e8SKenneth D. Merry 		default:
679e9e688e2SHidetoshi Shimokawa 			sbp_cmd_status->sfmt = SBP_SFMT_DEFER;
680*1cc052e8SKenneth D. Merry 			break;
681*1cc052e8SKenneth D. Merry 		}
682e9e688e2SHidetoshi Shimokawa 
683*1cc052e8SKenneth D. Merry 		if (scsi_get_sense_info(sense, sense_len, SSD_DESC_INFO, &info,
684*1cc052e8SKenneth D. Merry 					&sinfo) == 0) {
685*1cc052e8SKenneth D. Merry 			uint32_t info_trunc;
686*1cc052e8SKenneth D. Merry 			sbp_cmd_status->valid = 1;
687*1cc052e8SKenneth D. Merry 			info_trunc = info;
688e9e688e2SHidetoshi Shimokawa 
689*1cc052e8SKenneth D. Merry 			sbp_cmd_status->info = htobe32(info_trunc);
690*1cc052e8SKenneth D. Merry 		} else {
691*1cc052e8SKenneth D. Merry 			sbp_cmd_status->valid = 0;
692*1cc052e8SKenneth D. Merry 		}
693e9e688e2SHidetoshi Shimokawa 
694*1cc052e8SKenneth D. Merry 		sbp_cmd_status->s_key = sense_key;
695*1cc052e8SKenneth D. Merry 
696*1cc052e8SKenneth D. Merry 		if (scsi_get_stream_info(sense, sense_len, NULL,
697*1cc052e8SKenneth D. Merry 					 &stream_bits) == 0) {
698*1cc052e8SKenneth D. Merry 			sbp_cmd_status->mark =
699*1cc052e8SKenneth D. Merry 			    (stream_bits & SSD_FILEMARK) ? 1 : 0;
700*1cc052e8SKenneth D. Merry 			sbp_cmd_status->eom =
701*1cc052e8SKenneth D. Merry 			    (stream_bits & SSD_EOM) ? 1 : 0;
702*1cc052e8SKenneth D. Merry 			sbp_cmd_status->ill_len =
703*1cc052e8SKenneth D. Merry 			    (stream_bits & SSD_ILI) ? 1 : 0;
704*1cc052e8SKenneth D. Merry 		} else {
705*1cc052e8SKenneth D. Merry 			sbp_cmd_status->mark = 0;
706*1cc052e8SKenneth D. Merry 			sbp_cmd_status->eom = 0;
707*1cc052e8SKenneth D. Merry 			sbp_cmd_status->ill_len = 0;
708*1cc052e8SKenneth D. Merry 		}
709*1cc052e8SKenneth D. Merry 
710*1cc052e8SKenneth D. Merry 
711e9e688e2SHidetoshi Shimokawa 		/* add_sense_code(_qual), info, cmd_spec_info */
712e9e688e2SHidetoshi Shimokawa 		sbp_status->len = 4;
713*1cc052e8SKenneth D. Merry 
714*1cc052e8SKenneth D. Merry 		if (scsi_get_sense_info(sense, sense_len, SSD_DESC_COMMAND,
715*1cc052e8SKenneth D. Merry 					&info, &sinfo) == 0) {
716*1cc052e8SKenneth D. Merry 			uint32_t cmdspec_trunc;
717*1cc052e8SKenneth D. Merry 
718*1cc052e8SKenneth D. Merry 			cmdspec_trunc = info;
719*1cc052e8SKenneth D. Merry 
720*1cc052e8SKenneth D. Merry 			sbp_cmd_status->cdb = htobe32(cmdspec_trunc);
721*1cc052e8SKenneth D. Merry 		}
722*1cc052e8SKenneth D. Merry 
723*1cc052e8SKenneth D. Merry 		sbp_cmd_status->s_code = asc;
724*1cc052e8SKenneth D. Merry 		sbp_cmd_status->s_qlfr = ascq;
725*1cc052e8SKenneth D. Merry 
726*1cc052e8SKenneth D. Merry 		if (scsi_get_sense_info(sense, sense_len, SSD_DESC_FRU, &info,
727*1cc052e8SKenneth D. Merry 					&sinfo) == 0) {
728*1cc052e8SKenneth D. Merry 			sbp_cmd_status->fru = (uint8_t)info;
729e9e688e2SHidetoshi Shimokawa 			sbp_status->len = 5;
730*1cc052e8SKenneth D. Merry 		} else {
731*1cc052e8SKenneth D. Merry 			sbp_cmd_status->fru = 0;
732*1cc052e8SKenneth D. Merry 		}
733e9e688e2SHidetoshi Shimokawa 
734*1cc052e8SKenneth D. Merry 		if (scsi_get_sks(sense, sense_len, sks) == 0) {
735*1cc052e8SKenneth D. Merry 			bcopy(sks, &sbp_cmd_status->s_keydep[0], sizeof(sks));
736*1cc052e8SKenneth D. Merry 			sbp_status->len = 5;
737*1cc052e8SKenneth D. Merry 		}
738e9e688e2SHidetoshi Shimokawa 
739e9e688e2SHidetoshi Shimokawa 		break;
740e9e688e2SHidetoshi Shimokawa 	}
741e9e688e2SHidetoshi Shimokawa 	default:
74210d3ed64SHidetoshi Shimokawa 		printf("%s: unknown scsi status 0x%x\n", __func__,
743e9e688e2SHidetoshi Shimokawa 		    sbp_status->status);
744e9e688e2SHidetoshi Shimokawa 	}
745e9e688e2SHidetoshi Shimokawa 
746e9e688e2SHidetoshi Shimokawa 	if (orbi->page_table != NULL)
747e9e688e2SHidetoshi Shimokawa 		free(orbi->page_table, M_SBP_TARG);
7489950b741SHidetoshi Shimokawa 
7499950b741SHidetoshi Shimokawa 	sbp_targ_status_FIFO(orbi,
7509950b741SHidetoshi Shimokawa 	    orbi->login->fifo_hi, orbi->login->fifo_lo, /*dequeue*/1);
751e9e688e2SHidetoshi Shimokawa }
752e9e688e2SHidetoshi Shimokawa 
753e9e688e2SHidetoshi Shimokawa static void
754e9e688e2SHidetoshi Shimokawa sbp_targ_cam_done(struct fw_xfer *xfer)
755e9e688e2SHidetoshi Shimokawa {
756e9e688e2SHidetoshi Shimokawa 	struct orb_info *orbi;
757e9e688e2SHidetoshi Shimokawa 	union ccb *ccb;
758e9e688e2SHidetoshi Shimokawa 
759e9e688e2SHidetoshi Shimokawa 	orbi = (struct orb_info *)xfer->sc;
760e9e688e2SHidetoshi Shimokawa 
761a73ff510SHidetoshi Shimokawa 	if (debug > 1)
76210d3ed64SHidetoshi Shimokawa 		printf("%s: resp=%d refcount=%d\n", __func__,
763e9e688e2SHidetoshi Shimokawa 			xfer->resp, orbi->refcount);
764e9e688e2SHidetoshi Shimokawa 
765e9e688e2SHidetoshi Shimokawa 	if (xfer->resp != 0) {
76610d3ed64SHidetoshi Shimokawa 		printf("%s: xfer->resp = %d\n", __func__, xfer->resp);
767e9e688e2SHidetoshi Shimokawa 		orbi->status.resp = SBP_TRANS_FAIL;
7681398a889SHidetoshi Shimokawa 		orbi->status.status = OBJ_DATA | SBE_TIMEOUT/*XXX*/;
769e9e688e2SHidetoshi Shimokawa 		orbi->status.dead = 1;
7709950b741SHidetoshi Shimokawa 		sbp_targ_abort(orbi->sc, STAILQ_NEXT(orbi, link));
771e9e688e2SHidetoshi Shimokawa 	}
772e9e688e2SHidetoshi Shimokawa 
773e9e688e2SHidetoshi Shimokawa 	orbi->refcount --;
774e9e688e2SHidetoshi Shimokawa 
775e9e688e2SHidetoshi Shimokawa 	ccb = orbi->ccb;
776e9e688e2SHidetoshi Shimokawa 	if (orbi->refcount == 0) {
7779950b741SHidetoshi Shimokawa 		orbi->ccb = NULL;
778e9e688e2SHidetoshi Shimokawa 		if (orbi->state == ORBI_STATUS_ABORTED) {
779e9e688e2SHidetoshi Shimokawa 			if (debug)
78010d3ed64SHidetoshi Shimokawa 				printf("%s: orbi aborted\n", __func__);
781a73ff510SHidetoshi Shimokawa 			sbp_targ_remove_orb_info(orbi->login, orbi);
782e9e688e2SHidetoshi Shimokawa 			if (orbi->page_table != NULL)
783e9e688e2SHidetoshi Shimokawa 				free(orbi->page_table, M_SBP_TARG);
784e9e688e2SHidetoshi Shimokawa 			free(orbi, M_SBP_TARG);
785e9e688e2SHidetoshi Shimokawa 		} else if (orbi->status.resp == 0) {
786e9e688e2SHidetoshi Shimokawa 			if ((ccb->ccb_h.flags & CAM_SEND_STATUS) != 0)
787e9e688e2SHidetoshi Shimokawa 				sbp_targ_send_status(orbi, ccb);
788e9e688e2SHidetoshi Shimokawa 			ccb->ccb_h.status = CAM_REQ_CMP;
7899950b741SHidetoshi Shimokawa 			SBP_LOCK(orbi->sc);
790e9e688e2SHidetoshi Shimokawa 			xpt_done(ccb);
7919950b741SHidetoshi Shimokawa 			SBP_UNLOCK(orbi->sc);
792e9e688e2SHidetoshi Shimokawa 		} else {
793e9e688e2SHidetoshi Shimokawa 			orbi->status.len = 1;
794e9e688e2SHidetoshi Shimokawa 			sbp_targ_status_FIFO(orbi,
795a73ff510SHidetoshi Shimokawa 		    	    orbi->login->fifo_hi, orbi->login->fifo_lo,
796e9e688e2SHidetoshi Shimokawa 			    /*dequeue*/1);
797e9e688e2SHidetoshi Shimokawa 			ccb->ccb_h.status = CAM_REQ_ABORTED;
7989950b741SHidetoshi Shimokawa 			SBP_LOCK(orbi->sc);
799e9e688e2SHidetoshi Shimokawa 			xpt_done(ccb);
8009950b741SHidetoshi Shimokawa 			SBP_UNLOCK(orbi->sc);
801e9e688e2SHidetoshi Shimokawa 		}
802e9e688e2SHidetoshi Shimokawa 	}
803e9e688e2SHidetoshi Shimokawa 
804e9e688e2SHidetoshi Shimokawa 	fw_xfer_free(xfer);
805e9e688e2SHidetoshi Shimokawa }
806e9e688e2SHidetoshi Shimokawa 
807e9e688e2SHidetoshi Shimokawa static cam_status
808e9e688e2SHidetoshi Shimokawa sbp_targ_abort_ccb(struct sbp_targ_softc *sc, union ccb *ccb)
809e9e688e2SHidetoshi Shimokawa {
810e9e688e2SHidetoshi Shimokawa 	union ccb *accb;
811e9e688e2SHidetoshi Shimokawa 	struct sbp_targ_lstate *lstate;
812e9e688e2SHidetoshi Shimokawa 	struct ccb_hdr_slist *list;
813e9e688e2SHidetoshi Shimokawa 	struct ccb_hdr *curelm;
814e9e688e2SHidetoshi Shimokawa 	int found;
815e9e688e2SHidetoshi Shimokawa 	cam_status status;
816e9e688e2SHidetoshi Shimokawa 
817e9e688e2SHidetoshi Shimokawa 	status = sbp_targ_find_devs(sc, ccb, &lstate, 0);
818e9e688e2SHidetoshi Shimokawa 	if (status != CAM_REQ_CMP)
819e9e688e2SHidetoshi Shimokawa 		return (status);
820e9e688e2SHidetoshi Shimokawa 
821e9e688e2SHidetoshi Shimokawa 	accb = ccb->cab.abort_ccb;
822e9e688e2SHidetoshi Shimokawa 
823e9e688e2SHidetoshi Shimokawa 	if (accb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO)
824e9e688e2SHidetoshi Shimokawa 		list = &lstate->accept_tios;
825e9e688e2SHidetoshi Shimokawa 	else if (accb->ccb_h.func_code == XPT_IMMED_NOTIFY)
826e9e688e2SHidetoshi Shimokawa 		list = &lstate->immed_notifies;
827e9e688e2SHidetoshi Shimokawa 	else
828e9e688e2SHidetoshi Shimokawa 		return (CAM_UA_ABORT);
829e9e688e2SHidetoshi Shimokawa 
830e9e688e2SHidetoshi Shimokawa 	curelm = SLIST_FIRST(list);
831e9e688e2SHidetoshi Shimokawa 	found = 0;
832e9e688e2SHidetoshi Shimokawa 	if (curelm == &accb->ccb_h) {
833e9e688e2SHidetoshi Shimokawa 		found = 1;
834e9e688e2SHidetoshi Shimokawa 		SLIST_REMOVE_HEAD(list, sim_links.sle);
835e9e688e2SHidetoshi Shimokawa 	} else {
836e9e688e2SHidetoshi Shimokawa 		while(curelm != NULL) {
837e9e688e2SHidetoshi Shimokawa 			struct ccb_hdr *nextelm;
838e9e688e2SHidetoshi Shimokawa 
839e9e688e2SHidetoshi Shimokawa 			nextelm = SLIST_NEXT(curelm, sim_links.sle);
840e9e688e2SHidetoshi Shimokawa 			if (nextelm == &accb->ccb_h) {
841e9e688e2SHidetoshi Shimokawa 				found = 1;
842e9e688e2SHidetoshi Shimokawa 				SLIST_NEXT(curelm, sim_links.sle) =
843e9e688e2SHidetoshi Shimokawa 				    SLIST_NEXT(nextelm, sim_links.sle);
844e9e688e2SHidetoshi Shimokawa 				break;
845e9e688e2SHidetoshi Shimokawa 			}
846e9e688e2SHidetoshi Shimokawa 			curelm = nextelm;
847e9e688e2SHidetoshi Shimokawa 		}
848e9e688e2SHidetoshi Shimokawa 	}
849e9e688e2SHidetoshi Shimokawa 	if (found) {
850e9e688e2SHidetoshi Shimokawa 		accb->ccb_h.status = CAM_REQ_ABORTED;
851e9e688e2SHidetoshi Shimokawa 		xpt_done(accb);
852e9e688e2SHidetoshi Shimokawa 		return (CAM_REQ_CMP);
853e9e688e2SHidetoshi Shimokawa 	}
85410d3ed64SHidetoshi Shimokawa 	printf("%s: not found\n", __func__);
855e9e688e2SHidetoshi Shimokawa 	return (CAM_PATH_INVALID);
856e9e688e2SHidetoshi Shimokawa }
857e9e688e2SHidetoshi Shimokawa 
858e9e688e2SHidetoshi Shimokawa static void
859e9e688e2SHidetoshi Shimokawa sbp_targ_xfer_buf(struct orb_info *orbi, u_int offset,
86003161bbcSDoug Rabson     uint16_t dst_hi, uint32_t dst_lo, u_int size,
861e9e688e2SHidetoshi Shimokawa     void (*hand)(struct fw_xfer *))
862e9e688e2SHidetoshi Shimokawa {
863e9e688e2SHidetoshi Shimokawa 	struct fw_xfer *xfer;
864e9e688e2SHidetoshi Shimokawa 	u_int len, ccb_dir, off = 0;
865e9e688e2SHidetoshi Shimokawa 	char *ptr;
866e9e688e2SHidetoshi Shimokawa 
867a73ff510SHidetoshi Shimokawa 	if (debug > 1)
86810d3ed64SHidetoshi Shimokawa 		printf("%s: offset=%d size=%d\n", __func__, offset, size);
869e9e688e2SHidetoshi Shimokawa 	ccb_dir = orbi->ccb->ccb_h.flags & CAM_DIR_MASK;
870e9e688e2SHidetoshi Shimokawa 	ptr = (char *)orbi->ccb->csio.data_ptr + offset;
871e9e688e2SHidetoshi Shimokawa 
872e9e688e2SHidetoshi Shimokawa 	while (size > 0) {
873e9e688e2SHidetoshi Shimokawa 		/* XXX assume dst_lo + off doesn't overflow */
874e9e688e2SHidetoshi Shimokawa 		len = MIN(size, 2048 /* XXX */);
875e9e688e2SHidetoshi Shimokawa 		size -= len;
876e9e688e2SHidetoshi Shimokawa 		orbi->refcount ++;
877e9e688e2SHidetoshi Shimokawa 		if (ccb_dir == CAM_DIR_OUT)
878e9e688e2SHidetoshi Shimokawa 			xfer = fwmem_read_block(orbi->fwdev,
879e9e688e2SHidetoshi Shimokawa 			   (void *)orbi, /*spd*/2,
880e9e688e2SHidetoshi Shimokawa 			    dst_hi, dst_lo + off, len,
881e9e688e2SHidetoshi Shimokawa 			    ptr + off, hand);
882e9e688e2SHidetoshi Shimokawa 		else
883e9e688e2SHidetoshi Shimokawa 			xfer = fwmem_write_block(orbi->fwdev,
884e9e688e2SHidetoshi Shimokawa 			   (void *)orbi, /*spd*/2,
885e9e688e2SHidetoshi Shimokawa 			    dst_hi, dst_lo + off, len,
886e9e688e2SHidetoshi Shimokawa 			    ptr + off, hand);
887e9e688e2SHidetoshi Shimokawa 		if (xfer == NULL) {
88810d3ed64SHidetoshi Shimokawa 			printf("%s: xfer == NULL", __func__);
889e9e688e2SHidetoshi Shimokawa 			/* XXX what should we do?? */
890e9e688e2SHidetoshi Shimokawa 			orbi->refcount --;
891e9e688e2SHidetoshi Shimokawa 		}
892e9e688e2SHidetoshi Shimokawa 		off += len;
893e9e688e2SHidetoshi Shimokawa 	}
894e9e688e2SHidetoshi Shimokawa }
895e9e688e2SHidetoshi Shimokawa 
896e9e688e2SHidetoshi Shimokawa static void
897e9e688e2SHidetoshi Shimokawa sbp_targ_pt_done(struct fw_xfer *xfer)
898e9e688e2SHidetoshi Shimokawa {
899e9e688e2SHidetoshi Shimokawa 	struct orb_info *orbi;
900e9e688e2SHidetoshi Shimokawa 	union ccb *ccb;
901e9e688e2SHidetoshi Shimokawa 	u_int i, offset, res, len;
90203161bbcSDoug Rabson 	uint32_t t1, t2, *p;
903e9e688e2SHidetoshi Shimokawa 
904e9e688e2SHidetoshi Shimokawa 	orbi = (struct orb_info *)xfer->sc;
905e9e688e2SHidetoshi Shimokawa 	ccb = orbi->ccb;
906e9e688e2SHidetoshi Shimokawa 	if (orbi->state == ORBI_STATUS_ABORTED) {
907e9e688e2SHidetoshi Shimokawa 		if (debug)
90810d3ed64SHidetoshi Shimokawa 			printf("%s: orbi aborted\n", __func__);
909a73ff510SHidetoshi Shimokawa 		sbp_targ_remove_orb_info(orbi->login, orbi);
910e9e688e2SHidetoshi Shimokawa 		free(orbi->page_table, M_SBP_TARG);
911e9e688e2SHidetoshi Shimokawa 		free(orbi, M_SBP_TARG);
912e9e688e2SHidetoshi Shimokawa 		fw_xfer_free(xfer);
913e9e688e2SHidetoshi Shimokawa 		return;
914e9e688e2SHidetoshi Shimokawa 	}
915e9e688e2SHidetoshi Shimokawa 	if (xfer->resp != 0) {
91610d3ed64SHidetoshi Shimokawa 		printf("%s: xfer->resp = %d\n", __func__, xfer->resp);
917e9e688e2SHidetoshi Shimokawa 		orbi->status.resp = SBP_TRANS_FAIL;
9181398a889SHidetoshi Shimokawa 		orbi->status.status = OBJ_PT | SBE_TIMEOUT/*XXX*/;
919e9e688e2SHidetoshi Shimokawa 		orbi->status.dead = 1;
920e9e688e2SHidetoshi Shimokawa 		orbi->status.len = 1;
9219950b741SHidetoshi Shimokawa 		sbp_targ_abort(orbi->sc, STAILQ_NEXT(orbi, link));
922e9e688e2SHidetoshi Shimokawa 
923e9e688e2SHidetoshi Shimokawa 		sbp_targ_status_FIFO(orbi,
924a73ff510SHidetoshi Shimokawa 		    orbi->login->fifo_hi, orbi->login->fifo_lo, /*dequeue*/1);
925e9e688e2SHidetoshi Shimokawa 		free(orbi->page_table, M_SBP_TARG);
926e9e688e2SHidetoshi Shimokawa 		fw_xfer_free(xfer);
927e9e688e2SHidetoshi Shimokawa 		return;
928e9e688e2SHidetoshi Shimokawa 	}
929e9e688e2SHidetoshi Shimokawa 	res = ccb->csio.dxfer_len;
930e9e688e2SHidetoshi Shimokawa 	offset = 0;
931e9e688e2SHidetoshi Shimokawa 	if (debug)
93210d3ed64SHidetoshi Shimokawa 		printf("%s: dxfer_len=%d\n", __func__, res);
933e9e688e2SHidetoshi Shimokawa 	orbi->refcount ++;
934e9e688e2SHidetoshi Shimokawa 	for (p = orbi->page_table, i = orbi->orb4.data_size; i > 0; i --) {
935e9e688e2SHidetoshi Shimokawa 		t1 = ntohl(*p++);
936e9e688e2SHidetoshi Shimokawa 		t2 = ntohl(*p++);
937a73ff510SHidetoshi Shimokawa 		if (debug > 1)
938e9e688e2SHidetoshi Shimokawa 			printf("page_table: %04x:%08x %d\n",
939e9e688e2SHidetoshi Shimokawa 			    t1 & 0xffff, t2, t1>>16);
940e9e688e2SHidetoshi Shimokawa 		len = MIN(t1 >> 16, res);
941e9e688e2SHidetoshi Shimokawa 		res -= len;
942e9e688e2SHidetoshi Shimokawa 		sbp_targ_xfer_buf(orbi, offset, t1 & 0xffff, t2, len,
943e9e688e2SHidetoshi Shimokawa 		    sbp_targ_cam_done);
944e9e688e2SHidetoshi Shimokawa 		offset += len;
945e9e688e2SHidetoshi Shimokawa 		if (res == 0)
946e9e688e2SHidetoshi Shimokawa 			break;
947e9e688e2SHidetoshi Shimokawa 	}
948e9e688e2SHidetoshi Shimokawa 	orbi->refcount --;
949e9e688e2SHidetoshi Shimokawa 	if (orbi->refcount == 0)
95010d3ed64SHidetoshi Shimokawa 		printf("%s: refcount == 0\n", __func__);
951e9e688e2SHidetoshi Shimokawa 	if (res !=0)
952e9e688e2SHidetoshi Shimokawa 		/* XXX handle res != 0 case */
95310d3ed64SHidetoshi Shimokawa 		printf("%s: page table is too small(%d)\n", __func__, res);
954e9e688e2SHidetoshi Shimokawa 
955e9e688e2SHidetoshi Shimokawa 	fw_xfer_free(xfer);
956e9e688e2SHidetoshi Shimokawa 	return;
957e9e688e2SHidetoshi Shimokawa }
958e9e688e2SHidetoshi Shimokawa 
959e9e688e2SHidetoshi Shimokawa static void
960e9e688e2SHidetoshi Shimokawa sbp_targ_fetch_pt(struct orb_info *orbi)
961e9e688e2SHidetoshi Shimokawa {
962e9e688e2SHidetoshi Shimokawa 	struct fw_xfer *xfer;
963e9e688e2SHidetoshi Shimokawa 
964e9e688e2SHidetoshi Shimokawa 	if (debug)
965e9e688e2SHidetoshi Shimokawa 		printf("%s: page_table_size=%d\n",
96610d3ed64SHidetoshi Shimokawa 		    __func__, orbi->orb4.data_size);
967e9e688e2SHidetoshi Shimokawa 	orbi->page_table = malloc(orbi->orb4.data_size*8, M_SBP_TARG, M_NOWAIT);
968e9e688e2SHidetoshi Shimokawa 	if (orbi->page_table == NULL)
969e9e688e2SHidetoshi Shimokawa 		goto error;
970e9e688e2SHidetoshi Shimokawa 	xfer = fwmem_read_block(orbi->fwdev, (void *)orbi, /*spd*/2,
971e9e688e2SHidetoshi Shimokawa 		    orbi->data_hi, orbi->data_lo, orbi->orb4.data_size*8,
972e9e688e2SHidetoshi Shimokawa 			    (void *)orbi->page_table, sbp_targ_pt_done);
973e9e688e2SHidetoshi Shimokawa 	if (xfer != NULL)
974e9e688e2SHidetoshi Shimokawa 		return;
975e9e688e2SHidetoshi Shimokawa error:
976e9e688e2SHidetoshi Shimokawa 	orbi->ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
977e9e688e2SHidetoshi Shimokawa 	xpt_done(orbi->ccb);
978e9e688e2SHidetoshi Shimokawa 	return;
979e9e688e2SHidetoshi Shimokawa }
980e9e688e2SHidetoshi Shimokawa 
981e9e688e2SHidetoshi Shimokawa static void
982e9e688e2SHidetoshi Shimokawa sbp_targ_action1(struct cam_sim *sim, union ccb *ccb)
983e9e688e2SHidetoshi Shimokawa {
984e9e688e2SHidetoshi Shimokawa 	struct sbp_targ_softc *sc;
985e9e688e2SHidetoshi Shimokawa 	struct sbp_targ_lstate *lstate;
986e9e688e2SHidetoshi Shimokawa 	cam_status status;
987e9e688e2SHidetoshi Shimokawa 	u_int ccb_dir;
988e9e688e2SHidetoshi Shimokawa 
989e9e688e2SHidetoshi Shimokawa 	sc =  (struct sbp_targ_softc *)cam_sim_softc(sim);
990e9e688e2SHidetoshi Shimokawa 
991e9e688e2SHidetoshi Shimokawa 	status = sbp_targ_find_devs(sc, ccb, &lstate, TRUE);
992e9e688e2SHidetoshi Shimokawa 
993e9e688e2SHidetoshi Shimokawa 	switch (ccb->ccb_h.func_code) {
994e9e688e2SHidetoshi Shimokawa 	case XPT_CONT_TARGET_IO:
995e9e688e2SHidetoshi Shimokawa 	{
996e9e688e2SHidetoshi Shimokawa 		struct orb_info *orbi;
997e9e688e2SHidetoshi Shimokawa 
998e9e688e2SHidetoshi Shimokawa 		if (debug)
9999950b741SHidetoshi Shimokawa 			printf("%s: XPT_CONT_TARGET_IO (0x%08x)\n",
10009950b741SHidetoshi Shimokawa 					 __func__, ccb->csio.tag_id);
1001e9e688e2SHidetoshi Shimokawa 
1002e9e688e2SHidetoshi Shimokawa 		if (status != CAM_REQ_CMP) {
1003e9e688e2SHidetoshi Shimokawa 			ccb->ccb_h.status = status;
1004e9e688e2SHidetoshi Shimokawa 			xpt_done(ccb);
1005e9e688e2SHidetoshi Shimokawa 			break;
1006e9e688e2SHidetoshi Shimokawa 		}
1007e9e688e2SHidetoshi Shimokawa 		/* XXX transfer from/to initiator */
1008e9e688e2SHidetoshi Shimokawa 		orbi = sbp_targ_get_orb_info(lstate,
1009e9e688e2SHidetoshi Shimokawa 		    ccb->csio.tag_id, ccb->csio.init_id);
1010e9e688e2SHidetoshi Shimokawa 		if (orbi == NULL) {
1011e9e688e2SHidetoshi Shimokawa 			ccb->ccb_h.status = CAM_REQ_ABORTED; /* XXX */
1012e9e688e2SHidetoshi Shimokawa 			xpt_done(ccb);
1013e9e688e2SHidetoshi Shimokawa 			break;
1014e9e688e2SHidetoshi Shimokawa 		}
1015e9e688e2SHidetoshi Shimokawa 		if (orbi->state == ORBI_STATUS_ABORTED) {
1016e9e688e2SHidetoshi Shimokawa 			if (debug)
101710d3ed64SHidetoshi Shimokawa 				printf("%s: ctio aborted\n", __func__);
10189950b741SHidetoshi Shimokawa 			sbp_targ_remove_orb_info_locked(orbi->login, orbi);
1019e9e688e2SHidetoshi Shimokawa 			free(orbi, M_SBP_TARG);
10209950b741SHidetoshi Shimokawa 			ccb->ccb_h.status = CAM_REQ_ABORTED;
10219950b741SHidetoshi Shimokawa 			xpt_done(ccb);
1022e9e688e2SHidetoshi Shimokawa 			break;
1023e9e688e2SHidetoshi Shimokawa 		}
1024e9e688e2SHidetoshi Shimokawa 		orbi->state = ORBI_STATUS_CTIO;
1025e9e688e2SHidetoshi Shimokawa 
1026e9e688e2SHidetoshi Shimokawa 		orbi->ccb = ccb;
1027e9e688e2SHidetoshi Shimokawa 		ccb_dir = ccb->ccb_h.flags & CAM_DIR_MASK;
1028e9e688e2SHidetoshi Shimokawa 
1029e9e688e2SHidetoshi Shimokawa 		/* XXX */
1030e9e688e2SHidetoshi Shimokawa 		if (ccb->csio.dxfer_len == 0)
1031e9e688e2SHidetoshi Shimokawa 			ccb_dir = CAM_DIR_NONE;
1032e9e688e2SHidetoshi Shimokawa 
1033e9e688e2SHidetoshi Shimokawa 		/* Sanity check */
1034e9e688e2SHidetoshi Shimokawa 		if (ccb_dir == CAM_DIR_IN && orbi->orb4.dir == 0)
103510d3ed64SHidetoshi Shimokawa 			printf("%s: direction mismatch\n", __func__);
1036e9e688e2SHidetoshi Shimokawa 
1037e9e688e2SHidetoshi Shimokawa 		/* check page table */
1038e9e688e2SHidetoshi Shimokawa 		if (ccb_dir != CAM_DIR_NONE && orbi->orb4.page_table_present) {
1039e9e688e2SHidetoshi Shimokawa 			if (debug)
1040e9e688e2SHidetoshi Shimokawa 				printf("%s: page_table_present\n",
104110d3ed64SHidetoshi Shimokawa 				    __func__);
1042e9e688e2SHidetoshi Shimokawa 			if (orbi->orb4.page_size != 0) {
1043e9e688e2SHidetoshi Shimokawa 				printf("%s: unsupported pagesize %d != 0\n",
104410d3ed64SHidetoshi Shimokawa 			 	    __func__, orbi->orb4.page_size);
1045e9e688e2SHidetoshi Shimokawa 				ccb->ccb_h.status = CAM_REQ_INVALID;
1046e9e688e2SHidetoshi Shimokawa 				xpt_done(ccb);
1047e9e688e2SHidetoshi Shimokawa 				break;
1048e9e688e2SHidetoshi Shimokawa 			}
1049e9e688e2SHidetoshi Shimokawa 			sbp_targ_fetch_pt(orbi);
1050e9e688e2SHidetoshi Shimokawa 			break;
1051e9e688e2SHidetoshi Shimokawa 		}
1052e9e688e2SHidetoshi Shimokawa 
1053e9e688e2SHidetoshi Shimokawa 		/* Sanity check */
1054e9e688e2SHidetoshi Shimokawa 		if (ccb_dir != CAM_DIR_NONE &&
1055e9e688e2SHidetoshi Shimokawa 		    orbi->orb4.data_size != ccb->csio.dxfer_len)
1056e9e688e2SHidetoshi Shimokawa 			printf("%s: data_size(%d) != dxfer_len(%d)\n",
105710d3ed64SHidetoshi Shimokawa 			    __func__, orbi->orb4.data_size,
1058e9e688e2SHidetoshi Shimokawa 			    ccb->csio.dxfer_len);
1059e9e688e2SHidetoshi Shimokawa 
1060e9e688e2SHidetoshi Shimokawa 		if (ccb_dir != CAM_DIR_NONE)
1061e9e688e2SHidetoshi Shimokawa 			sbp_targ_xfer_buf(orbi, 0, orbi->data_hi,
1062e9e688e2SHidetoshi Shimokawa 			    orbi->data_lo,
1063e9e688e2SHidetoshi Shimokawa 			    MIN(orbi->orb4.data_size, ccb->csio.dxfer_len),
1064e9e688e2SHidetoshi Shimokawa 			    sbp_targ_cam_done);
1065e9e688e2SHidetoshi Shimokawa 
1066e9e688e2SHidetoshi Shimokawa 		if (ccb_dir == CAM_DIR_NONE) {
10679950b741SHidetoshi Shimokawa 			if ((ccb->ccb_h.flags & CAM_SEND_STATUS) != 0) {
10689950b741SHidetoshi Shimokawa 				/* XXX */
10699950b741SHidetoshi Shimokawa 				SBP_UNLOCK(sc);
1070e9e688e2SHidetoshi Shimokawa 				sbp_targ_send_status(orbi, ccb);
10719950b741SHidetoshi Shimokawa 				SBP_LOCK(sc);
10729950b741SHidetoshi Shimokawa 			}
1073e9e688e2SHidetoshi Shimokawa 			ccb->ccb_h.status = CAM_REQ_CMP;
1074e9e688e2SHidetoshi Shimokawa 			xpt_done(ccb);
1075e9e688e2SHidetoshi Shimokawa 		}
1076e9e688e2SHidetoshi Shimokawa 		break;
1077e9e688e2SHidetoshi Shimokawa 	}
1078e9e688e2SHidetoshi Shimokawa 	case XPT_ACCEPT_TARGET_IO:	/* Add Accept Target IO Resource */
1079e9e688e2SHidetoshi Shimokawa 		if (status != CAM_REQ_CMP) {
1080e9e688e2SHidetoshi Shimokawa 			ccb->ccb_h.status = status;
1081e9e688e2SHidetoshi Shimokawa 			xpt_done(ccb);
1082e9e688e2SHidetoshi Shimokawa 			break;
1083e9e688e2SHidetoshi Shimokawa 		}
1084e9e688e2SHidetoshi Shimokawa 		SLIST_INSERT_HEAD(&lstate->accept_tios, &ccb->ccb_h,
1085e9e688e2SHidetoshi Shimokawa 		    sim_links.sle);
1086e9e688e2SHidetoshi Shimokawa 		ccb->ccb_h.status = CAM_REQ_INPROG;
1087a73ff510SHidetoshi Shimokawa 		if ((lstate->flags & F_ATIO_STARVED) != 0) {
1088a73ff510SHidetoshi Shimokawa 			struct sbp_targ_login *login;
1089a73ff510SHidetoshi Shimokawa 
1090e9e688e2SHidetoshi Shimokawa 			if (debug)
109110d3ed64SHidetoshi Shimokawa 				printf("%s: new atio arrived\n", __func__);
1092a73ff510SHidetoshi Shimokawa 			lstate->flags &= ~F_ATIO_STARVED;
1093a73ff510SHidetoshi Shimokawa 			STAILQ_FOREACH(login, &lstate->logins, link)
1094a73ff510SHidetoshi Shimokawa 				if ((login->flags & F_ATIO_STARVED) != 0) {
1095a73ff510SHidetoshi Shimokawa 					login->flags &= ~F_ATIO_STARVED;
1096a73ff510SHidetoshi Shimokawa 					sbp_targ_fetch_orb(lstate->sc,
1097a73ff510SHidetoshi Shimokawa 					    login->fwdev,
1098a73ff510SHidetoshi Shimokawa 					    login->last_hi, login->last_lo,
1099a73ff510SHidetoshi Shimokawa 					    login, FETCH_CMD);
1100a73ff510SHidetoshi Shimokawa 				}
1101e9e688e2SHidetoshi Shimokawa 		}
1102e9e688e2SHidetoshi Shimokawa 		break;
1103e9e688e2SHidetoshi Shimokawa 	case XPT_NOTIFY_ACK:		/* recycle notify ack */
1104e9e688e2SHidetoshi Shimokawa 	case XPT_IMMED_NOTIFY:		/* Add Immediate Notify Resource */
1105e9e688e2SHidetoshi Shimokawa 		if (status != CAM_REQ_CMP) {
1106e9e688e2SHidetoshi Shimokawa 			ccb->ccb_h.status = status;
1107e9e688e2SHidetoshi Shimokawa 			xpt_done(ccb);
1108e9e688e2SHidetoshi Shimokawa 			break;
1109e9e688e2SHidetoshi Shimokawa 		}
1110e9e688e2SHidetoshi Shimokawa 		SLIST_INSERT_HEAD(&lstate->immed_notifies, &ccb->ccb_h,
1111e9e688e2SHidetoshi Shimokawa 		    sim_links.sle);
1112e9e688e2SHidetoshi Shimokawa 		ccb->ccb_h.status = CAM_REQ_INPROG;
1113e9e688e2SHidetoshi Shimokawa 		sbp_targ_send_lstate_events(sc, lstate);
1114e9e688e2SHidetoshi Shimokawa 		break;
1115e9e688e2SHidetoshi Shimokawa 	case XPT_EN_LUN:
1116e9e688e2SHidetoshi Shimokawa 		sbp_targ_en_lun(sc, ccb);
1117e9e688e2SHidetoshi Shimokawa 		xpt_done(ccb);
1118e9e688e2SHidetoshi Shimokawa 		break;
1119e9e688e2SHidetoshi Shimokawa 	case XPT_PATH_INQ:
1120e9e688e2SHidetoshi Shimokawa 	{
1121e9e688e2SHidetoshi Shimokawa 		struct ccb_pathinq *cpi = &ccb->cpi;
1122e9e688e2SHidetoshi Shimokawa 
1123e9e688e2SHidetoshi Shimokawa 		cpi->version_num = 1; /* XXX??? */
1124e9e688e2SHidetoshi Shimokawa 		cpi->hba_inquiry = PI_TAG_ABLE;
1125e9e688e2SHidetoshi Shimokawa 		cpi->target_sprt = PIT_PROCESSOR
1126e9e688e2SHidetoshi Shimokawa 				 | PIT_DISCONNECT
1127e9e688e2SHidetoshi Shimokawa 				 | PIT_TERM_IO;
1128e9e688e2SHidetoshi Shimokawa 		cpi->hba_misc = PIM_NOBUSRESET | PIM_NO_6_BYTE;
1129e9e688e2SHidetoshi Shimokawa 		cpi->hba_eng_cnt = 0;
1130e9e688e2SHidetoshi Shimokawa 		cpi->max_target = 7; /* XXX */
1131e9e688e2SHidetoshi Shimokawa 		cpi->max_lun = MAX_LUN - 1;
1132e9e688e2SHidetoshi Shimokawa 		cpi->initiator_id = 7; /* XXX */
1133e9e688e2SHidetoshi Shimokawa 		cpi->bus_id = sim->bus_id;
1134e9e688e2SHidetoshi Shimokawa 		cpi->base_transfer_speed = 400 * 1000 / 8;
1135e9e688e2SHidetoshi Shimokawa 		strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
1136e9e688e2SHidetoshi Shimokawa 		strncpy(cpi->hba_vid, "SBP_TARG", HBA_IDLEN);
1137e9e688e2SHidetoshi Shimokawa 		strncpy(cpi->dev_name, sim->sim_name, DEV_IDLEN);
1138e9e688e2SHidetoshi Shimokawa 		cpi->unit_number = sim->unit_number;
1139e9e688e2SHidetoshi Shimokawa 
1140e9e688e2SHidetoshi Shimokawa 		cpi->ccb_h.status = CAM_REQ_CMP;
1141e9e688e2SHidetoshi Shimokawa 		xpt_done(ccb);
1142e9e688e2SHidetoshi Shimokawa 		break;
1143e9e688e2SHidetoshi Shimokawa 	}
1144e9e688e2SHidetoshi Shimokawa 	case XPT_ABORT:
1145e9e688e2SHidetoshi Shimokawa 	{
1146e9e688e2SHidetoshi Shimokawa 		union ccb *accb = ccb->cab.abort_ccb;
1147e9e688e2SHidetoshi Shimokawa 
1148e9e688e2SHidetoshi Shimokawa 		switch (accb->ccb_h.func_code) {
1149e9e688e2SHidetoshi Shimokawa 		case XPT_ACCEPT_TARGET_IO:
1150e9e688e2SHidetoshi Shimokawa 		case XPT_IMMED_NOTIFY:
1151e9e688e2SHidetoshi Shimokawa 			ccb->ccb_h.status = sbp_targ_abort_ccb(sc, ccb);
1152e9e688e2SHidetoshi Shimokawa 			break;
1153e9e688e2SHidetoshi Shimokawa 		case XPT_CONT_TARGET_IO:
1154e9e688e2SHidetoshi Shimokawa 			/* XXX */
1155e9e688e2SHidetoshi Shimokawa 			ccb->ccb_h.status = CAM_UA_ABORT;
1156e9e688e2SHidetoshi Shimokawa 			break;
1157e9e688e2SHidetoshi Shimokawa 		default:
1158e9e688e2SHidetoshi Shimokawa 			printf("%s: aborting unknown function %d\n",
115910d3ed64SHidetoshi Shimokawa 				__func__, accb->ccb_h.func_code);
1160e9e688e2SHidetoshi Shimokawa 			ccb->ccb_h.status = CAM_REQ_INVALID;
1161e9e688e2SHidetoshi Shimokawa 			break;
1162e9e688e2SHidetoshi Shimokawa 		}
1163e9e688e2SHidetoshi Shimokawa 		xpt_done(ccb);
1164e9e688e2SHidetoshi Shimokawa 		break;
1165e9e688e2SHidetoshi Shimokawa 	}
1166e9e688e2SHidetoshi Shimokawa 	default:
1167e9e688e2SHidetoshi Shimokawa 		printf("%s: unknown function %d\n",
116810d3ed64SHidetoshi Shimokawa 		    __func__, ccb->ccb_h.func_code);
1169e9e688e2SHidetoshi Shimokawa 		ccb->ccb_h.status = CAM_REQ_INVALID;
1170e9e688e2SHidetoshi Shimokawa 		xpt_done(ccb);
1171e9e688e2SHidetoshi Shimokawa 		break;
1172e9e688e2SHidetoshi Shimokawa 	}
1173e9e688e2SHidetoshi Shimokawa 	return;
1174e9e688e2SHidetoshi Shimokawa }
1175e9e688e2SHidetoshi Shimokawa 
1176e9e688e2SHidetoshi Shimokawa static void
1177e9e688e2SHidetoshi Shimokawa sbp_targ_action(struct cam_sim *sim, union ccb *ccb)
1178e9e688e2SHidetoshi Shimokawa {
1179e9e688e2SHidetoshi Shimokawa 	int s;
1180e9e688e2SHidetoshi Shimokawa 
1181e9e688e2SHidetoshi Shimokawa 	s = splfw();
1182e9e688e2SHidetoshi Shimokawa 	sbp_targ_action1(sim, ccb);
1183e9e688e2SHidetoshi Shimokawa 	splx(s);
1184e9e688e2SHidetoshi Shimokawa }
1185e9e688e2SHidetoshi Shimokawa 
1186e9e688e2SHidetoshi Shimokawa static void
1187e9e688e2SHidetoshi Shimokawa sbp_targ_poll(struct cam_sim *sim)
1188e9e688e2SHidetoshi Shimokawa {
1189e9e688e2SHidetoshi Shimokawa 	/* XXX */
1190e9e688e2SHidetoshi Shimokawa 	return;
1191e9e688e2SHidetoshi Shimokawa }
1192e9e688e2SHidetoshi Shimokawa 
1193e9e688e2SHidetoshi Shimokawa static void
1194e9e688e2SHidetoshi Shimokawa sbp_targ_cmd_handler(struct fw_xfer *xfer)
1195e9e688e2SHidetoshi Shimokawa {
1196e9e688e2SHidetoshi Shimokawa 	struct fw_pkt *fp;
119703161bbcSDoug Rabson 	uint32_t *orb;
1198e9e688e2SHidetoshi Shimokawa 	struct corb4 *orb4;
1199e9e688e2SHidetoshi Shimokawa 	struct orb_info *orbi;
1200e9e688e2SHidetoshi Shimokawa 	struct ccb_accept_tio *atio;
1201e9e688e2SHidetoshi Shimokawa 	u_char *bytes;
1202e9e688e2SHidetoshi Shimokawa 	int i;
1203e9e688e2SHidetoshi Shimokawa 
1204e9e688e2SHidetoshi Shimokawa 	orbi = (struct orb_info *)xfer->sc;
1205e9e688e2SHidetoshi Shimokawa 	if (xfer->resp != 0) {
120610d3ed64SHidetoshi Shimokawa 		printf("%s: xfer->resp = %d\n", __func__, xfer->resp);
1207e9e688e2SHidetoshi Shimokawa 		orbi->status.resp = SBP_TRANS_FAIL;
12081398a889SHidetoshi Shimokawa 		orbi->status.status = OBJ_ORB | SBE_TIMEOUT/*XXX*/;
1209e9e688e2SHidetoshi Shimokawa 		orbi->status.dead = 1;
1210e9e688e2SHidetoshi Shimokawa 		orbi->status.len = 1;
12119950b741SHidetoshi Shimokawa 		sbp_targ_abort(orbi->sc, STAILQ_NEXT(orbi, link));
1212e9e688e2SHidetoshi Shimokawa 
1213e9e688e2SHidetoshi Shimokawa 		sbp_targ_status_FIFO(orbi,
1214a73ff510SHidetoshi Shimokawa 		    orbi->login->fifo_hi, orbi->login->fifo_lo, /*dequeue*/1);
1215e9e688e2SHidetoshi Shimokawa 		fw_xfer_free(xfer);
1216e9e688e2SHidetoshi Shimokawa 		return;
1217e9e688e2SHidetoshi Shimokawa 	}
1218e9e688e2SHidetoshi Shimokawa 	fp = &xfer->recv.hdr;
1219e9e688e2SHidetoshi Shimokawa 
12209950b741SHidetoshi Shimokawa 	atio = orbi->atio;
12219950b741SHidetoshi Shimokawa 
1222e9e688e2SHidetoshi Shimokawa 	if (orbi->state == ORBI_STATUS_ABORTED) {
122310d3ed64SHidetoshi Shimokawa 		printf("%s: aborted\n", __func__);
1224a73ff510SHidetoshi Shimokawa 		sbp_targ_remove_orb_info(orbi->login, orbi);
1225e9e688e2SHidetoshi Shimokawa 		free(orbi, M_SBP_TARG);
12269950b741SHidetoshi Shimokawa 		atio->ccb_h.status = CAM_REQ_ABORTED;
12279950b741SHidetoshi Shimokawa 		SBP_LOCK(orbi->sc);
12289950b741SHidetoshi Shimokawa 		xpt_done((union ccb*)atio);
12299950b741SHidetoshi Shimokawa 		SBP_UNLOCK(orbi->sc);
1230e9e688e2SHidetoshi Shimokawa 		goto done0;
1231e9e688e2SHidetoshi Shimokawa 	}
1232e9e688e2SHidetoshi Shimokawa 	orbi->state = ORBI_STATUS_ATIO;
1233e9e688e2SHidetoshi Shimokawa 
1234e9e688e2SHidetoshi Shimokawa 	orb = orbi->orb;
1235e9e688e2SHidetoshi Shimokawa 	/* swap payload except SCSI command */
1236e9e688e2SHidetoshi Shimokawa 	for (i = 0; i < 5; i ++)
1237e9e688e2SHidetoshi Shimokawa 		orb[i] = ntohl(orb[i]);
1238e9e688e2SHidetoshi Shimokawa 
1239e9e688e2SHidetoshi Shimokawa 	orb4 = (struct corb4 *)&orb[4];
1240e9e688e2SHidetoshi Shimokawa 	if (orb4->rq_fmt != 0) {
1241e9e688e2SHidetoshi Shimokawa 		/* XXX */
124210d3ed64SHidetoshi Shimokawa 		printf("%s: rq_fmt(%d) != 0\n", __func__, orb4->rq_fmt);
1243e9e688e2SHidetoshi Shimokawa 	}
1244e9e688e2SHidetoshi Shimokawa 
1245e9e688e2SHidetoshi Shimokawa 	atio->ccb_h.target_id = 0; /* XXX */
1246a73ff510SHidetoshi Shimokawa 	atio->ccb_h.target_lun = orbi->login->lstate->lun;
1247e9e688e2SHidetoshi Shimokawa 	atio->sense_len = 0;
1248e9e688e2SHidetoshi Shimokawa 	atio->tag_action = 1; /* XXX */
1249e9e688e2SHidetoshi Shimokawa 	atio->tag_id = orbi->orb_lo;
1250a73ff510SHidetoshi Shimokawa 	atio->init_id = orbi->login->id;
1251a73ff510SHidetoshi Shimokawa 
1252e9e688e2SHidetoshi Shimokawa 	atio->ccb_h.flags = CAM_TAG_ACTION_VALID;
12539950b741SHidetoshi Shimokawa 	bytes = (u_char *)&orb[5];
1254e9e688e2SHidetoshi Shimokawa 	if (debug)
12559950b741SHidetoshi Shimokawa 		printf("%s: %p %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
12569950b741SHidetoshi Shimokawa 		    __func__, (void *)atio,
1257e9e688e2SHidetoshi Shimokawa 		    bytes[0], bytes[1], bytes[2], bytes[3], bytes[4],
1258e9e688e2SHidetoshi Shimokawa 		    bytes[5], bytes[6], bytes[7], bytes[8], bytes[9]);
1259e9e688e2SHidetoshi Shimokawa 	switch (bytes[0] >> 5) {
1260e9e688e2SHidetoshi Shimokawa 	case 0:
1261e9e688e2SHidetoshi Shimokawa 		atio->cdb_len = 6;
1262e9e688e2SHidetoshi Shimokawa 		break;
1263e9e688e2SHidetoshi Shimokawa 	case 1:
1264e9e688e2SHidetoshi Shimokawa 	case 2:
1265e9e688e2SHidetoshi Shimokawa 		atio->cdb_len = 10;
1266e9e688e2SHidetoshi Shimokawa 		break;
1267e9e688e2SHidetoshi Shimokawa 	case 4:
1268e9e688e2SHidetoshi Shimokawa 		atio->cdb_len = 16;
1269e9e688e2SHidetoshi Shimokawa 		break;
1270e9e688e2SHidetoshi Shimokawa 	case 5:
1271e9e688e2SHidetoshi Shimokawa 		atio->cdb_len = 12;
1272e9e688e2SHidetoshi Shimokawa 		break;
1273e9e688e2SHidetoshi Shimokawa 	case 3:
1274e9e688e2SHidetoshi Shimokawa 	default:
1275e9e688e2SHidetoshi Shimokawa 		/* Only copy the opcode. */
1276e9e688e2SHidetoshi Shimokawa 		atio->cdb_len = 1;
1277e9e688e2SHidetoshi Shimokawa 		printf("Reserved or VU command code type encountered\n");
1278e9e688e2SHidetoshi Shimokawa 		break;
1279e9e688e2SHidetoshi Shimokawa 	}
1280e9e688e2SHidetoshi Shimokawa 
1281e9e688e2SHidetoshi Shimokawa 	memcpy(atio->cdb_io.cdb_bytes, bytes, atio->cdb_len);
1282e9e688e2SHidetoshi Shimokawa 
1283e9e688e2SHidetoshi Shimokawa 	atio->ccb_h.status |= CAM_CDB_RECVD;
1284e9e688e2SHidetoshi Shimokawa 
1285e9e688e2SHidetoshi Shimokawa 	/* next ORB */
1286e9e688e2SHidetoshi Shimokawa 	if ((orb[0] & (1<<31)) == 0) {
1287e9e688e2SHidetoshi Shimokawa 		if (debug)
128810d3ed64SHidetoshi Shimokawa 			printf("%s: fetch next orb\n", __func__);
1289e9e688e2SHidetoshi Shimokawa 		orbi->status.src = SRC_NEXT_EXISTS;
1290e9e688e2SHidetoshi Shimokawa 		sbp_targ_fetch_orb(orbi->sc, orbi->fwdev,
1291a73ff510SHidetoshi Shimokawa 		    orb[0], orb[1], orbi->login, FETCH_CMD);
1292e9e688e2SHidetoshi Shimokawa 	} else {
1293e9e688e2SHidetoshi Shimokawa 		orbi->status.src = SRC_NO_NEXT;
1294a73ff510SHidetoshi Shimokawa 		orbi->login->flags &= ~F_LINK_ACTIVE;
1295e9e688e2SHidetoshi Shimokawa 	}
1296e9e688e2SHidetoshi Shimokawa 
1297e9e688e2SHidetoshi Shimokawa 	orbi->data_hi = orb[2];
1298e9e688e2SHidetoshi Shimokawa 	orbi->data_lo = orb[3];
1299e9e688e2SHidetoshi Shimokawa 	orbi->orb4 = *orb4;
1300e9e688e2SHidetoshi Shimokawa 
13019950b741SHidetoshi Shimokawa 	SBP_LOCK(orbi->sc);
1302e9e688e2SHidetoshi Shimokawa 	xpt_done((union ccb*)atio);
13039950b741SHidetoshi Shimokawa 	SBP_UNLOCK(orbi->sc);
1304e9e688e2SHidetoshi Shimokawa done0:
1305e9e688e2SHidetoshi Shimokawa 	fw_xfer_free(xfer);
1306e9e688e2SHidetoshi Shimokawa 	return;
1307e9e688e2SHidetoshi Shimokawa }
1308e9e688e2SHidetoshi Shimokawa 
1309a73ff510SHidetoshi Shimokawa static struct sbp_targ_login *
1310a73ff510SHidetoshi Shimokawa sbp_targ_get_login(struct sbp_targ_softc *sc, struct fw_device *fwdev, int lun)
1311a73ff510SHidetoshi Shimokawa {
1312a73ff510SHidetoshi Shimokawa 	struct sbp_targ_lstate *lstate;
1313a73ff510SHidetoshi Shimokawa 	struct sbp_targ_login *login;
1314a73ff510SHidetoshi Shimokawa 	int i;
1315a73ff510SHidetoshi Shimokawa 
1316a73ff510SHidetoshi Shimokawa 	lstate = sc->lstate[lun];
1317a73ff510SHidetoshi Shimokawa 
1318a73ff510SHidetoshi Shimokawa 	STAILQ_FOREACH(login, &lstate->logins, link)
1319a73ff510SHidetoshi Shimokawa 		if (login->fwdev == fwdev)
1320a73ff510SHidetoshi Shimokawa 			return (login);
1321a73ff510SHidetoshi Shimokawa 
1322a73ff510SHidetoshi Shimokawa 	for (i = 0; i < MAX_LOGINS; i ++)
1323a73ff510SHidetoshi Shimokawa 		if (sc->logins[i] == NULL)
1324a73ff510SHidetoshi Shimokawa 			goto found;
1325a73ff510SHidetoshi Shimokawa 
132610d3ed64SHidetoshi Shimokawa 	printf("%s: increase MAX_LOGIN\n", __func__);
1327a73ff510SHidetoshi Shimokawa 	return (NULL);
1328a73ff510SHidetoshi Shimokawa 
1329a73ff510SHidetoshi Shimokawa found:
1330a73ff510SHidetoshi Shimokawa 	login = (struct sbp_targ_login *)malloc(
1331a73ff510SHidetoshi Shimokawa 	    sizeof(struct sbp_targ_login), M_SBP_TARG, M_NOWAIT | M_ZERO);
1332a73ff510SHidetoshi Shimokawa 
1333a73ff510SHidetoshi Shimokawa 	if (login == NULL) {
133410d3ed64SHidetoshi Shimokawa 		printf("%s: malloc failed\n", __func__);
1335a73ff510SHidetoshi Shimokawa 		return (NULL);
1336a73ff510SHidetoshi Shimokawa 	}
1337a73ff510SHidetoshi Shimokawa 
1338c6cf3e20SHidetoshi Shimokawa 	login->id = i;
1339a73ff510SHidetoshi Shimokawa 	login->fwdev = fwdev;
1340a73ff510SHidetoshi Shimokawa 	login->lstate = lstate;
1341a73ff510SHidetoshi Shimokawa 	login->last_hi = 0xffff;
1342a73ff510SHidetoshi Shimokawa 	login->last_lo = 0xffffffff;
1343a73ff510SHidetoshi Shimokawa 	login->hold_sec = 1;
1344a73ff510SHidetoshi Shimokawa 	STAILQ_INIT(&login->orbs);
1345a73ff510SHidetoshi Shimokawa 	CALLOUT_INIT(&login->hold_callout);
1346a73ff510SHidetoshi Shimokawa 	sc->logins[i] = login;
1347a73ff510SHidetoshi Shimokawa 	return (login);
1348a73ff510SHidetoshi Shimokawa }
1349a73ff510SHidetoshi Shimokawa 
1350e9e688e2SHidetoshi Shimokawa static void
1351e9e688e2SHidetoshi Shimokawa sbp_targ_mgm_handler(struct fw_xfer *xfer)
1352e9e688e2SHidetoshi Shimokawa {
1353e9e688e2SHidetoshi Shimokawa 	struct sbp_targ_lstate *lstate;
1354a73ff510SHidetoshi Shimokawa 	struct sbp_targ_login *login;
1355e9e688e2SHidetoshi Shimokawa 	struct fw_pkt *fp;
135603161bbcSDoug Rabson 	uint32_t *orb;
1357e9e688e2SHidetoshi Shimokawa 	struct morb4 *orb4;
1358e9e688e2SHidetoshi Shimokawa 	struct orb_info *orbi;
1359e9e688e2SHidetoshi Shimokawa 	int i;
1360e9e688e2SHidetoshi Shimokawa 
1361e9e688e2SHidetoshi Shimokawa 	orbi = (struct orb_info *)xfer->sc;
1362e9e688e2SHidetoshi Shimokawa 	if (xfer->resp != 0) {
136310d3ed64SHidetoshi Shimokawa 		printf("%s: xfer->resp = %d\n", __func__, xfer->resp);
1364e9e688e2SHidetoshi Shimokawa 		orbi->status.resp = SBP_TRANS_FAIL;
13651398a889SHidetoshi Shimokawa 		orbi->status.status = OBJ_ORB | SBE_TIMEOUT/*XXX*/;
1366e9e688e2SHidetoshi Shimokawa 		orbi->status.dead = 1;
1367e9e688e2SHidetoshi Shimokawa 		orbi->status.len = 1;
13689950b741SHidetoshi Shimokawa 		sbp_targ_abort(orbi->sc, STAILQ_NEXT(orbi, link));
1369e9e688e2SHidetoshi Shimokawa 
1370e9e688e2SHidetoshi Shimokawa 		sbp_targ_status_FIFO(orbi,
1371a73ff510SHidetoshi Shimokawa 		    orbi->login->fifo_hi, orbi->login->fifo_lo, /*dequeue*/0);
1372e9e688e2SHidetoshi Shimokawa 		fw_xfer_free(xfer);
1373e9e688e2SHidetoshi Shimokawa 		return;
1374e9e688e2SHidetoshi Shimokawa 	}
1375e9e688e2SHidetoshi Shimokawa 	fp = &xfer->recv.hdr;
1376e9e688e2SHidetoshi Shimokawa 
1377e9e688e2SHidetoshi Shimokawa 	orb = orbi->orb;
1378e9e688e2SHidetoshi Shimokawa 	/* swap payload */
1379e9e688e2SHidetoshi Shimokawa 	for (i = 0; i < 8; i ++) {
1380e9e688e2SHidetoshi Shimokawa 		orb[i] = ntohl(orb[i]);
1381e9e688e2SHidetoshi Shimokawa 	}
1382e9e688e2SHidetoshi Shimokawa 	orb4 = (struct morb4 *)&orb[4];
1383e9e688e2SHidetoshi Shimokawa 	if (debug)
138410d3ed64SHidetoshi Shimokawa 		printf("%s: %s\n", __func__, orb_fun_name[orb4->fun]);
1385e9e688e2SHidetoshi Shimokawa 
1386e9e688e2SHidetoshi Shimokawa 	orbi->status.src = SRC_NO_NEXT;
1387e9e688e2SHidetoshi Shimokawa 
1388e9e688e2SHidetoshi Shimokawa 	switch (orb4->fun << 16) {
1389e9e688e2SHidetoshi Shimokawa 	case ORB_FUN_LGI:
1390e9e688e2SHidetoshi Shimokawa 	{
1391a73ff510SHidetoshi Shimokawa 		int exclusive = 0, lun;
1392e9e688e2SHidetoshi Shimokawa 
1393a73ff510SHidetoshi Shimokawa 		if (orb[4] & ORB_EXV)
1394a73ff510SHidetoshi Shimokawa 			exclusive = 1;
1395a73ff510SHidetoshi Shimokawa 
1396a73ff510SHidetoshi Shimokawa 		lun = orb4->id;
1397a73ff510SHidetoshi Shimokawa 		lstate = orbi->sc->lstate[lun];
1398a73ff510SHidetoshi Shimokawa 
1399a73ff510SHidetoshi Shimokawa 		if (lun >= MAX_LUN || lstate == NULL ||
1400a73ff510SHidetoshi Shimokawa 		    (exclusive &&
1401a73ff510SHidetoshi Shimokawa 		    STAILQ_FIRST(&lstate->logins) != NULL &&
1402a73ff510SHidetoshi Shimokawa 		    STAILQ_FIRST(&lstate->logins)->fwdev != orbi->fwdev)
1403a73ff510SHidetoshi Shimokawa 		    ) {
1404e9e688e2SHidetoshi Shimokawa 			/* error */
1405e9e688e2SHidetoshi Shimokawa 			orbi->status.dead = 1;
1406e9e688e2SHidetoshi Shimokawa 			orbi->status.status = STATUS_ACCESS_DENY;
1407e9e688e2SHidetoshi Shimokawa 			orbi->status.len = 1;
1408e9e688e2SHidetoshi Shimokawa 			break;
1409e9e688e2SHidetoshi Shimokawa 		}
1410a73ff510SHidetoshi Shimokawa 
1411a73ff510SHidetoshi Shimokawa 		/* allocate login */
1412a73ff510SHidetoshi Shimokawa 		login = sbp_targ_get_login(orbi->sc, orbi->fwdev, lun);
1413a73ff510SHidetoshi Shimokawa 		if (login == NULL) {
1414a73ff510SHidetoshi Shimokawa 			printf("%s: sbp_targ_get_login failed\n",
141510d3ed64SHidetoshi Shimokawa 			    __func__);
1416a73ff510SHidetoshi Shimokawa 			orbi->status.dead = 1;
1417a73ff510SHidetoshi Shimokawa 			orbi->status.status = STATUS_RES_UNAVAIL;
1418a73ff510SHidetoshi Shimokawa 			orbi->status.len = 1;
1419a73ff510SHidetoshi Shimokawa 			break;
1420a73ff510SHidetoshi Shimokawa 		}
14219950b741SHidetoshi Shimokawa 		printf("%s: login id=%d\n", __func__, login->id);
1422a73ff510SHidetoshi Shimokawa 
1423a73ff510SHidetoshi Shimokawa 		login->fifo_hi = orb[6];
1424a73ff510SHidetoshi Shimokawa 		login->fifo_lo = orb[7];
142503161bbcSDoug Rabson 		login->loginres.len = htons(sizeof(uint32_t) * 4);
1426a73ff510SHidetoshi Shimokawa 		login->loginres.id = htons(login->id);
1427a73ff510SHidetoshi Shimokawa 		login->loginres.cmd_hi = htons(SBP_TARG_BIND_HI);
1428a73ff510SHidetoshi Shimokawa 		login->loginres.cmd_lo = htonl(SBP_TARG_BIND_LO(login->id));
1429a73ff510SHidetoshi Shimokawa 		login->loginres.recon_hold = htons(login->hold_sec);
1430a73ff510SHidetoshi Shimokawa 
14319950b741SHidetoshi Shimokawa 		STAILQ_INSERT_TAIL(&lstate->logins, login, link);
1432e9e688e2SHidetoshi Shimokawa 		fwmem_write_block(orbi->fwdev, NULL, /*spd*/2, orb[2], orb[3],
1433a73ff510SHidetoshi Shimokawa 		    sizeof(struct sbp_login_res), (void *)&login->loginres,
1434e9e688e2SHidetoshi Shimokawa 		    fw_asy_callback_free);
1435c54d1fe2SHidetoshi Shimokawa 		/* XXX return status after loginres is successfully written */
1436e9e688e2SHidetoshi Shimokawa 		break;
1437e9e688e2SHidetoshi Shimokawa 	}
1438e9e688e2SHidetoshi Shimokawa 	case ORB_FUN_RCN:
1439a73ff510SHidetoshi Shimokawa 		login = orbi->sc->logins[orb4->id];
1440a73ff510SHidetoshi Shimokawa 		if (login != NULL && login->fwdev == orbi->fwdev) {
1441a73ff510SHidetoshi Shimokawa 			login->flags &= ~F_HOLD;
1442a73ff510SHidetoshi Shimokawa 			callout_stop(&login->hold_callout);
1443a73ff510SHidetoshi Shimokawa 			printf("%s: reconnected id=%d\n",
144410d3ed64SHidetoshi Shimokawa 			    __func__, login->id);
1445a73ff510SHidetoshi Shimokawa 		} else {
1446e9e688e2SHidetoshi Shimokawa 			orbi->status.dead = 1;
1447e9e688e2SHidetoshi Shimokawa 			orbi->status.status = STATUS_ACCESS_DENY;
1448a73ff510SHidetoshi Shimokawa 			printf("%s: reconnection faild id=%d\n",
144910d3ed64SHidetoshi Shimokawa 			    __func__, orb4->id);
1450a73ff510SHidetoshi Shimokawa 		}
1451a73ff510SHidetoshi Shimokawa 		break;
1452a73ff510SHidetoshi Shimokawa 	case ORB_FUN_LGO:
1453a73ff510SHidetoshi Shimokawa 		login = orbi->sc->logins[orb4->id];
1454a73ff510SHidetoshi Shimokawa 		if (login->fwdev != orbi->fwdev) {
145510d3ed64SHidetoshi Shimokawa 			printf("%s: wrong initiator\n", __func__);
1456a73ff510SHidetoshi Shimokawa 			break;
1457a73ff510SHidetoshi Shimokawa 		}
1458a73ff510SHidetoshi Shimokawa 		sbp_targ_dealloc_login(login);
1459e9e688e2SHidetoshi Shimokawa 		break;
1460e9e688e2SHidetoshi Shimokawa 	default:
1461e9e688e2SHidetoshi Shimokawa 		printf("%s: %s not implemented yet\n",
146210d3ed64SHidetoshi Shimokawa 		    __func__, orb_fun_name[orb4->fun]);
1463e9e688e2SHidetoshi Shimokawa 		break;
1464e9e688e2SHidetoshi Shimokawa 	}
1465e9e688e2SHidetoshi Shimokawa 	orbi->status.len = 1;
1466e9e688e2SHidetoshi Shimokawa 	sbp_targ_status_FIFO(orbi, orb[6], orb[7], /*dequeue*/0);
1467e9e688e2SHidetoshi Shimokawa 	fw_xfer_free(xfer);
1468e9e688e2SHidetoshi Shimokawa 	return;
1469e9e688e2SHidetoshi Shimokawa }
1470e9e688e2SHidetoshi Shimokawa 
1471e9e688e2SHidetoshi Shimokawa static void
1472e9e688e2SHidetoshi Shimokawa sbp_targ_pointer_handler(struct fw_xfer *xfer)
1473e9e688e2SHidetoshi Shimokawa {
1474e9e688e2SHidetoshi Shimokawa 	struct orb_info *orbi;
147503161bbcSDoug Rabson 	uint32_t orb0, orb1;
1476e9e688e2SHidetoshi Shimokawa 
1477e9e688e2SHidetoshi Shimokawa 	orbi = (struct orb_info *)xfer->sc;
1478e9e688e2SHidetoshi Shimokawa 	if (xfer->resp != 0) {
147910d3ed64SHidetoshi Shimokawa 		printf("%s: xfer->resp = %d\n", __func__, xfer->resp);
1480e9e688e2SHidetoshi Shimokawa 		goto done;
1481e9e688e2SHidetoshi Shimokawa 	}
1482e9e688e2SHidetoshi Shimokawa 
1483e9e688e2SHidetoshi Shimokawa 	orb0 = ntohl(orbi->orb[0]);
1484e9e688e2SHidetoshi Shimokawa 	orb1 = ntohl(orbi->orb[1]);
1485e9e688e2SHidetoshi Shimokawa 	if ((orb0 & (1 << 31)) != 0) {
148610d3ed64SHidetoshi Shimokawa 		printf("%s: invalid pointer\n", __func__);
1487e9e688e2SHidetoshi Shimokawa 		goto done;
1488e9e688e2SHidetoshi Shimokawa 	}
1489a73ff510SHidetoshi Shimokawa 	sbp_targ_fetch_orb(orbi->login->lstate->sc, orbi->fwdev,
149003161bbcSDoug Rabson 	    (uint16_t)orb0, orb1, orbi->login, FETCH_CMD);
1491e9e688e2SHidetoshi Shimokawa done:
1492e9e688e2SHidetoshi Shimokawa 	free(orbi, M_SBP_TARG);
1493e9e688e2SHidetoshi Shimokawa 	fw_xfer_free(xfer);
1494e9e688e2SHidetoshi Shimokawa 	return;
1495e9e688e2SHidetoshi Shimokawa }
1496e9e688e2SHidetoshi Shimokawa 
1497e9e688e2SHidetoshi Shimokawa static void
1498e9e688e2SHidetoshi Shimokawa sbp_targ_fetch_orb(struct sbp_targ_softc *sc, struct fw_device *fwdev,
149903161bbcSDoug Rabson     uint16_t orb_hi, uint32_t orb_lo, struct sbp_targ_login *login,
1500e9e688e2SHidetoshi Shimokawa     int mode)
1501e9e688e2SHidetoshi Shimokawa {
1502e9e688e2SHidetoshi Shimokawa 	struct orb_info *orbi;
1503e9e688e2SHidetoshi Shimokawa 
1504e9e688e2SHidetoshi Shimokawa 	if (debug)
150510d3ed64SHidetoshi Shimokawa 		printf("%s: fetch orb %04x:%08x\n", __func__, orb_hi, orb_lo);
1506e9e688e2SHidetoshi Shimokawa 	orbi = malloc(sizeof(struct orb_info), M_SBP_TARG, M_NOWAIT | M_ZERO);
1507e9e688e2SHidetoshi Shimokawa 	if (orbi == NULL) {
150810d3ed64SHidetoshi Shimokawa 		printf("%s: malloc failed\n", __func__);
1509e9e688e2SHidetoshi Shimokawa 		return;
1510e9e688e2SHidetoshi Shimokawa 	}
1511e9e688e2SHidetoshi Shimokawa 	orbi->sc = sc;
1512e9e688e2SHidetoshi Shimokawa 	orbi->fwdev = fwdev;
1513a73ff510SHidetoshi Shimokawa 	orbi->login = login;
1514e9e688e2SHidetoshi Shimokawa 	orbi->orb_hi = orb_hi;
1515e9e688e2SHidetoshi Shimokawa 	orbi->orb_lo = orb_lo;
1516e9e688e2SHidetoshi Shimokawa 	orbi->status.orb_hi = htons(orb_hi);
1517e9e688e2SHidetoshi Shimokawa 	orbi->status.orb_lo = htonl(orb_lo);
1518e9e688e2SHidetoshi Shimokawa 
1519e9e688e2SHidetoshi Shimokawa 	switch (mode) {
1520e9e688e2SHidetoshi Shimokawa 	case FETCH_MGM:
1521e9e688e2SHidetoshi Shimokawa 		fwmem_read_block(fwdev, (void *)orbi, /*spd*/2, orb_hi, orb_lo,
152203161bbcSDoug Rabson 		    sizeof(uint32_t) * 8, &orbi->orb[0],
1523e9e688e2SHidetoshi Shimokawa 		    sbp_targ_mgm_handler);
1524e9e688e2SHidetoshi Shimokawa 		break;
1525e9e688e2SHidetoshi Shimokawa 	case FETCH_CMD:
1526e9e688e2SHidetoshi Shimokawa 		orbi->state = ORBI_STATUS_FETCH;
1527a73ff510SHidetoshi Shimokawa 		login->last_hi = orb_hi;
1528a73ff510SHidetoshi Shimokawa 		login->last_lo = orb_lo;
1529a73ff510SHidetoshi Shimokawa 		login->flags |= F_LINK_ACTIVE;
1530e9e688e2SHidetoshi Shimokawa 		/* dequeue */
15319950b741SHidetoshi Shimokawa 		SBP_LOCK(sc);
1532e9e688e2SHidetoshi Shimokawa 		orbi->atio = (struct ccb_accept_tio *)
1533a73ff510SHidetoshi Shimokawa 		    SLIST_FIRST(&login->lstate->accept_tios);
1534e9e688e2SHidetoshi Shimokawa 		if (orbi->atio == NULL) {
15359950b741SHidetoshi Shimokawa 			SBP_UNLOCK(sc);
153610d3ed64SHidetoshi Shimokawa 			printf("%s: no free atio\n", __func__);
1537a73ff510SHidetoshi Shimokawa 			login->lstate->flags |= F_ATIO_STARVED;
1538a73ff510SHidetoshi Shimokawa 			login->flags |= F_ATIO_STARVED;
1539a73ff510SHidetoshi Shimokawa #if 0
1540a73ff510SHidetoshi Shimokawa 			/* XXX ?? */
1541a73ff510SHidetoshi Shimokawa 			login->fwdev = fwdev;
1542a73ff510SHidetoshi Shimokawa #endif
1543e9e688e2SHidetoshi Shimokawa 			break;
1544e9e688e2SHidetoshi Shimokawa 		}
1545a73ff510SHidetoshi Shimokawa 		SLIST_REMOVE_HEAD(&login->lstate->accept_tios, sim_links.sle);
15469950b741SHidetoshi Shimokawa 		STAILQ_INSERT_TAIL(&login->orbs, orbi, link);
15479950b741SHidetoshi Shimokawa 		SBP_UNLOCK(sc);
1548e9e688e2SHidetoshi Shimokawa 		fwmem_read_block(fwdev, (void *)orbi, /*spd*/2, orb_hi, orb_lo,
154903161bbcSDoug Rabson 		    sizeof(uint32_t) * 8, &orbi->orb[0],
1550e9e688e2SHidetoshi Shimokawa 		    sbp_targ_cmd_handler);
1551e9e688e2SHidetoshi Shimokawa 		break;
1552e9e688e2SHidetoshi Shimokawa 	case FETCH_POINTER:
1553e9e688e2SHidetoshi Shimokawa 		orbi->state = ORBI_STATUS_POINTER;
1554a73ff510SHidetoshi Shimokawa 		login->flags |= F_LINK_ACTIVE;
1555e9e688e2SHidetoshi Shimokawa 		fwmem_read_block(fwdev, (void *)orbi, /*spd*/2, orb_hi, orb_lo,
155603161bbcSDoug Rabson 		    sizeof(uint32_t) * 2, &orbi->orb[0],
1557e9e688e2SHidetoshi Shimokawa 		    sbp_targ_pointer_handler);
1558e9e688e2SHidetoshi Shimokawa 		break;
1559e9e688e2SHidetoshi Shimokawa 	default:
156010d3ed64SHidetoshi Shimokawa 		printf("%s: invalid mode %d\n", __func__, mode);
1561e9e688e2SHidetoshi Shimokawa 	}
1562e9e688e2SHidetoshi Shimokawa }
1563e9e688e2SHidetoshi Shimokawa 
1564e9e688e2SHidetoshi Shimokawa static void
1565e9e688e2SHidetoshi Shimokawa sbp_targ_resp_callback(struct fw_xfer *xfer)
1566e9e688e2SHidetoshi Shimokawa {
1567e9e688e2SHidetoshi Shimokawa 	struct sbp_targ_softc *sc;
1568e9e688e2SHidetoshi Shimokawa 	int s;
1569e9e688e2SHidetoshi Shimokawa 
1570e9e688e2SHidetoshi Shimokawa 	if (debug)
157110d3ed64SHidetoshi Shimokawa 		printf("%s: xfer=%p\n", __func__, xfer);
1572e9e688e2SHidetoshi Shimokawa 	sc = (struct sbp_targ_softc *)xfer->sc;
1573e9e688e2SHidetoshi Shimokawa 	fw_xfer_unload(xfer);
1574e9e688e2SHidetoshi Shimokawa 	xfer->recv.pay_len = SBP_TARG_RECV_LEN;
1575801167a8SHidetoshi Shimokawa 	xfer->hand = sbp_targ_recv;
1576e9e688e2SHidetoshi Shimokawa 	s = splfw();
1577e9e688e2SHidetoshi Shimokawa 	STAILQ_INSERT_TAIL(&sc->fwb.xferlist, xfer, link);
1578e9e688e2SHidetoshi Shimokawa 	splx(s);
1579e9e688e2SHidetoshi Shimokawa }
1580e9e688e2SHidetoshi Shimokawa 
1581e9e688e2SHidetoshi Shimokawa static int
1582a73ff510SHidetoshi Shimokawa sbp_targ_cmd(struct fw_xfer *xfer, struct fw_device *fwdev, int login_id,
1583a73ff510SHidetoshi Shimokawa     int reg)
1584e9e688e2SHidetoshi Shimokawa {
1585a73ff510SHidetoshi Shimokawa 	struct sbp_targ_login *login;
1586e9e688e2SHidetoshi Shimokawa 	struct sbp_targ_softc *sc;
1587e9e688e2SHidetoshi Shimokawa 	int rtcode = 0;
1588e9e688e2SHidetoshi Shimokawa 
1589a73ff510SHidetoshi Shimokawa 	if (login_id < 0 || login_id >= MAX_LOGINS)
1590e9e688e2SHidetoshi Shimokawa 		return(RESP_ADDRESS_ERROR);
1591e9e688e2SHidetoshi Shimokawa 
1592e9e688e2SHidetoshi Shimokawa 	sc = (struct sbp_targ_softc *)xfer->sc;
1593a73ff510SHidetoshi Shimokawa 	login = sc->logins[login_id];
1594a73ff510SHidetoshi Shimokawa 	if (login == NULL)
1595e9e688e2SHidetoshi Shimokawa 		return(RESP_ADDRESS_ERROR);
1596e9e688e2SHidetoshi Shimokawa 
1597a73ff510SHidetoshi Shimokawa 	if (login->fwdev != fwdev) {
1598a73ff510SHidetoshi Shimokawa 		/* XXX */
1599a73ff510SHidetoshi Shimokawa 		return(RESP_ADDRESS_ERROR);
1600a73ff510SHidetoshi Shimokawa 	}
1601a73ff510SHidetoshi Shimokawa 
1602e9e688e2SHidetoshi Shimokawa 	switch (reg) {
1603e9e688e2SHidetoshi Shimokawa 	case 0x08:	/* ORB_POINTER */
1604e9e688e2SHidetoshi Shimokawa 		if (debug)
16059950b741SHidetoshi Shimokawa 			printf("%s: ORB_POINTER(%d)\n", __func__, login_id);
1606a73ff510SHidetoshi Shimokawa 		if ((login->flags & F_LINK_ACTIVE) != 0) {
1607a73ff510SHidetoshi Shimokawa 			if (debug)
1608a73ff510SHidetoshi Shimokawa 				printf("link active (ORB_POINTER)\n");
1609a73ff510SHidetoshi Shimokawa 			break;
1610a73ff510SHidetoshi Shimokawa 		}
1611a73ff510SHidetoshi Shimokawa 		sbp_targ_fetch_orb(sc, fwdev,
1612e9e688e2SHidetoshi Shimokawa 		    ntohl(xfer->recv.payload[0]),
1613e9e688e2SHidetoshi Shimokawa 		    ntohl(xfer->recv.payload[1]),
1614a73ff510SHidetoshi Shimokawa 		    login, FETCH_CMD);
1615e9e688e2SHidetoshi Shimokawa 		break;
1616e9e688e2SHidetoshi Shimokawa 	case 0x04:	/* AGENT_RESET */
1617e9e688e2SHidetoshi Shimokawa 		if (debug)
16189950b741SHidetoshi Shimokawa 			printf("%s: AGENT RESET(%d)\n", __func__, login_id);
1619a73ff510SHidetoshi Shimokawa 		login->last_hi = 0xffff;
1620a73ff510SHidetoshi Shimokawa 		login->last_lo = 0xffffffff;
16219950b741SHidetoshi Shimokawa 		sbp_targ_abort(sc, STAILQ_FIRST(&login->orbs));
1622e9e688e2SHidetoshi Shimokawa 		break;
1623e9e688e2SHidetoshi Shimokawa 	case 0x10:	/* DOORBELL */
1624e9e688e2SHidetoshi Shimokawa 		if (debug)
16259950b741SHidetoshi Shimokawa 			printf("%s: DOORBELL(%d)\n", __func__, login_id);
1626a73ff510SHidetoshi Shimokawa 		if (login->last_hi == 0xffff &&
1627a73ff510SHidetoshi Shimokawa 		    login->last_lo == 0xffffffff) {
1628e9e688e2SHidetoshi Shimokawa 			printf("%s: no previous pointer(DOORBELL)\n",
162910d3ed64SHidetoshi Shimokawa 			    __func__);
1630e9e688e2SHidetoshi Shimokawa 			break;
1631e9e688e2SHidetoshi Shimokawa 		}
1632a73ff510SHidetoshi Shimokawa 		if ((login->flags & F_LINK_ACTIVE) != 0) {
1633e9e688e2SHidetoshi Shimokawa 			if (debug)
1634e9e688e2SHidetoshi Shimokawa 				printf("link active (DOORBELL)\n");
1635e9e688e2SHidetoshi Shimokawa 			break;
1636e9e688e2SHidetoshi Shimokawa 		}
1637a73ff510SHidetoshi Shimokawa 		sbp_targ_fetch_orb(sc, fwdev,
1638a73ff510SHidetoshi Shimokawa 		    login->last_hi, login->last_lo,
1639a73ff510SHidetoshi Shimokawa 		    login, FETCH_POINTER);
1640e9e688e2SHidetoshi Shimokawa 		break;
1641e9e688e2SHidetoshi Shimokawa 	case 0x00:	/* AGENT_STATE */
16429950b741SHidetoshi Shimokawa 		printf("%s: AGENT_STATE (%d:ignore)\n", __func__, login_id);
1643e9e688e2SHidetoshi Shimokawa 		break;
1644e9e688e2SHidetoshi Shimokawa 	case 0x14:	/* UNSOLICITED_STATE_ENABLE */
16459950b741SHidetoshi Shimokawa 		printf("%s: UNSOLICITED_STATE_ENABLE (%d:ignore)\n",
16469950b741SHidetoshi Shimokawa 							 __func__, login_id);
1647e9e688e2SHidetoshi Shimokawa 		break;
1648e9e688e2SHidetoshi Shimokawa 	default:
16499950b741SHidetoshi Shimokawa 		printf("%s: invalid register %d(%d)\n",
16509950b741SHidetoshi Shimokawa 						 __func__, reg, login_id);
1651e9e688e2SHidetoshi Shimokawa 		rtcode = RESP_ADDRESS_ERROR;
1652e9e688e2SHidetoshi Shimokawa 	}
1653e9e688e2SHidetoshi Shimokawa 
1654e9e688e2SHidetoshi Shimokawa 	return (rtcode);
1655e9e688e2SHidetoshi Shimokawa }
1656e9e688e2SHidetoshi Shimokawa 
1657e9e688e2SHidetoshi Shimokawa static int
1658e9e688e2SHidetoshi Shimokawa sbp_targ_mgm(struct fw_xfer *xfer, struct fw_device *fwdev)
1659e9e688e2SHidetoshi Shimokawa {
1660e9e688e2SHidetoshi Shimokawa 	struct sbp_targ_softc *sc;
1661e9e688e2SHidetoshi Shimokawa 	struct fw_pkt *fp;
1662e9e688e2SHidetoshi Shimokawa 
1663e9e688e2SHidetoshi Shimokawa 	sc = (struct sbp_targ_softc *)xfer->sc;
1664e9e688e2SHidetoshi Shimokawa 
1665e9e688e2SHidetoshi Shimokawa 	fp = &xfer->recv.hdr;
1666e9e688e2SHidetoshi Shimokawa 	if (fp->mode.wreqb.tcode != FWTCODE_WREQB){
166710d3ed64SHidetoshi Shimokawa 		printf("%s: tcode = %d\n", __func__, fp->mode.wreqb.tcode);
1668e9e688e2SHidetoshi Shimokawa 		return(RESP_TYPE_ERROR);
1669e9e688e2SHidetoshi Shimokawa         }
1670e9e688e2SHidetoshi Shimokawa 
1671e9e688e2SHidetoshi Shimokawa 	sbp_targ_fetch_orb(sc, fwdev,
1672e9e688e2SHidetoshi Shimokawa 	    ntohl(xfer->recv.payload[0]),
1673e9e688e2SHidetoshi Shimokawa 	    ntohl(xfer->recv.payload[1]),
1674e9e688e2SHidetoshi Shimokawa 	    NULL, FETCH_MGM);
1675e9e688e2SHidetoshi Shimokawa 
1676e9e688e2SHidetoshi Shimokawa 	return(0);
1677e9e688e2SHidetoshi Shimokawa }
1678e9e688e2SHidetoshi Shimokawa 
1679e9e688e2SHidetoshi Shimokawa static void
1680e9e688e2SHidetoshi Shimokawa sbp_targ_recv(struct fw_xfer *xfer)
1681e9e688e2SHidetoshi Shimokawa {
1682e9e688e2SHidetoshi Shimokawa 	struct fw_pkt *fp, *sfp;
1683e9e688e2SHidetoshi Shimokawa 	struct fw_device *fwdev;
168403161bbcSDoug Rabson 	uint32_t lo;
1685e9e688e2SHidetoshi Shimokawa 	int s, rtcode;
1686e9e688e2SHidetoshi Shimokawa 	struct sbp_targ_softc *sc;
1687e9e688e2SHidetoshi Shimokawa 
1688e9e688e2SHidetoshi Shimokawa 	s = splfw();
1689e9e688e2SHidetoshi Shimokawa 	sc = (struct sbp_targ_softc *)xfer->sc;
1690e9e688e2SHidetoshi Shimokawa 	fp = &xfer->recv.hdr;
1691e9e688e2SHidetoshi Shimokawa 	fwdev = fw_noderesolve_nodeid(sc->fd.fc, fp->mode.wreqb.src & 0x3f);
1692e9e688e2SHidetoshi Shimokawa 	if (fwdev == NULL) {
1693e9e688e2SHidetoshi Shimokawa 		printf("%s: cannot resolve nodeid=%d\n",
169410d3ed64SHidetoshi Shimokawa 		    __func__, fp->mode.wreqb.src & 0x3f);
1695e9e688e2SHidetoshi Shimokawa 		rtcode = RESP_TYPE_ERROR; /* XXX */
1696e9e688e2SHidetoshi Shimokawa 		goto done;
1697e9e688e2SHidetoshi Shimokawa 	}
1698e9e688e2SHidetoshi Shimokawa 	lo = fp->mode.wreqb.dest_lo;
16999950b741SHidetoshi Shimokawa 
1700e9e688e2SHidetoshi Shimokawa 	if (lo == SBP_TARG_BIND_LO(-1))
1701e9e688e2SHidetoshi Shimokawa 		rtcode = sbp_targ_mgm(xfer, fwdev);
1702e9e688e2SHidetoshi Shimokawa 	else if (lo >= SBP_TARG_BIND_LO(0))
1703a73ff510SHidetoshi Shimokawa 		rtcode = sbp_targ_cmd(xfer, fwdev, SBP_TARG_LOGIN_ID(lo),
1704a73ff510SHidetoshi Shimokawa 		    lo % 0x20);
1705e9e688e2SHidetoshi Shimokawa 	else
1706e9e688e2SHidetoshi Shimokawa 		rtcode = RESP_ADDRESS_ERROR;
1707e9e688e2SHidetoshi Shimokawa 
1708e9e688e2SHidetoshi Shimokawa done:
1709e9e688e2SHidetoshi Shimokawa 	if (rtcode != 0)
171010d3ed64SHidetoshi Shimokawa 		printf("%s: rtcode = %d\n", __func__, rtcode);
1711e9e688e2SHidetoshi Shimokawa 	sfp = &xfer->send.hdr;
1712e9e688e2SHidetoshi Shimokawa 	xfer->send.spd = 2; /* XXX */
1713801167a8SHidetoshi Shimokawa 	xfer->hand = sbp_targ_resp_callback;
1714e9e688e2SHidetoshi Shimokawa 	sfp->mode.wres.dst = fp->mode.wreqb.src;
1715e9e688e2SHidetoshi Shimokawa 	sfp->mode.wres.tlrt = fp->mode.wreqb.tlrt;
1716e9e688e2SHidetoshi Shimokawa 	sfp->mode.wres.tcode = FWTCODE_WRES;
1717e9e688e2SHidetoshi Shimokawa 	sfp->mode.wres.rtcode = rtcode;
1718e9e688e2SHidetoshi Shimokawa 	sfp->mode.wres.pri = 0;
1719e9e688e2SHidetoshi Shimokawa 
1720e9e688e2SHidetoshi Shimokawa 	fw_asyreq(xfer->fc, -1, xfer);
1721e9e688e2SHidetoshi Shimokawa 	splx(s);
1722e9e688e2SHidetoshi Shimokawa }
1723e9e688e2SHidetoshi Shimokawa 
1724e9e688e2SHidetoshi Shimokawa static int
1725e9e688e2SHidetoshi Shimokawa sbp_targ_attach(device_t dev)
1726e9e688e2SHidetoshi Shimokawa {
1727e9e688e2SHidetoshi Shimokawa 	struct sbp_targ_softc *sc;
1728e9e688e2SHidetoshi Shimokawa 	struct cam_devq *devq;
17299950b741SHidetoshi Shimokawa 	struct firewire_comm *fc;
1730e9e688e2SHidetoshi Shimokawa 
1731e9e688e2SHidetoshi Shimokawa         sc = (struct sbp_targ_softc *) device_get_softc(dev);
1732e9e688e2SHidetoshi Shimokawa 	bzero((void *)sc, sizeof(struct sbp_targ_softc));
1733e9e688e2SHidetoshi Shimokawa 
17349950b741SHidetoshi Shimokawa 	mtx_init(&sc->mtx, "sbp_targ", NULL, MTX_DEF);
17359950b741SHidetoshi Shimokawa 	sc->fd.fc = fc = device_get_ivars(dev);
1736e9e688e2SHidetoshi Shimokawa 	sc->fd.dev = dev;
1737a73ff510SHidetoshi Shimokawa 	sc->fd.post_explore = (void *) sbp_targ_post_explore;
1738e9e688e2SHidetoshi Shimokawa 	sc->fd.post_busreset = (void *) sbp_targ_post_busreset;
1739e9e688e2SHidetoshi Shimokawa 
1740c6cf3e20SHidetoshi Shimokawa         devq = cam_simq_alloc(/*maxopenings*/MAX_LUN*MAX_INITIATORS);
1741e9e688e2SHidetoshi Shimokawa 	if (devq == NULL)
1742e9e688e2SHidetoshi Shimokawa 		return (ENXIO);
1743e9e688e2SHidetoshi Shimokawa 
1744e9e688e2SHidetoshi Shimokawa 	sc->sim = cam_sim_alloc(sbp_targ_action, sbp_targ_poll,
17459950b741SHidetoshi Shimokawa 	    "sbp_targ", sc, device_get_unit(dev), &sc->mtx,
1746e9e688e2SHidetoshi Shimokawa 	    /*untagged*/ 1, /*tagged*/ 1, devq);
1747e9e688e2SHidetoshi Shimokawa 	if (sc->sim == NULL) {
1748e9e688e2SHidetoshi Shimokawa 		cam_simq_free(devq);
1749e9e688e2SHidetoshi Shimokawa 		return (ENXIO);
1750e9e688e2SHidetoshi Shimokawa 	}
1751e9e688e2SHidetoshi Shimokawa 
17529950b741SHidetoshi Shimokawa 	SBP_LOCK(sc);
1753b50569b7SScott Long 	if (xpt_bus_register(sc->sim, dev, /*bus*/0) != CAM_SUCCESS)
1754e9e688e2SHidetoshi Shimokawa 		goto fail;
1755e9e688e2SHidetoshi Shimokawa 
1756e9e688e2SHidetoshi Shimokawa 	if (xpt_create_path(&sc->path, /*periph*/ NULL, cam_sim_path(sc->sim),
1757e9e688e2SHidetoshi Shimokawa 	    CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
1758e9e688e2SHidetoshi Shimokawa 		xpt_bus_deregister(cam_sim_path(sc->sim));
1759e9e688e2SHidetoshi Shimokawa 		goto fail;
1760e9e688e2SHidetoshi Shimokawa 	}
17619950b741SHidetoshi Shimokawa 	SBP_UNLOCK(sc);
1762e9e688e2SHidetoshi Shimokawa 
1763e9e688e2SHidetoshi Shimokawa 	sc->fwb.start = SBP_TARG_BIND_START;
1764e9e688e2SHidetoshi Shimokawa 	sc->fwb.end = SBP_TARG_BIND_END;
1765e9e688e2SHidetoshi Shimokawa 
1766e9e688e2SHidetoshi Shimokawa 	/* pre-allocate xfer */
1767e9e688e2SHidetoshi Shimokawa 	STAILQ_INIT(&sc->fwb.xferlist);
17680892f4c5SHidetoshi Shimokawa 	fw_xferlist_add(&sc->fwb.xferlist, M_SBP_TARG,
17690892f4c5SHidetoshi Shimokawa 	    /*send*/ 0, /*recv*/ SBP_TARG_RECV_LEN, MAX_LUN /* XXX */,
17709950b741SHidetoshi Shimokawa 	    fc, (void *)sc, sbp_targ_recv);
17719950b741SHidetoshi Shimokawa 	fw_bindadd(fc, &sc->fwb);
1772e9e688e2SHidetoshi Shimokawa 	return 0;
1773e9e688e2SHidetoshi Shimokawa 
1774e9e688e2SHidetoshi Shimokawa fail:
17759950b741SHidetoshi Shimokawa 	SBP_UNLOCK(sc);
1776e9e688e2SHidetoshi Shimokawa 	cam_sim_free(sc->sim, /*free_devq*/TRUE);
1777e9e688e2SHidetoshi Shimokawa 	return (ENXIO);
1778e9e688e2SHidetoshi Shimokawa }
1779e9e688e2SHidetoshi Shimokawa 
1780e9e688e2SHidetoshi Shimokawa static int
1781e9e688e2SHidetoshi Shimokawa sbp_targ_detach(device_t dev)
1782e9e688e2SHidetoshi Shimokawa {
1783e9e688e2SHidetoshi Shimokawa 	struct sbp_targ_softc *sc;
1784e9e688e2SHidetoshi Shimokawa 	struct sbp_targ_lstate *lstate;
1785e9e688e2SHidetoshi Shimokawa 	int i;
1786e9e688e2SHidetoshi Shimokawa 
1787e9e688e2SHidetoshi Shimokawa 	sc = (struct sbp_targ_softc *)device_get_softc(dev);
1788e9e688e2SHidetoshi Shimokawa 	sc->fd.post_busreset = NULL;
1789e9e688e2SHidetoshi Shimokawa 
17909950b741SHidetoshi Shimokawa 	SBP_LOCK(sc);
1791e9e688e2SHidetoshi Shimokawa 	xpt_free_path(sc->path);
1792e9e688e2SHidetoshi Shimokawa 	xpt_bus_deregister(cam_sim_path(sc->sim));
17939950b741SHidetoshi Shimokawa 	SBP_UNLOCK(sc);
1794e9e688e2SHidetoshi Shimokawa 	cam_sim_free(sc->sim, /*free_devq*/TRUE);
1795e9e688e2SHidetoshi Shimokawa 
1796e9e688e2SHidetoshi Shimokawa 	for (i = 0; i < MAX_LUN; i ++) {
1797e9e688e2SHidetoshi Shimokawa 		lstate = sc->lstate[i];
1798e9e688e2SHidetoshi Shimokawa 		if (lstate != NULL) {
1799e9e688e2SHidetoshi Shimokawa 			xpt_free_path(lstate->path);
1800e9e688e2SHidetoshi Shimokawa 			free(lstate, M_SBP_TARG);
1801e9e688e2SHidetoshi Shimokawa 		}
1802e9e688e2SHidetoshi Shimokawa 	}
1803e9e688e2SHidetoshi Shimokawa 	if (sc->black_hole != NULL) {
1804e9e688e2SHidetoshi Shimokawa 		xpt_free_path(sc->black_hole->path);
1805e9e688e2SHidetoshi Shimokawa 		free(sc->black_hole, M_SBP_TARG);
1806e9e688e2SHidetoshi Shimokawa 	}
1807e9e688e2SHidetoshi Shimokawa 
1808e9e688e2SHidetoshi Shimokawa 	fw_bindremove(sc->fd.fc, &sc->fwb);
18090892f4c5SHidetoshi Shimokawa 	fw_xferlist_remove(&sc->fwb.xferlist);
1810e9e688e2SHidetoshi Shimokawa 
18119950b741SHidetoshi Shimokawa 	mtx_destroy(&sc->mtx);
18129950b741SHidetoshi Shimokawa 
1813e9e688e2SHidetoshi Shimokawa 	return 0;
1814e9e688e2SHidetoshi Shimokawa }
1815e9e688e2SHidetoshi Shimokawa 
1816e9e688e2SHidetoshi Shimokawa static devclass_t sbp_targ_devclass;
1817e9e688e2SHidetoshi Shimokawa 
1818e9e688e2SHidetoshi Shimokawa static device_method_t sbp_targ_methods[] = {
1819e9e688e2SHidetoshi Shimokawa 	/* device interface */
1820e9e688e2SHidetoshi Shimokawa 	DEVMETHOD(device_identify,	sbp_targ_identify),
1821e9e688e2SHidetoshi Shimokawa 	DEVMETHOD(device_probe,		sbp_targ_probe),
1822e9e688e2SHidetoshi Shimokawa 	DEVMETHOD(device_attach,	sbp_targ_attach),
1823e9e688e2SHidetoshi Shimokawa 	DEVMETHOD(device_detach,	sbp_targ_detach),
1824e9e688e2SHidetoshi Shimokawa 	{ 0, 0 }
1825e9e688e2SHidetoshi Shimokawa };
1826e9e688e2SHidetoshi Shimokawa 
1827e9e688e2SHidetoshi Shimokawa static driver_t sbp_targ_driver = {
1828e9e688e2SHidetoshi Shimokawa 	"sbp_targ",
1829e9e688e2SHidetoshi Shimokawa 	sbp_targ_methods,
1830e9e688e2SHidetoshi Shimokawa 	sizeof(struct sbp_targ_softc),
1831e9e688e2SHidetoshi Shimokawa };
1832e9e688e2SHidetoshi Shimokawa 
1833e9e688e2SHidetoshi Shimokawa DRIVER_MODULE(sbp_targ, firewire, sbp_targ_driver, sbp_targ_devclass, 0, 0);
1834e9e688e2SHidetoshi Shimokawa MODULE_VERSION(sbp_targ, 1);
1835e9e688e2SHidetoshi Shimokawa MODULE_DEPEND(sbp_targ, firewire, 1, 1, 1);
1836e9e688e2SHidetoshi Shimokawa MODULE_DEPEND(sbp_targ, cam, 1, 1, 1);
1837