1139749Simp/*-
2121186Ssimokawa * Copyright (C) 2003
3121186Ssimokawa * 	Hidetoshi Shimokawa. All rights reserved.
4121186Ssimokawa *
5121186Ssimokawa * Redistribution and use in source and binary forms, with or without
6121186Ssimokawa * modification, are permitted provided that the following conditions
7121186Ssimokawa * are met:
8121186Ssimokawa * 1. Redistributions of source code must retain the above copyright
9121186Ssimokawa *    notice, this list of conditions and the following disclaimer.
10121186Ssimokawa * 2. Redistributions in binary form must reproduce the above copyright
11121186Ssimokawa *    notice, this list of conditions and the following disclaimer in the
12121186Ssimokawa *    documentation and/or other materials provided with the distribution.
13121186Ssimokawa * 3. All advertising materials mentioning features or use of this software
14121186Ssimokawa *    must display the following acknowledgement:
15121186Ssimokawa *
16121186Ssimokawa *	This product includes software developed by Hidetoshi Shimokawa.
17121186Ssimokawa *
18121186Ssimokawa * 4. Neither the name of the author nor the names of its contributors
19121186Ssimokawa *    may be used to endorse or promote products derived from this software
20121186Ssimokawa *    without specific prior written permission.
21121186Ssimokawa *
22121186Ssimokawa * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23121186Ssimokawa * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24121186Ssimokawa * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25121186Ssimokawa * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26121186Ssimokawa * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27121186Ssimokawa * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28121186Ssimokawa * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29121186Ssimokawa * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30121186Ssimokawa * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31121186Ssimokawa * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32121186Ssimokawa * SUCH DAMAGE.
33121186Ssimokawa *
34121186Ssimokawa * $FreeBSD: stable/10/sys/dev/firewire/sbp_targ.c 315813 2017-03-23 06:41:13Z mav $
35121186Ssimokawa */
36121186Ssimokawa
37121186Ssimokawa#include <sys/param.h>
38121186Ssimokawa#include <sys/kernel.h>
39121186Ssimokawa#include <sys/systm.h>
40121186Ssimokawa#include <sys/sysctl.h>
41121186Ssimokawa#include <sys/types.h>
42121186Ssimokawa#include <sys/conf.h>
43121186Ssimokawa#include <sys/malloc.h>
44225950Sken#include <sys/endian.h>
45121186Ssimokawa#if __FreeBSD_version < 500000
46121186Ssimokawa#include <sys/devicestat.h>
47121186Ssimokawa#endif
48121186Ssimokawa
49121186Ssimokawa#include <sys/bus.h>
50121186Ssimokawa#include <machine/bus.h>
51121186Ssimokawa
52121186Ssimokawa#include <dev/firewire/firewire.h>
53121186Ssimokawa#include <dev/firewire/firewirereg.h>
54121186Ssimokawa#include <dev/firewire/iec13213.h>
55121186Ssimokawa#include <dev/firewire/sbp.h>
56121186Ssimokawa#include <dev/firewire/fwmem.h>
57121186Ssimokawa
58121186Ssimokawa#include <cam/cam.h>
59121186Ssimokawa#include <cam/cam_ccb.h>
60121186Ssimokawa#include <cam/cam_sim.h>
61121186Ssimokawa#include <cam/cam_xpt_sim.h>
62121186Ssimokawa#include <cam/cam_debug.h>
63121186Ssimokawa#include <cam/cam_periph.h>
64121186Ssimokawa#include <cam/scsi/scsi_all.h>
65230558Ssbruno#include <cam/scsi/scsi_message.h>
66121186Ssimokawa
67123430Ssimokawa#define SBP_TARG_RECV_LEN	8
68123430Ssimokawa#define MAX_INITIATORS		8
69123430Ssimokawa#define MAX_LUN			63
70123430Ssimokawa#define MAX_LOGINS		63
71123430Ssimokawa#define MAX_NODES		63
72121186Ssimokawa/*
73121186Ssimokawa * management/command block agent registers
74121186Ssimokawa *
75121186Ssimokawa * BASE 0xffff f001 0000 management port
76123430Ssimokawa * BASE 0xffff f001 0020 command port for login id 0
77123430Ssimokawa * BASE 0xffff f001 0040 command port for login id 1
78121186Ssimokawa *
79121186Ssimokawa */
80121186Ssimokawa#define SBP_TARG_MGM	 0x10000	/* offset from 0xffff f000 000 */
81121186Ssimokawa#define SBP_TARG_BIND_HI	0xffff
82121186Ssimokawa#define SBP_TARG_BIND_LO(l)	(0xf0000000 + SBP_TARG_MGM + 0x20 * ((l) + 1))
83121186Ssimokawa#define SBP_TARG_BIND_START	(((u_int64_t)SBP_TARG_BIND_HI << 32) | \
84121186Ssimokawa				    SBP_TARG_BIND_LO(-1))
85121186Ssimokawa#define SBP_TARG_BIND_END	(((u_int64_t)SBP_TARG_BIND_HI << 32) | \
86123430Ssimokawa				    SBP_TARG_BIND_LO(MAX_LOGINS))
87123430Ssimokawa#define SBP_TARG_LOGIN_ID(lo)	(((lo) - SBP_TARG_BIND_LO(0))/0x20)
88121186Ssimokawa
89121186Ssimokawa#define FETCH_MGM	0
90121186Ssimokawa#define FETCH_CMD	1
91121186Ssimokawa#define FETCH_POINTER	2
92121186Ssimokawa
93123430Ssimokawa#define F_LINK_ACTIVE	(1 << 0)
94123430Ssimokawa#define F_ATIO_STARVED	(1 << 1)
95123430Ssimokawa#define F_LOGIN		(1 << 2)
96123430Ssimokawa#define F_HOLD		(1 << 3)
97123430Ssimokawa#define F_FREEZED	(1 << 4)
98123430Ssimokawa
99227293Sedstatic MALLOC_DEFINE(M_SBP_TARG, "sbp_targ", "SBP-II/FireWire target mode");
100121186Ssimokawa
101121186Ssimokawastatic int debug = 0;
102121186Ssimokawa
103121186SsimokawaSYSCTL_INT(_debug, OID_AUTO, sbp_targ_debug, CTLFLAG_RW, &debug, 0,
104121186Ssimokawa        "SBP target mode debug flag");
105121186Ssimokawa
106123430Ssimokawastruct sbp_targ_login {
107123430Ssimokawa	struct sbp_targ_lstate *lstate;
108123430Ssimokawa	struct fw_device *fwdev;
109123430Ssimokawa	struct sbp_login_res loginres;
110129585Sdfr	uint16_t fifo_hi;
111129585Sdfr	uint16_t last_hi;
112129585Sdfr	uint32_t fifo_lo;
113129585Sdfr	uint32_t last_lo;
114123430Ssimokawa	STAILQ_HEAD(, orb_info) orbs;
115124877Ssimokawa	STAILQ_ENTRY(sbp_targ_login) link;
116129585Sdfr	uint16_t hold_sec;
117129585Sdfr	uint16_t id;
118129585Sdfr	uint8_t flags;
119129585Sdfr	uint8_t spd;
120123430Ssimokawa	struct callout hold_callout;
121123430Ssimokawa};
122123430Ssimokawa
123123430Ssimokawastruct sbp_targ_lstate {
124129585Sdfr	uint16_t lun;
125123430Ssimokawa	struct sbp_targ_softc *sc;
126123430Ssimokawa	struct cam_path *path;
127123430Ssimokawa	struct ccb_hdr_slist accept_tios;
128123430Ssimokawa	struct ccb_hdr_slist immed_notifies;
129123430Ssimokawa	struct crom_chunk model;
130129585Sdfr	uint32_t flags;
131123430Ssimokawa	STAILQ_HEAD(, sbp_targ_login) logins;
132123430Ssimokawa};
133123430Ssimokawa
134121186Ssimokawastruct sbp_targ_softc {
135121186Ssimokawa        struct firewire_dev_comm fd;
136121186Ssimokawa	struct cam_sim *sim;
137121186Ssimokawa	struct cam_path *path;
138121186Ssimokawa	struct fw_bind fwb;
139121186Ssimokawa	int ndevs;
140123430Ssimokawa	int flags;
141121186Ssimokawa	struct crom_chunk unit;
142121186Ssimokawa	struct sbp_targ_lstate *lstate[MAX_LUN];
143121186Ssimokawa	struct sbp_targ_lstate *black_hole;
144123430Ssimokawa	struct sbp_targ_login *logins[MAX_LOGINS];
145170374Ssimokawa	struct mtx mtx;
146121186Ssimokawa};
147170374Ssimokawa#define SBP_LOCK(sc) mtx_lock(&(sc)->mtx)
148170374Ssimokawa#define SBP_UNLOCK(sc) mtx_unlock(&(sc)->mtx)
149121186Ssimokawa
150121186Ssimokawastruct corb4 {
151121186Ssimokawa#if BYTE_ORDER == BIG_ENDIAN
152129585Sdfr	uint32_t n:1,
153121186Ssimokawa		  rq_fmt:2,
154121186Ssimokawa		  :1,
155121186Ssimokawa		  dir:1,
156121186Ssimokawa		  spd:3,
157121186Ssimokawa		  max_payload:4,
158121186Ssimokawa		  page_table_present:1,
159121186Ssimokawa		  page_size:3,
160121186Ssimokawa		  data_size:16;
161121186Ssimokawa#else
162129585Sdfr	uint32_t data_size:16,
163121186Ssimokawa		  page_size:3,
164121186Ssimokawa		  page_table_present:1,
165121186Ssimokawa		  max_payload:4,
166121186Ssimokawa		  spd:3,
167121186Ssimokawa		  dir:1,
168121186Ssimokawa		  :1,
169121186Ssimokawa		  rq_fmt:2,
170121186Ssimokawa		  n:1;
171121186Ssimokawa#endif
172121186Ssimokawa};
173121186Ssimokawa
174121186Ssimokawastruct morb4 {
175121186Ssimokawa#if BYTE_ORDER == BIG_ENDIAN
176129585Sdfr	uint32_t n:1,
177121186Ssimokawa		  rq_fmt:2,
178121186Ssimokawa		  :9,
179121186Ssimokawa		  fun:4,
180121186Ssimokawa		  id:16;
181121186Ssimokawa#else
182129585Sdfr	uint32_t id:16,
183121186Ssimokawa		  fun:4,
184121186Ssimokawa		  :9,
185121186Ssimokawa		  rq_fmt:2,
186121186Ssimokawa		  n:1;
187121186Ssimokawa#endif
188121186Ssimokawa};
189121186Ssimokawa
190230558Ssbruno
191230558Ssbruno/*
192230558Ssbruno * Urestricted page table format
193230558Ssbruno * states that the segment length
194230558Ssbruno * and high base addr are in the first
195230558Ssbruno * 32 bits and the base low is in
196230558Ssbruno * the second
197230558Ssbruno */
198230558Ssbrunostruct unrestricted_page_table_fmt {
199230558Ssbruno	uint16_t segment_len;
200230558Ssbruno	uint16_t segment_base_high;
201230558Ssbruno	uint32_t segment_base_low;
202230558Ssbruno};
203230558Ssbruno
204230558Ssbruno
205121186Ssimokawastruct orb_info {
206121186Ssimokawa	struct sbp_targ_softc *sc;
207121186Ssimokawa	struct fw_device *fwdev;
208123430Ssimokawa	struct sbp_targ_login *login;
209121186Ssimokawa	union ccb *ccb;
210121186Ssimokawa	struct ccb_accept_tio *atio;
211129585Sdfr	uint8_t state;
212121186Ssimokawa#define ORBI_STATUS_NONE	0
213121186Ssimokawa#define ORBI_STATUS_FETCH	1
214121186Ssimokawa#define ORBI_STATUS_ATIO	2
215121186Ssimokawa#define ORBI_STATUS_CTIO	3
216121186Ssimokawa#define ORBI_STATUS_STATUS	4
217121186Ssimokawa#define ORBI_STATUS_POINTER	5
218121186Ssimokawa#define ORBI_STATUS_ABORTED	7
219129585Sdfr	uint8_t refcount;
220129585Sdfr	uint16_t orb_hi;
221129585Sdfr	uint32_t orb_lo;
222129585Sdfr	uint32_t data_hi;
223129585Sdfr	uint32_t data_lo;
224121186Ssimokawa	struct corb4 orb4;
225121186Ssimokawa	STAILQ_ENTRY(orb_info) link;
226129585Sdfr	uint32_t orb[8];
227230558Ssbruno	struct unrestricted_page_table_fmt *page_table;
228230558Ssbruno	struct unrestricted_page_table_fmt *cur_pte;
229230558Ssbruno	struct unrestricted_page_table_fmt *last_pte;
230230558Ssbruno	uint32_t  last_block_read;
231121186Ssimokawa	struct sbp_status status;
232121186Ssimokawa};
233121186Ssimokawa
234121186Ssimokawastatic char *orb_fun_name[] = {
235121186Ssimokawa	ORB_FUN_NAMES
236121186Ssimokawa};
237121186Ssimokawa
238121186Ssimokawastatic void sbp_targ_recv(struct fw_xfer *);
239121186Ssimokawastatic void sbp_targ_fetch_orb(struct sbp_targ_softc *, struct fw_device *,
240129585Sdfr    uint16_t, uint32_t, struct sbp_targ_login *, int);
241230558Ssbrunostatic void sbp_targ_xfer_pt(struct orb_info *);
242170374Ssimokawastatic void sbp_targ_abort(struct sbp_targ_softc *, struct orb_info *);
243121186Ssimokawa
244121186Ssimokawastatic void
245121186Ssimokawasbp_targ_identify(driver_t *driver, device_t parent)
246121186Ssimokawa{
247121186Ssimokawa	BUS_ADD_CHILD(parent, 0, "sbp_targ", device_get_unit(parent));
248121186Ssimokawa}
249121186Ssimokawa
250121186Ssimokawastatic int
251121186Ssimokawasbp_targ_probe(device_t dev)
252121186Ssimokawa{
253121186Ssimokawa	device_t pa;
254121186Ssimokawa
255121186Ssimokawa	pa = device_get_parent(dev);
256121186Ssimokawa	if(device_get_unit(dev) != device_get_unit(pa)){
257121186Ssimokawa		return(ENXIO);
258121186Ssimokawa	}
259121186Ssimokawa
260121186Ssimokawa	device_set_desc(dev, "SBP-2/SCSI over FireWire target mode");
261121186Ssimokawa	return (0);
262121186Ssimokawa}
263121186Ssimokawa
264121186Ssimokawastatic void
265123430Ssimokawasbp_targ_dealloc_login(struct sbp_targ_login *login)
266123430Ssimokawa{
267123430Ssimokawa	struct orb_info *orbi, *next;
268123430Ssimokawa
269123430Ssimokawa	if (login == NULL) {
270127468Ssimokawa		printf("%s: login = NULL\n", __func__);
271123430Ssimokawa		return;
272123430Ssimokawa	}
273123430Ssimokawa	for (orbi = STAILQ_FIRST(&login->orbs); orbi != NULL; orbi = next) {
274123430Ssimokawa		next = STAILQ_NEXT(orbi, link);
275230558Ssbruno		if (debug)
276230558Ssbruno			printf("%s: free orbi %p\n", __func__, orbi);
277123430Ssimokawa		free(orbi, M_SBP_TARG);
278230558Ssbruno		orbi = NULL;
279123430Ssimokawa	}
280123430Ssimokawa	callout_stop(&login->hold_callout);
281123430Ssimokawa
282123430Ssimokawa	STAILQ_REMOVE(&login->lstate->logins, login, sbp_targ_login, link);
283123430Ssimokawa	login->lstate->sc->logins[login->id] = NULL;
284230558Ssbruno	if (debug)
285230558Ssbruno		printf("%s: free login %p\n", __func__, login);
286123430Ssimokawa	free((void *)login, M_SBP_TARG);
287230558Ssbruno	login = NULL;
288123430Ssimokawa}
289123430Ssimokawa
290123430Ssimokawastatic void
291123430Ssimokawasbp_targ_hold_expire(void *arg)
292123430Ssimokawa{
293123430Ssimokawa	struct sbp_targ_login *login;
294123430Ssimokawa
295123430Ssimokawa	login = (struct sbp_targ_login *)arg;
296123430Ssimokawa
297123430Ssimokawa	if (login->flags & F_HOLD) {
298127468Ssimokawa		printf("%s: login_id=%d expired\n", __func__, login->id);
299123430Ssimokawa		sbp_targ_dealloc_login(login);
300123430Ssimokawa	} else {
301127468Ssimokawa		printf("%s: login_id=%d not hold\n", __func__, login->id);
302123430Ssimokawa	}
303123430Ssimokawa}
304123430Ssimokawa
305123430Ssimokawastatic void
306121186Ssimokawasbp_targ_post_busreset(void *arg)
307121186Ssimokawa{
308121186Ssimokawa	struct sbp_targ_softc *sc;
309121186Ssimokawa	struct crom_src *src;
310121186Ssimokawa	struct crom_chunk *root;
311121186Ssimokawa	struct crom_chunk *unit;
312121186Ssimokawa	struct sbp_targ_lstate *lstate;
313123430Ssimokawa	struct sbp_targ_login *login;
314121186Ssimokawa	int i;
315121186Ssimokawa
316123430Ssimokawa	sc = (struct sbp_targ_softc *)arg;
317121186Ssimokawa	src = sc->fd.fc->crom_src;
318121186Ssimokawa	root = sc->fd.fc->crom_root;
319121186Ssimokawa
320121186Ssimokawa	unit = &sc->unit;
321121186Ssimokawa
322123430Ssimokawa	if ((sc->flags & F_FREEZED) == 0) {
323170374Ssimokawa		SBP_LOCK(sc);
324123430Ssimokawa		sc->flags |= F_FREEZED;
325123430Ssimokawa		xpt_freeze_simq(sc->sim, /*count*/1);
326170374Ssimokawa		SBP_UNLOCK(sc);
327123430Ssimokawa	} else {
328127468Ssimokawa		printf("%s: already freezed\n", __func__);
329123430Ssimokawa	}
330123430Ssimokawa
331121186Ssimokawa	bzero(unit, sizeof(struct crom_chunk));
332121186Ssimokawa
333121186Ssimokawa	crom_add_chunk(src, root, unit, CROM_UDIR);
334121186Ssimokawa	crom_add_entry(unit, CSRKEY_SPEC, CSRVAL_ANSIT10);
335121186Ssimokawa	crom_add_entry(unit, CSRKEY_VER, CSRVAL_T10SBP2);
336121186Ssimokawa	crom_add_entry(unit, CSRKEY_COM_SPEC, CSRVAL_ANSIT10);
337121186Ssimokawa	crom_add_entry(unit, CSRKEY_COM_SET, CSRVAL_SCSI);
338121186Ssimokawa
339121186Ssimokawa	crom_add_entry(unit, CROM_MGM, SBP_TARG_MGM >> 2);
340121186Ssimokawa	crom_add_entry(unit, CSRKEY_UNIT_CH, (10<<8) | 8);
341121186Ssimokawa
342121186Ssimokawa	for (i = 0; i < MAX_LUN; i ++) {
343121186Ssimokawa		lstate = sc->lstate[i];
344121186Ssimokawa		if (lstate == NULL)
345121186Ssimokawa			continue;
346121186Ssimokawa		crom_add_entry(unit, CSRKEY_FIRM_VER, 1);
347121186Ssimokawa		crom_add_entry(unit, CROM_LUN, i);
348121186Ssimokawa		crom_add_entry(unit, CSRKEY_MODEL, 1);
349121186Ssimokawa		crom_add_simple_text(src, unit, &lstate->model, "TargetMode");
350121186Ssimokawa	}
351123430Ssimokawa
352123430Ssimokawa	/* Process for reconnection hold time */
353123430Ssimokawa	for (i = 0; i < MAX_LOGINS; i ++) {
354123430Ssimokawa		login = sc->logins[i];
355123430Ssimokawa		if (login == NULL)
356123430Ssimokawa			continue;
357170374Ssimokawa		sbp_targ_abort(sc, STAILQ_FIRST(&login->orbs));
358123430Ssimokawa		if (login->flags & F_LOGIN) {
359123430Ssimokawa			login->flags |= F_HOLD;
360123430Ssimokawa			callout_reset(&login->hold_callout,
361123430Ssimokawa			    hz * login->hold_sec,
362123430Ssimokawa			    sbp_targ_hold_expire, (void *)login);
363123430Ssimokawa		}
364123430Ssimokawa	}
365121186Ssimokawa}
366121186Ssimokawa
367123430Ssimokawastatic void
368123430Ssimokawasbp_targ_post_explore(void *arg)
369123430Ssimokawa{
370123430Ssimokawa	struct sbp_targ_softc *sc;
371123430Ssimokawa
372123430Ssimokawa	sc = (struct sbp_targ_softc *)arg;
373170374Ssimokawa	SBP_LOCK(sc);
374123430Ssimokawa	sc->flags &= ~F_FREEZED;
375123430Ssimokawa	xpt_release_simq(sc->sim, /*run queue*/TRUE);
376170374Ssimokawa	SBP_UNLOCK(sc);
377123430Ssimokawa	return;
378123430Ssimokawa}
379123430Ssimokawa
380121186Ssimokawastatic cam_status
381121186Ssimokawasbp_targ_find_devs(struct sbp_targ_softc *sc, union ccb *ccb,
382121186Ssimokawa    struct sbp_targ_lstate **lstate, int notfound_failure)
383121186Ssimokawa{
384121186Ssimokawa	u_int lun;
385121186Ssimokawa
386121186Ssimokawa	/* XXX 0 is the only vaild target_id */
387121186Ssimokawa	if (ccb->ccb_h.target_id == CAM_TARGET_WILDCARD &&
388121186Ssimokawa	    ccb->ccb_h.target_lun == CAM_LUN_WILDCARD) {
389121186Ssimokawa		*lstate = sc->black_hole;
390230558Ssbruno		if (debug)
391230558Ssbruno			printf("setting black hole for this target id(%d)\n", ccb->ccb_h.target_id);
392121186Ssimokawa		return (CAM_REQ_CMP);
393121186Ssimokawa	}
394121186Ssimokawa
395121186Ssimokawa	lun = ccb->ccb_h.target_lun;
396121186Ssimokawa	if (lun >= MAX_LUN)
397121186Ssimokawa		return (CAM_LUN_INVALID);
398121186Ssimokawa
399121186Ssimokawa	*lstate = sc->lstate[lun];
400121186Ssimokawa
401230558Ssbruno	if (notfound_failure != 0 && *lstate == NULL) {
402230558Ssbruno		if (debug)
403230558Ssbruno			printf("%s: lstate for lun is invalid, target(%d), lun(%d)\n",
404230558Ssbruno				__func__, ccb->ccb_h.target_id, lun);
405121186Ssimokawa		return (CAM_PATH_INVALID);
406230558Ssbruno	} else
407230558Ssbruno		if (debug)
408230558Ssbruno			printf("%s: setting lstate for tgt(%d) lun(%d)\n",
409230558Ssbruno				__func__,ccb->ccb_h.target_id, lun);
410121186Ssimokawa
411121186Ssimokawa	return (CAM_REQ_CMP);
412121186Ssimokawa}
413121186Ssimokawa
414121186Ssimokawastatic void
415121186Ssimokawasbp_targ_en_lun(struct sbp_targ_softc *sc, union ccb *ccb)
416121186Ssimokawa{
417121186Ssimokawa	struct ccb_en_lun *cel = &ccb->cel;
418121186Ssimokawa	struct sbp_targ_lstate *lstate;
419121186Ssimokawa	cam_status status;
420121186Ssimokawa
421121186Ssimokawa	status = sbp_targ_find_devs(sc, ccb, &lstate, 0);
422121186Ssimokawa	if (status != CAM_REQ_CMP) {
423121186Ssimokawa		ccb->ccb_h.status = status;
424121186Ssimokawa		return;
425121186Ssimokawa	}
426121186Ssimokawa
427121186Ssimokawa	if (cel->enable != 0) {
428121186Ssimokawa		if (lstate != NULL) {
429121186Ssimokawa			xpt_print_path(ccb->ccb_h.path);
430121186Ssimokawa			printf("Lun already enabled\n");
431121186Ssimokawa			ccb->ccb_h.status = CAM_LUN_ALRDY_ENA;
432121186Ssimokawa			return;
433121186Ssimokawa		}
434121186Ssimokawa		if (cel->grp6_len != 0 || cel->grp7_len != 0) {
435121186Ssimokawa			ccb->ccb_h.status = CAM_REQ_INVALID;
436121186Ssimokawa			printf("Non-zero Group Codes\n");
437121186Ssimokawa			return;
438121186Ssimokawa		}
439121186Ssimokawa		lstate = (struct sbp_targ_lstate *)
440121186Ssimokawa		    malloc(sizeof(*lstate), M_SBP_TARG, M_NOWAIT | M_ZERO);
441121186Ssimokawa		if (lstate == NULL) {
442121186Ssimokawa			xpt_print_path(ccb->ccb_h.path);
443121186Ssimokawa			printf("Couldn't allocate lstate\n");
444121186Ssimokawa			ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
445121186Ssimokawa			return;
446230558Ssbruno		} else {
447230558Ssbruno			if (debug)
448230558Ssbruno				printf("%s: malloc'd lstate %p\n",__func__, lstate);
449230558Ssbruno		}
450230558Ssbruno		if (ccb->ccb_h.target_id == CAM_TARGET_WILDCARD) {
451121186Ssimokawa			sc->black_hole = lstate;
452230558Ssbruno			if (debug)
453230558Ssbruno				printf("Blackhole set due to target id == %d\n",
454230558Ssbruno					ccb->ccb_h.target_id);
455230558Ssbruno		} else
456121186Ssimokawa			sc->lstate[ccb->ccb_h.target_lun] = lstate;
457230558Ssbruno
458121186Ssimokawa		memset(lstate, 0, sizeof(*lstate));
459121186Ssimokawa		lstate->sc = sc;
460121186Ssimokawa		status = xpt_create_path(&lstate->path, /*periph*/NULL,
461121186Ssimokawa					 xpt_path_path_id(ccb->ccb_h.path),
462121186Ssimokawa					 xpt_path_target_id(ccb->ccb_h.path),
463121186Ssimokawa					 xpt_path_lun_id(ccb->ccb_h.path));
464121186Ssimokawa		if (status != CAM_REQ_CMP) {
465121186Ssimokawa			free(lstate, M_SBP_TARG);
466230558Ssbruno			lstate = NULL;
467121186Ssimokawa			xpt_print_path(ccb->ccb_h.path);
468121186Ssimokawa			printf("Couldn't allocate path\n");
469121186Ssimokawa			ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
470121186Ssimokawa			return;
471121186Ssimokawa		}
472121186Ssimokawa		SLIST_INIT(&lstate->accept_tios);
473121186Ssimokawa		SLIST_INIT(&lstate->immed_notifies);
474123430Ssimokawa		STAILQ_INIT(&lstate->logins);
475121186Ssimokawa
476121186Ssimokawa		ccb->ccb_h.status = CAM_REQ_CMP;
477121186Ssimokawa		xpt_print_path(ccb->ccb_h.path);
478121186Ssimokawa		printf("Lun now enabled for target mode\n");
479121186Ssimokawa		/* bus reset */
480121186Ssimokawa		sc->fd.fc->ibr(sc->fd.fc);
481121186Ssimokawa	} else {
482123430Ssimokawa		struct sbp_targ_login *login, *next;
483123430Ssimokawa
484121186Ssimokawa		if (lstate == NULL) {
485121186Ssimokawa			ccb->ccb_h.status = CAM_LUN_INVALID;
486230558Ssbruno			printf("Invalid lstate for this target\n");
487121186Ssimokawa			return;
488121186Ssimokawa		}
489121186Ssimokawa		ccb->ccb_h.status = CAM_REQ_CMP;
490121186Ssimokawa
491121186Ssimokawa		if (SLIST_FIRST(&lstate->accept_tios) != NULL) {
492121186Ssimokawa			printf("ATIOs pending\n");
493121186Ssimokawa			ccb->ccb_h.status = CAM_REQ_INVALID;
494121186Ssimokawa		}
495121186Ssimokawa
496121186Ssimokawa		if (SLIST_FIRST(&lstate->immed_notifies) != NULL) {
497121186Ssimokawa			printf("INOTs pending\n");
498121186Ssimokawa			ccb->ccb_h.status = CAM_REQ_INVALID;
499121186Ssimokawa		}
500121186Ssimokawa
501121186Ssimokawa		if (ccb->ccb_h.status != CAM_REQ_CMP) {
502230558Ssbruno			printf("status != CAM_REQ_CMP\n");
503121186Ssimokawa			return;
504121186Ssimokawa		}
505121186Ssimokawa
506121186Ssimokawa		xpt_print_path(ccb->ccb_h.path);
507121186Ssimokawa		printf("Target mode disabled\n");
508121186Ssimokawa		xpt_free_path(lstate->path);
509121186Ssimokawa
510123430Ssimokawa		for (login = STAILQ_FIRST(&lstate->logins); login != NULL;
511123430Ssimokawa		    login = next) {
512123430Ssimokawa			next = STAILQ_NEXT(login, link);
513123430Ssimokawa			sbp_targ_dealloc_login(login);
514121186Ssimokawa		}
515121186Ssimokawa
516121186Ssimokawa		if (ccb->ccb_h.target_id == CAM_TARGET_WILDCARD)
517121186Ssimokawa			sc->black_hole = NULL;
518121186Ssimokawa		else
519121186Ssimokawa			sc->lstate[ccb->ccb_h.target_lun] = NULL;
520230558Ssbruno		if (debug)
521230558Ssbruno			printf("%s: free lstate %p\n", __func__, lstate);
522121186Ssimokawa		free(lstate, M_SBP_TARG);
523230558Ssbruno		lstate = NULL;
524121186Ssimokawa
525121186Ssimokawa		/* bus reset */
526121186Ssimokawa		sc->fd.fc->ibr(sc->fd.fc);
527121186Ssimokawa	}
528121186Ssimokawa}
529121186Ssimokawa
530121186Ssimokawastatic void
531121186Ssimokawasbp_targ_send_lstate_events(struct sbp_targ_softc *sc,
532121186Ssimokawa    struct sbp_targ_lstate *lstate)
533121186Ssimokawa{
534121186Ssimokawa#if 0
535121186Ssimokawa	struct ccb_hdr *ccbh;
536237601Sken	struct ccb_immediate_notify *inot;
537121186Ssimokawa
538127468Ssimokawa	printf("%s: not implemented yet\n", __func__);
539121186Ssimokawa#endif
540121186Ssimokawa}
541121186Ssimokawa
542170374Ssimokawa
543121186Ssimokawastatic __inline void
544170374Ssimokawasbp_targ_remove_orb_info_locked(struct sbp_targ_login *login, struct orb_info *orbi)
545170374Ssimokawa{
546170374Ssimokawa	STAILQ_REMOVE(&login->orbs, orbi, orb_info, link);
547170374Ssimokawa}
548170374Ssimokawa
549170374Ssimokawastatic __inline void
550123430Ssimokawasbp_targ_remove_orb_info(struct sbp_targ_login *login, struct orb_info *orbi)
551121186Ssimokawa{
552170374Ssimokawa	SBP_LOCK(orbi->sc);
553123430Ssimokawa	STAILQ_REMOVE(&login->orbs, orbi, orb_info, link);
554170374Ssimokawa	SBP_UNLOCK(orbi->sc);
555121186Ssimokawa}
556121186Ssimokawa
557121186Ssimokawa/*
558121186Ssimokawa * tag_id/init_id encoding
559121186Ssimokawa *
560121186Ssimokawa * tag_id and init_id has only 32bit for each.
561121186Ssimokawa * scsi_target can handle very limited number(up to 15) of init_id.
562121186Ssimokawa * we have to encode 48bit orb and 64bit EUI64 into these
563121186Ssimokawa * variables.
564121186Ssimokawa *
565121186Ssimokawa * tag_id represents lower 32bit of ORB address.
566123430Ssimokawa * init_id represents login_id.
567121186Ssimokawa *
568121186Ssimokawa */
569121186Ssimokawa
570121186Ssimokawastatic struct orb_info *
571121186Ssimokawasbp_targ_get_orb_info(struct sbp_targ_lstate *lstate,
572121186Ssimokawa    u_int tag_id, u_int init_id)
573121186Ssimokawa{
574123430Ssimokawa	struct sbp_targ_login *login;
575121186Ssimokawa	struct orb_info *orbi;
576121186Ssimokawa
577123430Ssimokawa	login = lstate->sc->logins[init_id];
578123430Ssimokawa	if (login == NULL) {
579127468Ssimokawa		printf("%s: no such login\n", __func__);
580123430Ssimokawa		return (NULL);
581123430Ssimokawa	}
582123430Ssimokawa	STAILQ_FOREACH(orbi, &login->orbs, link)
583123430Ssimokawa		if (orbi->orb_lo == tag_id)
584121186Ssimokawa			goto found;
585170374Ssimokawa	printf("%s: orb not found tag_id=0x%08x init_id=%d\n",
586230558Ssbruno			 __func__, tag_id, init_id);
587121186Ssimokawa	return (NULL);
588121186Ssimokawafound:
589121186Ssimokawa	return (orbi);
590121186Ssimokawa}
591121186Ssimokawa
592121186Ssimokawastatic void
593170374Ssimokawasbp_targ_abort(struct sbp_targ_softc *sc, struct orb_info *orbi)
594121186Ssimokawa{
595121186Ssimokawa	struct orb_info *norbi;
596121186Ssimokawa
597170374Ssimokawa	SBP_LOCK(sc);
598121186Ssimokawa	for (; orbi != NULL; orbi = norbi) {
599170374Ssimokawa		printf("%s: status=%d ccb=%p\n", __func__, orbi->state, orbi->ccb);
600121186Ssimokawa		norbi = STAILQ_NEXT(orbi, link);
601121186Ssimokawa		if (orbi->state != ORBI_STATUS_ABORTED) {
602121186Ssimokawa			if (orbi->ccb != NULL) {
603121186Ssimokawa				orbi->ccb->ccb_h.status = CAM_REQ_ABORTED;
604121186Ssimokawa				xpt_done(orbi->ccb);
605121186Ssimokawa				orbi->ccb = NULL;
606121186Ssimokawa			}
607121186Ssimokawa			if (orbi->state <= ORBI_STATUS_ATIO) {
608170374Ssimokawa				sbp_targ_remove_orb_info_locked(orbi->login, orbi);
609230558Ssbruno				if (debug)
610230558Ssbruno					printf("%s: free orbi %p\n", __func__, orbi);
611121186Ssimokawa				free(orbi, M_SBP_TARG);
612230558Ssbruno				orbi = NULL;
613121186Ssimokawa			} else
614121186Ssimokawa				orbi->state = ORBI_STATUS_ABORTED;
615121186Ssimokawa		}
616121186Ssimokawa	}
617170374Ssimokawa	SBP_UNLOCK(sc);
618121186Ssimokawa}
619121186Ssimokawa
620121186Ssimokawastatic void
621121186Ssimokawasbp_targ_free_orbi(struct fw_xfer *xfer)
622121186Ssimokawa{
623121186Ssimokawa	struct orb_info *orbi;
624121186Ssimokawa
625121186Ssimokawa	if (xfer->resp != 0) {
626121186Ssimokawa		/* XXX */
627127468Ssimokawa		printf("%s: xfer->resp = %d\n", __func__, xfer->resp);
628121186Ssimokawa	}
629230558Ssbruno	orbi = (struct orb_info *)xfer->sc;
630230558Ssbruno	if ( orbi->page_table != NULL ) {
631230558Ssbruno		if (debug)
632230558Ssbruno			printf("%s:  free orbi->page_table %p\n", __func__, orbi->page_table);
633230558Ssbruno		free(orbi->page_table, M_SBP_TARG);
634230558Ssbruno		orbi->page_table = NULL;
635230558Ssbruno	}
636230558Ssbruno	if (debug)
637230558Ssbruno		printf("%s: free orbi %p\n", __func__, orbi);
638121186Ssimokawa	free(orbi, M_SBP_TARG);
639230558Ssbruno	orbi = NULL;
640121186Ssimokawa	fw_xfer_free(xfer);
641121186Ssimokawa}
642121186Ssimokawa
643121186Ssimokawastatic void
644121186Ssimokawasbp_targ_status_FIFO(struct orb_info *orbi,
645129585Sdfr    uint32_t fifo_hi, uint32_t fifo_lo, int dequeue)
646121186Ssimokawa{
647121186Ssimokawa	struct fw_xfer *xfer;
648121186Ssimokawa
649121186Ssimokawa	if (dequeue)
650123430Ssimokawa		sbp_targ_remove_orb_info(orbi->login, orbi);
651121186Ssimokawa
652121186Ssimokawa	xfer = fwmem_write_block(orbi->fwdev, (void *)orbi,
653230558Ssbruno	    /*spd*/FWSPD_S400, fifo_hi, fifo_lo,
654129585Sdfr	    sizeof(uint32_t) * (orbi->status.len + 1), (char *)&orbi->status,
655121186Ssimokawa	    sbp_targ_free_orbi);
656121186Ssimokawa
657121186Ssimokawa	if (xfer == NULL) {
658121186Ssimokawa		/* XXX */
659127468Ssimokawa		printf("%s: xfer == NULL\n", __func__);
660121186Ssimokawa	}
661121186Ssimokawa}
662121186Ssimokawa
663230558Ssbruno/*
664230558Ssbruno * Generate the appropriate CAM status for the
665230558Ssbruno * target.
666230558Ssbruno */
667121186Ssimokawastatic void
668121186Ssimokawasbp_targ_send_status(struct orb_info *orbi, union ccb *ccb)
669121186Ssimokawa{
670121186Ssimokawa	struct sbp_status *sbp_status;
671170410Smjacob#if	0
672170374Ssimokawa	struct orb_info *norbi;
673170410Smjacob#endif
674121186Ssimokawa
675121186Ssimokawa	sbp_status = &orbi->status;
676121186Ssimokawa
677121186Ssimokawa	orbi->state = ORBI_STATUS_STATUS;
678121186Ssimokawa
679121186Ssimokawa	sbp_status->resp = 0; /* XXX */
680121186Ssimokawa	sbp_status->status = 0; /* XXX */
681121186Ssimokawa	sbp_status->dead = 0; /* XXX */
682121186Ssimokawa
683230558Ssbruno	ccb->ccb_h.status= CAM_REQ_CMP;
684230558Ssbruno
685121186Ssimokawa	switch (ccb->csio.scsi_status) {
686121186Ssimokawa	case SCSI_STATUS_OK:
687121186Ssimokawa		if (debug)
688127468Ssimokawa			printf("%s: STATUS_OK\n", __func__);
689121186Ssimokawa		sbp_status->len = 1;
690121186Ssimokawa		break;
691121186Ssimokawa	case SCSI_STATUS_CHECK_COND:
692230558Ssbruno		if (debug)
693230558Ssbruno			printf("%s: STATUS SCSI_STATUS_CHECK_COND\n", __func__);
694230558Ssbruno		goto process_scsi_status;
695121186Ssimokawa	case SCSI_STATUS_BUSY:
696230558Ssbruno		if (debug)
697230558Ssbruno			printf("%s: STATUS SCSI_STATUS_BUSY\n", __func__);
698230558Ssbruno		goto process_scsi_status;
699121186Ssimokawa	case SCSI_STATUS_CMD_TERMINATED:
700230558Ssbrunoprocess_scsi_status:
701121186Ssimokawa	{
702121186Ssimokawa		struct sbp_cmd_status *sbp_cmd_status;
703121186Ssimokawa		struct scsi_sense_data *sense;
704225950Sken		int error_code, sense_key, asc, ascq;
705225950Sken		uint8_t stream_bits;
706225950Sken		uint8_t sks[3];
707225950Sken		uint64_t info;
708225950Sken		int64_t sinfo;
709225950Sken		int sense_len;
710121186Ssimokawa
711121186Ssimokawa		sbp_cmd_status = (struct sbp_cmd_status *)&sbp_status->data[0];
712121186Ssimokawa		sbp_cmd_status->status = ccb->csio.scsi_status;
713121186Ssimokawa		sense = &ccb->csio.sense_data;
714121186Ssimokawa
715170374Ssimokawa#if 0		/* XXX What we should do? */
716170374Ssimokawa#if 0
717170374Ssimokawa		sbp_targ_abort(orbi->sc, STAILQ_NEXT(orbi, link));
718170374Ssimokawa#else
719170374Ssimokawa		norbi = STAILQ_NEXT(orbi, link);
720170374Ssimokawa		while (norbi) {
721170374Ssimokawa			printf("%s: status=%d\n", __func__, norbi->state);
722170374Ssimokawa			if (norbi->ccb != NULL) {
723170374Ssimokawa				norbi->ccb->ccb_h.status = CAM_REQ_ABORTED;
724170374Ssimokawa				xpt_done(norbi->ccb);
725170374Ssimokawa				norbi->ccb = NULL;
726170374Ssimokawa			}
727170374Ssimokawa			sbp_targ_remove_orb_info_locked(orbi->login, norbi);
728170374Ssimokawa			norbi = STAILQ_NEXT(norbi, link);
729170374Ssimokawa			free(norbi, M_SBP_TARG);
730170374Ssimokawa		}
731170374Ssimokawa#endif
732170374Ssimokawa#endif
733121186Ssimokawa
734225950Sken		sense_len = ccb->csio.sense_len - ccb->csio.sense_resid;
735225950Sken		scsi_extract_sense_len(sense, sense_len, &error_code,
736225950Sken		    &sense_key, &asc, &ascq, /*show_errors*/ 0);
737225950Sken
738225950Sken		switch (error_code) {
739225950Sken		case SSD_CURRENT_ERROR:
740225950Sken		case SSD_DESC_CURRENT_ERROR:
741121186Ssimokawa			sbp_cmd_status->sfmt = SBP_SFMT_CURR;
742225950Sken			break;
743225950Sken		default:
744121186Ssimokawa			sbp_cmd_status->sfmt = SBP_SFMT_DEFER;
745225950Sken			break;
746225950Sken		}
747121186Ssimokawa
748225950Sken		if (scsi_get_sense_info(sense, sense_len, SSD_DESC_INFO, &info,
749225950Sken					&sinfo) == 0) {
750225950Sken			uint32_t info_trunc;
751225950Sken			sbp_cmd_status->valid = 1;
752225950Sken			info_trunc = info;
753121186Ssimokawa
754225950Sken			sbp_cmd_status->info = htobe32(info_trunc);
755225950Sken		} else {
756225950Sken			sbp_cmd_status->valid = 0;
757225950Sken		}
758121186Ssimokawa
759225950Sken		sbp_cmd_status->s_key = sense_key;
760225950Sken
761225950Sken		if (scsi_get_stream_info(sense, sense_len, NULL,
762225950Sken					 &stream_bits) == 0) {
763225950Sken			sbp_cmd_status->mark =
764225950Sken			    (stream_bits & SSD_FILEMARK) ? 1 : 0;
765225950Sken			sbp_cmd_status->eom =
766225950Sken			    (stream_bits & SSD_EOM) ? 1 : 0;
767225950Sken			sbp_cmd_status->ill_len =
768225950Sken			    (stream_bits & SSD_ILI) ? 1 : 0;
769225950Sken		} else {
770225950Sken			sbp_cmd_status->mark = 0;
771225950Sken			sbp_cmd_status->eom = 0;
772225950Sken			sbp_cmd_status->ill_len = 0;
773225950Sken		}
774225950Sken
775225950Sken
776225950Sken		/* add_sense_code(_qual), info, cmd_spec_info */
777225950Sken		sbp_status->len = 4;
778225950Sken
779225950Sken		if (scsi_get_sense_info(sense, sense_len, SSD_DESC_COMMAND,
780225950Sken					&info, &sinfo) == 0) {
781225950Sken			uint32_t cmdspec_trunc;
782225950Sken
783225950Sken			cmdspec_trunc = info;
784225950Sken
785225950Sken			sbp_cmd_status->cdb = htobe32(cmdspec_trunc);
786225950Sken		}
787225950Sken
788225950Sken		sbp_cmd_status->s_code = asc;
789225950Sken		sbp_cmd_status->s_qlfr = ascq;
790225950Sken
791225950Sken		if (scsi_get_sense_info(sense, sense_len, SSD_DESC_FRU, &info,
792225950Sken					&sinfo) == 0) {
793225950Sken			sbp_cmd_status->fru = (uint8_t)info;
794121186Ssimokawa			sbp_status->len = 5;
795225950Sken		} else {
796225950Sken			sbp_cmd_status->fru = 0;
797225950Sken		}
798121186Ssimokawa
799225950Sken		if (scsi_get_sks(sense, sense_len, sks) == 0) {
800225950Sken			bcopy(sks, &sbp_cmd_status->s_keydep[0], sizeof(sks));
801225950Sken			sbp_status->len = 5;
802230558Ssbruno			ccb->ccb_h.status |= CAM_SENT_SENSE;
803225950Sken		}
804121186Ssimokawa
805121186Ssimokawa		break;
806121186Ssimokawa	}
807121186Ssimokawa	default:
808127468Ssimokawa		printf("%s: unknown scsi status 0x%x\n", __func__,
809121186Ssimokawa		    sbp_status->status);
810121186Ssimokawa	}
811121186Ssimokawa
812170374Ssimokawa
813121186Ssimokawa	sbp_targ_status_FIFO(orbi,
814123430Ssimokawa	    orbi->login->fifo_hi, orbi->login->fifo_lo, /*dequeue*/1);
815121186Ssimokawa}
816121186Ssimokawa
817230558Ssbruno/*
818230558Ssbruno * Invoked as a callback handler from fwmem_read/write_block
819230558Ssbruno *
820230558Ssbruno * Process read/write of initiator address space
821230558Ssbruno * completion and pass status onto the backend target.
822230558Ssbruno * If this is a partial read/write for a CCB then
823230558Ssbruno * we decrement the orbi's refcount to indicate
824230558Ssbruno * the status of the read/write is complete
825230558Ssbruno */
826121186Ssimokawastatic void
827121186Ssimokawasbp_targ_cam_done(struct fw_xfer *xfer)
828121186Ssimokawa{
829121186Ssimokawa	struct orb_info *orbi;
830121186Ssimokawa	union ccb *ccb;
831121186Ssimokawa
832121186Ssimokawa	orbi = (struct orb_info *)xfer->sc;
833121186Ssimokawa
834230558Ssbruno	if (debug)
835127468Ssimokawa		printf("%s: resp=%d refcount=%d\n", __func__,
836121186Ssimokawa			xfer->resp, orbi->refcount);
837121186Ssimokawa
838121186Ssimokawa	if (xfer->resp != 0) {
839127468Ssimokawa		printf("%s: xfer->resp = %d\n", __func__, xfer->resp);
840121186Ssimokawa		orbi->status.resp = SBP_TRANS_FAIL;
841124877Ssimokawa		orbi->status.status = OBJ_DATA | SBE_TIMEOUT/*XXX*/;
842121186Ssimokawa		orbi->status.dead = 1;
843170374Ssimokawa		sbp_targ_abort(orbi->sc, STAILQ_NEXT(orbi, link));
844121186Ssimokawa	}
845121186Ssimokawa
846121186Ssimokawa	orbi->refcount --;
847121186Ssimokawa
848121186Ssimokawa	ccb = orbi->ccb;
849121186Ssimokawa	if (orbi->refcount == 0) {
850170374Ssimokawa		orbi->ccb = NULL;
851121186Ssimokawa		if (orbi->state == ORBI_STATUS_ABORTED) {
852121186Ssimokawa			if (debug)
853127468Ssimokawa				printf("%s: orbi aborted\n", __func__);
854123430Ssimokawa			sbp_targ_remove_orb_info(orbi->login, orbi);
855230558Ssbruno			if (orbi->page_table != NULL) {
856230558Ssbruno				if (debug)
857230558Ssbruno					printf("%s: free orbi->page_table %p\n",
858230558Ssbruno						__func__, orbi->page_table);
859121186Ssimokawa				free(orbi->page_table, M_SBP_TARG);
860230558Ssbruno			}
861230558Ssbruno			if (debug)
862230558Ssbruno				printf("%s: free orbi %p\n", __func__, orbi);
863121186Ssimokawa			free(orbi, M_SBP_TARG);
864230558Ssbruno			orbi = NULL;
865230558Ssbruno		} else if (orbi->status.resp == ORBI_STATUS_NONE) {
866230558Ssbruno			if ((ccb->ccb_h.flags & CAM_SEND_STATUS) != 0) {
867230558Ssbruno				if (debug)
868230558Ssbruno					printf("%s: CAM_SEND_STATUS set %0x\n", __func__, ccb->ccb_h.flags);
869121186Ssimokawa				sbp_targ_send_status(orbi, ccb);
870230558Ssbruno			} else {
871230558Ssbruno				if (debug)
872230558Ssbruno					printf("%s: CAM_SEND_STATUS not set %0x\n", __func__, ccb->ccb_h.flags);
873230558Ssbruno				ccb->ccb_h.status = CAM_REQ_CMP;
874230558Ssbruno			}
875170374Ssimokawa			SBP_LOCK(orbi->sc);
876121186Ssimokawa			xpt_done(ccb);
877170374Ssimokawa			SBP_UNLOCK(orbi->sc);
878121186Ssimokawa		} else {
879121186Ssimokawa			orbi->status.len = 1;
880121186Ssimokawa			sbp_targ_status_FIFO(orbi,
881123430Ssimokawa		    	    orbi->login->fifo_hi, orbi->login->fifo_lo,
882121186Ssimokawa			    /*dequeue*/1);
883121186Ssimokawa			ccb->ccb_h.status = CAM_REQ_ABORTED;
884170374Ssimokawa			SBP_LOCK(orbi->sc);
885121186Ssimokawa			xpt_done(ccb);
886170374Ssimokawa			SBP_UNLOCK(orbi->sc);
887121186Ssimokawa		}
888121186Ssimokawa	}
889121186Ssimokawa
890121186Ssimokawa	fw_xfer_free(xfer);
891121186Ssimokawa}
892121186Ssimokawa
893121186Ssimokawastatic cam_status
894121186Ssimokawasbp_targ_abort_ccb(struct sbp_targ_softc *sc, union ccb *ccb)
895121186Ssimokawa{
896121186Ssimokawa	union ccb *accb;
897121186Ssimokawa	struct sbp_targ_lstate *lstate;
898121186Ssimokawa	struct ccb_hdr_slist *list;
899121186Ssimokawa	struct ccb_hdr *curelm;
900121186Ssimokawa	int found;
901121186Ssimokawa	cam_status status;
902121186Ssimokawa
903121186Ssimokawa	status = sbp_targ_find_devs(sc, ccb, &lstate, 0);
904121186Ssimokawa	if (status != CAM_REQ_CMP)
905121186Ssimokawa		return (status);
906121186Ssimokawa
907121186Ssimokawa	accb = ccb->cab.abort_ccb;
908121186Ssimokawa
909121186Ssimokawa	if (accb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO)
910121186Ssimokawa		list = &lstate->accept_tios;
911237601Sken	else if (accb->ccb_h.func_code == XPT_IMMEDIATE_NOTIFY)
912121186Ssimokawa		list = &lstate->immed_notifies;
913121186Ssimokawa	else
914121186Ssimokawa		return (CAM_UA_ABORT);
915121186Ssimokawa
916121186Ssimokawa	curelm = SLIST_FIRST(list);
917121186Ssimokawa	found = 0;
918121186Ssimokawa	if (curelm == &accb->ccb_h) {
919121186Ssimokawa		found = 1;
920121186Ssimokawa		SLIST_REMOVE_HEAD(list, sim_links.sle);
921121186Ssimokawa	} else {
922121186Ssimokawa		while(curelm != NULL) {
923121186Ssimokawa			struct ccb_hdr *nextelm;
924121186Ssimokawa
925121186Ssimokawa			nextelm = SLIST_NEXT(curelm, sim_links.sle);
926121186Ssimokawa			if (nextelm == &accb->ccb_h) {
927121186Ssimokawa				found = 1;
928121186Ssimokawa				SLIST_NEXT(curelm, sim_links.sle) =
929121186Ssimokawa				    SLIST_NEXT(nextelm, sim_links.sle);
930121186Ssimokawa				break;
931121186Ssimokawa			}
932121186Ssimokawa			curelm = nextelm;
933121186Ssimokawa		}
934121186Ssimokawa	}
935121186Ssimokawa	if (found) {
936121186Ssimokawa		accb->ccb_h.status = CAM_REQ_ABORTED;
937121186Ssimokawa		xpt_done(accb);
938121186Ssimokawa		return (CAM_REQ_CMP);
939121186Ssimokawa	}
940127468Ssimokawa	printf("%s: not found\n", __func__);
941121186Ssimokawa	return (CAM_PATH_INVALID);
942121186Ssimokawa}
943121186Ssimokawa
944230558Ssbruno/*
945230558Ssbruno * directly execute a read or write to the initiator
946230558Ssbruno * address space and set hand(sbp_targ_cam_done) to
947230558Ssbruno * process the completion from the SIM to the target.
948230558Ssbruno * set orbi->refcount to inidicate that a read/write
949230558Ssbruno * is inflight to/from the initiator.
950230558Ssbruno */
951121186Ssimokawastatic void
952121186Ssimokawasbp_targ_xfer_buf(struct orb_info *orbi, u_int offset,
953129585Sdfr    uint16_t dst_hi, uint32_t dst_lo, u_int size,
954121186Ssimokawa    void (*hand)(struct fw_xfer *))
955121186Ssimokawa{
956121186Ssimokawa	struct fw_xfer *xfer;
957121186Ssimokawa	u_int len, ccb_dir, off = 0;
958121186Ssimokawa	char *ptr;
959121186Ssimokawa
960123430Ssimokawa	if (debug > 1)
961127468Ssimokawa		printf("%s: offset=%d size=%d\n", __func__, offset, size);
962121186Ssimokawa	ccb_dir = orbi->ccb->ccb_h.flags & CAM_DIR_MASK;
963121186Ssimokawa	ptr = (char *)orbi->ccb->csio.data_ptr + offset;
964121186Ssimokawa
965121186Ssimokawa	while (size > 0) {
966121186Ssimokawa		/* XXX assume dst_lo + off doesn't overflow */
967121186Ssimokawa		len = MIN(size, 2048 /* XXX */);
968121186Ssimokawa		size -= len;
969121186Ssimokawa		orbi->refcount ++;
970230558Ssbruno		if (ccb_dir == CAM_DIR_OUT) {
971230558Ssbruno			if (debug)
972230558Ssbruno				printf("%s: CAM_DIR_OUT --> read block in?\n",__func__);
973121186Ssimokawa			xfer = fwmem_read_block(orbi->fwdev,
974230558Ssbruno			   (void *)orbi, /*spd*/FWSPD_S400,
975121186Ssimokawa			    dst_hi, dst_lo + off, len,
976121186Ssimokawa			    ptr + off, hand);
977230558Ssbruno		} else {
978230558Ssbruno			if (debug)
979230558Ssbruno				printf("%s: CAM_DIR_IN --> write block out?\n",__func__);
980121186Ssimokawa			xfer = fwmem_write_block(orbi->fwdev,
981230558Ssbruno			   (void *)orbi, /*spd*/FWSPD_S400,
982121186Ssimokawa			    dst_hi, dst_lo + off, len,
983121186Ssimokawa			    ptr + off, hand);
984230558Ssbruno		}
985121186Ssimokawa		if (xfer == NULL) {
986127468Ssimokawa			printf("%s: xfer == NULL", __func__);
987121186Ssimokawa			/* XXX what should we do?? */
988121186Ssimokawa			orbi->refcount --;
989121186Ssimokawa		}
990121186Ssimokawa		off += len;
991121186Ssimokawa	}
992121186Ssimokawa}
993121186Ssimokawa
994121186Ssimokawastatic void
995121186Ssimokawasbp_targ_pt_done(struct fw_xfer *xfer)
996121186Ssimokawa{
997121186Ssimokawa	struct orb_info *orbi;
998230558Ssbruno	struct unrestricted_page_table_fmt *pt;
999230558Ssbruno	uint32_t i;
1000121186Ssimokawa
1001121186Ssimokawa	orbi = (struct orb_info *)xfer->sc;
1002230558Ssbruno
1003121186Ssimokawa	if (orbi->state == ORBI_STATUS_ABORTED) {
1004121186Ssimokawa		if (debug)
1005127468Ssimokawa			printf("%s: orbi aborted\n", __func__);
1006123430Ssimokawa		sbp_targ_remove_orb_info(orbi->login, orbi);
1007230558Ssbruno		if (debug) {
1008230558Ssbruno			printf("%s: free orbi->page_table %p\n", __func__, orbi->page_table);
1009230558Ssbruno			printf("%s: free orbi %p\n", __func__, orbi);
1010230558Ssbruno		}
1011121186Ssimokawa		free(orbi->page_table, M_SBP_TARG);
1012121186Ssimokawa		free(orbi, M_SBP_TARG);
1013230558Ssbruno		orbi = NULL;
1014121186Ssimokawa		fw_xfer_free(xfer);
1015121186Ssimokawa		return;
1016121186Ssimokawa	}
1017121186Ssimokawa	if (xfer->resp != 0) {
1018127468Ssimokawa		printf("%s: xfer->resp = %d\n", __func__, xfer->resp);
1019121186Ssimokawa		orbi->status.resp = SBP_TRANS_FAIL;
1020124877Ssimokawa		orbi->status.status = OBJ_PT | SBE_TIMEOUT/*XXX*/;
1021121186Ssimokawa		orbi->status.dead = 1;
1022121186Ssimokawa		orbi->status.len = 1;
1023170374Ssimokawa		sbp_targ_abort(orbi->sc, STAILQ_NEXT(orbi, link));
1024121186Ssimokawa
1025230558Ssbruno		if (debug)
1026230558Ssbruno			printf("%s: free orbi->page_table %p\n", __func__, orbi->page_table);
1027230558Ssbruno
1028121186Ssimokawa		sbp_targ_status_FIFO(orbi,
1029123430Ssimokawa		    orbi->login->fifo_hi, orbi->login->fifo_lo, /*dequeue*/1);
1030121186Ssimokawa		free(orbi->page_table, M_SBP_TARG);
1031230558Ssbruno		orbi->page_table = NULL;
1032121186Ssimokawa		fw_xfer_free(xfer);
1033121186Ssimokawa		return;
1034121186Ssimokawa	}
1035230558Ssbruno	orbi->refcount++;
1036230558Ssbruno/*
1037230558Ssbruno * Set endianess here so we don't have
1038230558Ssbruno * to deal with is later
1039230558Ssbruno */
1040230558Ssbruno	for (i = 0, pt = orbi->page_table; i < orbi->orb4.data_size; i++, pt++) {
1041230558Ssbruno		pt->segment_len = ntohs(pt->segment_len);
1042230558Ssbruno		if (debug)
1043230558Ssbruno			printf("%s:segment_len = %u\n", __func__,pt->segment_len);
1044230558Ssbruno		pt->segment_base_high = ntohs(pt->segment_base_high);
1045230558Ssbruno		pt->segment_base_low = ntohl(pt->segment_base_low);
1046121186Ssimokawa	}
1047230558Ssbruno
1048230558Ssbruno	sbp_targ_xfer_pt(orbi);
1049230558Ssbruno
1050230558Ssbruno	orbi->refcount--;
1051121186Ssimokawa	if (orbi->refcount == 0)
1052127468Ssimokawa		printf("%s: refcount == 0\n", __func__);
1053121186Ssimokawa
1054121186Ssimokawa	fw_xfer_free(xfer);
1055121186Ssimokawa	return;
1056121186Ssimokawa}
1057121186Ssimokawa
1058230558Ssbrunostatic void sbp_targ_xfer_pt(struct orb_info *orbi)
1059230558Ssbruno{
1060230558Ssbruno	union ccb *ccb;
1061230558Ssbruno	uint32_t res, offset, len;
1062230558Ssbruno
1063230558Ssbruno	ccb = orbi->ccb;
1064230558Ssbruno	if (debug)
1065230558Ssbruno		printf("%s: dxfer_len=%d\n", __func__, ccb->csio.dxfer_len);
1066230558Ssbruno	res = ccb->csio.dxfer_len;
1067230558Ssbruno	/*
1068230558Ssbruno	 * If the page table required multiple CTIO's to
1069230558Ssbruno	 * complete, then cur_pte is non NULL
1070230558Ssbruno	 * and we need to start from the last position
1071230558Ssbruno	 * If this is the first pass over a page table
1072230558Ssbruno	 * then we just start at the beginning of the page
1073230558Ssbruno	 * table.
1074230558Ssbruno	 *
1075230558Ssbruno	 * Parse the unrestricted page table and figure out where we need
1076230558Ssbruno	 * to shove the data from this read request.
1077230558Ssbruno	 */
1078230558Ssbruno	for (offset = 0, len = 0; (res != 0) && (orbi->cur_pte < orbi->last_pte); offset += len) {
1079230558Ssbruno		len = MIN(orbi->cur_pte->segment_len, res);
1080230558Ssbruno		res -= len;
1081230558Ssbruno		if (debug)
1082230558Ssbruno			printf("%s:page_table: %04x:%08x segment_len(%u) res(%u) len(%u)\n",
1083230558Ssbruno				__func__, orbi->cur_pte->segment_base_high,
1084230558Ssbruno				orbi->cur_pte->segment_base_low,
1085230558Ssbruno				orbi->cur_pte->segment_len,
1086230558Ssbruno				res, len);
1087230558Ssbruno		sbp_targ_xfer_buf(orbi, offset,
1088230558Ssbruno				orbi->cur_pte->segment_base_high,
1089230558Ssbruno				orbi->cur_pte->segment_base_low,
1090230558Ssbruno				len, sbp_targ_cam_done);
1091230558Ssbruno		/*
1092230558Ssbruno		 * If we have only written partially to
1093230558Ssbruno		 * this page table, then we need to save
1094230558Ssbruno		 * our position for the next CTIO.  If we
1095230558Ssbruno		 * have completed the page table, then we
1096230558Ssbruno		 * are safe to move on to the next entry.
1097230558Ssbruno		 */
1098230558Ssbruno		if (len == orbi->cur_pte->segment_len) {
1099230558Ssbruno			orbi->cur_pte++;
1100230558Ssbruno		} else {
1101230558Ssbruno			uint32_t saved_base_low;
1102230558Ssbruno
1103230558Ssbruno			/* Handle transfers that cross a 4GB boundary. */
1104230558Ssbruno			saved_base_low = orbi->cur_pte->segment_base_low;
1105230558Ssbruno			orbi->cur_pte->segment_base_low += len;
1106230558Ssbruno			if (orbi->cur_pte->segment_base_low < saved_base_low)
1107230558Ssbruno				orbi->cur_pte->segment_base_high++;
1108230558Ssbruno
1109230558Ssbruno			orbi->cur_pte->segment_len -= len;
1110230558Ssbruno		}
1111230558Ssbruno	}
1112230558Ssbruno	if (debug) {
1113230558Ssbruno		printf("%s: base_low(%08x) page_table_off(%p) last_block(%u)\n",
1114230558Ssbruno			__func__, orbi->cur_pte->segment_base_low,
1115230558Ssbruno			orbi->cur_pte, orbi->last_block_read);
1116230558Ssbruno	}
1117230558Ssbruno	if (res != 0)
1118230558Ssbruno		printf("Warning - short pt encountered.  "
1119230558Ssbruno			"Could not transfer all data.\n");
1120230558Ssbruno	return;
1121230558Ssbruno}
1122230558Ssbruno
1123230558Ssbruno/*
1124230558Ssbruno * Create page table in local memory
1125230558Ssbruno * and transfer it from the initiator
1126230558Ssbruno * in order to know where we are supposed
1127230558Ssbruno * to put the data.
1128230558Ssbruno */
1129230558Ssbruno
1130121186Ssimokawastatic void
1131121186Ssimokawasbp_targ_fetch_pt(struct orb_info *orbi)
1132121186Ssimokawa{
1133121186Ssimokawa	struct fw_xfer *xfer;
1134121186Ssimokawa
1135230558Ssbruno	/*
1136230558Ssbruno	 * Pull in page table from initiator
1137230558Ssbruno	 * and setup for data from our
1138230558Ssbruno	 * backend device.
1139230558Ssbruno	 */
1140230558Ssbruno	if (orbi->page_table == NULL) {
1141230558Ssbruno		orbi->page_table = malloc(orbi->orb4.data_size*
1142230558Ssbruno					  sizeof(struct unrestricted_page_table_fmt),
1143230558Ssbruno					  M_SBP_TARG, M_NOWAIT|M_ZERO);
1144230558Ssbruno		if (orbi->page_table == NULL)
1145230558Ssbruno			goto error;
1146230558Ssbruno		orbi->cur_pte = orbi->page_table;
1147230558Ssbruno		orbi->last_pte = orbi->page_table + orbi->orb4.data_size;
1148230558Ssbruno		orbi->last_block_read = orbi->orb4.data_size;
1149230558Ssbruno		if (debug && orbi->page_table != NULL)
1150230558Ssbruno			printf("%s: malloc'd orbi->page_table(%p), orb4.data_size(%u)\n",
1151230558Ssbruno 				__func__, orbi->page_table, orbi->orb4.data_size);
1152230558Ssbruno
1153230558Ssbruno		xfer = fwmem_read_block(orbi->fwdev, (void *)orbi, /*spd*/FWSPD_S400,
1154230558Ssbruno					orbi->data_hi, orbi->data_lo, orbi->orb4.data_size*
1155230558Ssbruno					sizeof(struct unrestricted_page_table_fmt),
1156230558Ssbruno					(void *)orbi->page_table, sbp_targ_pt_done);
1157230558Ssbruno
1158230558Ssbruno		if (xfer != NULL)
1159230558Ssbruno			return;
1160230558Ssbruno	} else {
1161230558Ssbruno		/*
1162230558Ssbruno		 * This is a CTIO for a page table we have
1163230558Ssbruno		 * already malloc'd, so just directly invoke
1164230558Ssbruno		 * the xfer function on the orbi.
1165230558Ssbruno		 */
1166230558Ssbruno		sbp_targ_xfer_pt(orbi);
1167121186Ssimokawa		return;
1168230558Ssbruno	}
1169121186Ssimokawaerror:
1170121186Ssimokawa	orbi->ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
1171230558Ssbruno	if (debug)
1172230558Ssbruno		printf("%s: free orbi->page_table %p due to xfer == NULL\n", __func__, orbi->page_table);
1173230558Ssbruno	if (orbi->page_table != NULL) {
1174230558Ssbruno		free(orbi->page_table, M_SBP_TARG);
1175230558Ssbruno		orbi->page_table = NULL;
1176230558Ssbruno	}
1177121186Ssimokawa	xpt_done(orbi->ccb);
1178121186Ssimokawa	return;
1179121186Ssimokawa}
1180121186Ssimokawa
1181121186Ssimokawastatic void
1182121186Ssimokawasbp_targ_action1(struct cam_sim *sim, union ccb *ccb)
1183121186Ssimokawa{
1184121186Ssimokawa	struct sbp_targ_softc *sc;
1185121186Ssimokawa	struct sbp_targ_lstate *lstate;
1186121186Ssimokawa	cam_status status;
1187121186Ssimokawa	u_int ccb_dir;
1188121186Ssimokawa
1189121186Ssimokawa	sc =  (struct sbp_targ_softc *)cam_sim_softc(sim);
1190121186Ssimokawa
1191121186Ssimokawa	status = sbp_targ_find_devs(sc, ccb, &lstate, TRUE);
1192121186Ssimokawa
1193121186Ssimokawa	switch (ccb->ccb_h.func_code) {
1194121186Ssimokawa	case XPT_CONT_TARGET_IO:
1195121186Ssimokawa	{
1196121186Ssimokawa		struct orb_info *orbi;
1197121186Ssimokawa
1198121186Ssimokawa		if (debug)
1199170374Ssimokawa			printf("%s: XPT_CONT_TARGET_IO (0x%08x)\n",
1200170374Ssimokawa					 __func__, ccb->csio.tag_id);
1201121186Ssimokawa
1202121186Ssimokawa		if (status != CAM_REQ_CMP) {
1203121186Ssimokawa			ccb->ccb_h.status = status;
1204121186Ssimokawa			xpt_done(ccb);
1205121186Ssimokawa			break;
1206121186Ssimokawa		}
1207121186Ssimokawa		/* XXX transfer from/to initiator */
1208121186Ssimokawa		orbi = sbp_targ_get_orb_info(lstate,
1209121186Ssimokawa		    ccb->csio.tag_id, ccb->csio.init_id);
1210121186Ssimokawa		if (orbi == NULL) {
1211121186Ssimokawa			ccb->ccb_h.status = CAM_REQ_ABORTED; /* XXX */
1212121186Ssimokawa			xpt_done(ccb);
1213121186Ssimokawa			break;
1214121186Ssimokawa		}
1215121186Ssimokawa		if (orbi->state == ORBI_STATUS_ABORTED) {
1216121186Ssimokawa			if (debug)
1217127468Ssimokawa				printf("%s: ctio aborted\n", __func__);
1218170374Ssimokawa			sbp_targ_remove_orb_info_locked(orbi->login, orbi);
1219230558Ssbruno			if (debug)
1220230558Ssbruno				printf("%s: free orbi %p\n", __func__, orbi);
1221121186Ssimokawa			free(orbi, M_SBP_TARG);
1222170374Ssimokawa			ccb->ccb_h.status = CAM_REQ_ABORTED;
1223170374Ssimokawa			xpt_done(ccb);
1224121186Ssimokawa			break;
1225121186Ssimokawa		}
1226121186Ssimokawa		orbi->state = ORBI_STATUS_CTIO;
1227121186Ssimokawa
1228121186Ssimokawa		orbi->ccb = ccb;
1229121186Ssimokawa		ccb_dir = ccb->ccb_h.flags & CAM_DIR_MASK;
1230121186Ssimokawa
1231121186Ssimokawa		/* XXX */
1232121186Ssimokawa		if (ccb->csio.dxfer_len == 0)
1233121186Ssimokawa			ccb_dir = CAM_DIR_NONE;
1234121186Ssimokawa
1235121186Ssimokawa		/* Sanity check */
1236121186Ssimokawa		if (ccb_dir == CAM_DIR_IN && orbi->orb4.dir == 0)
1237127468Ssimokawa			printf("%s: direction mismatch\n", __func__);
1238121186Ssimokawa
1239121186Ssimokawa		/* check page table */
1240121186Ssimokawa		if (ccb_dir != CAM_DIR_NONE && orbi->orb4.page_table_present) {
1241121186Ssimokawa			if (debug)
1242121186Ssimokawa				printf("%s: page_table_present\n",
1243127468Ssimokawa				    __func__);
1244121186Ssimokawa			if (orbi->orb4.page_size != 0) {
1245121186Ssimokawa				printf("%s: unsupported pagesize %d != 0\n",
1246127468Ssimokawa			 	    __func__, orbi->orb4.page_size);
1247121186Ssimokawa				ccb->ccb_h.status = CAM_REQ_INVALID;
1248121186Ssimokawa				xpt_done(ccb);
1249121186Ssimokawa				break;
1250121186Ssimokawa			}
1251121186Ssimokawa			sbp_targ_fetch_pt(orbi);
1252121186Ssimokawa			break;
1253121186Ssimokawa		}
1254121186Ssimokawa
1255121186Ssimokawa		/* Sanity check */
1256230558Ssbruno		if (ccb_dir != CAM_DIR_NONE) {
1257121186Ssimokawa			sbp_targ_xfer_buf(orbi, 0, orbi->data_hi,
1258121186Ssimokawa			    orbi->data_lo,
1259121186Ssimokawa			    MIN(orbi->orb4.data_size, ccb->csio.dxfer_len),
1260121186Ssimokawa			    sbp_targ_cam_done);
1261230558Ssbruno			if ( orbi->orb4.data_size > ccb->csio.dxfer_len ) {
1262230558Ssbruno				orbi->data_lo += ccb->csio.dxfer_len;
1263230558Ssbruno				orbi->orb4.data_size -= ccb->csio.dxfer_len;
1264230558Ssbruno			}
1265230558Ssbruno		}
1266121186Ssimokawa
1267121186Ssimokawa		if (ccb_dir == CAM_DIR_NONE) {
1268170374Ssimokawa			if ((ccb->ccb_h.flags & CAM_SEND_STATUS) != 0) {
1269170374Ssimokawa				/* XXX */
1270170374Ssimokawa				SBP_UNLOCK(sc);
1271121186Ssimokawa				sbp_targ_send_status(orbi, ccb);
1272170374Ssimokawa				SBP_LOCK(sc);
1273170374Ssimokawa			}
1274121186Ssimokawa			ccb->ccb_h.status = CAM_REQ_CMP;
1275121186Ssimokawa			xpt_done(ccb);
1276121186Ssimokawa		}
1277121186Ssimokawa		break;
1278121186Ssimokawa	}
1279121186Ssimokawa	case XPT_ACCEPT_TARGET_IO:	/* Add Accept Target IO Resource */
1280121186Ssimokawa		if (status != CAM_REQ_CMP) {
1281121186Ssimokawa			ccb->ccb_h.status = status;
1282121186Ssimokawa			xpt_done(ccb);
1283121186Ssimokawa			break;
1284121186Ssimokawa		}
1285121186Ssimokawa		SLIST_INSERT_HEAD(&lstate->accept_tios, &ccb->ccb_h,
1286121186Ssimokawa		    sim_links.sle);
1287121186Ssimokawa		ccb->ccb_h.status = CAM_REQ_INPROG;
1288123430Ssimokawa		if ((lstate->flags & F_ATIO_STARVED) != 0) {
1289123430Ssimokawa			struct sbp_targ_login *login;
1290123430Ssimokawa
1291121186Ssimokawa			if (debug)
1292127468Ssimokawa				printf("%s: new atio arrived\n", __func__);
1293123430Ssimokawa			lstate->flags &= ~F_ATIO_STARVED;
1294123430Ssimokawa			STAILQ_FOREACH(login, &lstate->logins, link)
1295123430Ssimokawa				if ((login->flags & F_ATIO_STARVED) != 0) {
1296123430Ssimokawa					login->flags &= ~F_ATIO_STARVED;
1297123430Ssimokawa					sbp_targ_fetch_orb(lstate->sc,
1298123430Ssimokawa					    login->fwdev,
1299123430Ssimokawa					    login->last_hi, login->last_lo,
1300123430Ssimokawa					    login, FETCH_CMD);
1301123430Ssimokawa				}
1302121186Ssimokawa		}
1303121186Ssimokawa		break;
1304237601Sken	case XPT_NOTIFY_ACKNOWLEDGE:	/* recycle notify ack */
1305237601Sken	case XPT_IMMEDIATE_NOTIFY:	/* Add Immediate Notify Resource */
1306121186Ssimokawa		if (status != CAM_REQ_CMP) {
1307121186Ssimokawa			ccb->ccb_h.status = status;
1308121186Ssimokawa			xpt_done(ccb);
1309121186Ssimokawa			break;
1310121186Ssimokawa		}
1311121186Ssimokawa		SLIST_INSERT_HEAD(&lstate->immed_notifies, &ccb->ccb_h,
1312121186Ssimokawa		    sim_links.sle);
1313121186Ssimokawa		ccb->ccb_h.status = CAM_REQ_INPROG;
1314121186Ssimokawa		sbp_targ_send_lstate_events(sc, lstate);
1315121186Ssimokawa		break;
1316121186Ssimokawa	case XPT_EN_LUN:
1317121186Ssimokawa		sbp_targ_en_lun(sc, ccb);
1318121186Ssimokawa		xpt_done(ccb);
1319121186Ssimokawa		break;
1320121186Ssimokawa	case XPT_PATH_INQ:
1321121186Ssimokawa	{
1322121186Ssimokawa		struct ccb_pathinq *cpi = &ccb->cpi;
1323121186Ssimokawa
1324121186Ssimokawa		cpi->version_num = 1; /* XXX??? */
1325121186Ssimokawa		cpi->hba_inquiry = PI_TAG_ABLE;
1326121186Ssimokawa		cpi->target_sprt = PIT_PROCESSOR
1327121186Ssimokawa				 | PIT_DISCONNECT
1328121186Ssimokawa				 | PIT_TERM_IO;
1329230558Ssbruno		cpi->transport = XPORT_SPI; /* FIXME add XPORT_FW type to cam */
1330314725Smav		cpi->hba_misc = PIM_NOINITIATOR | PIM_NOBUSRESET |
1331314725Smav		    PIM_NO_6_BYTE;
1332121186Ssimokawa		cpi->hba_eng_cnt = 0;
1333121186Ssimokawa		cpi->max_target = 7; /* XXX */
1334121186Ssimokawa		cpi->max_lun = MAX_LUN - 1;
1335121186Ssimokawa		cpi->initiator_id = 7; /* XXX */
1336121186Ssimokawa		cpi->bus_id = sim->bus_id;
1337121186Ssimokawa		cpi->base_transfer_speed = 400 * 1000 / 8;
1338315813Smav		strlcpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
1339315813Smav		strlcpy(cpi->hba_vid, "SBP_TARG", HBA_IDLEN);
1340315813Smav		strlcpy(cpi->dev_name, sim->sim_name, DEV_IDLEN);
1341121186Ssimokawa		cpi->unit_number = sim->unit_number;
1342121186Ssimokawa
1343121186Ssimokawa		cpi->ccb_h.status = CAM_REQ_CMP;
1344121186Ssimokawa		xpt_done(ccb);
1345121186Ssimokawa		break;
1346121186Ssimokawa	}
1347121186Ssimokawa	case XPT_ABORT:
1348121186Ssimokawa	{
1349121186Ssimokawa		union ccb *accb = ccb->cab.abort_ccb;
1350121186Ssimokawa
1351121186Ssimokawa		switch (accb->ccb_h.func_code) {
1352121186Ssimokawa		case XPT_ACCEPT_TARGET_IO:
1353237601Sken		case XPT_IMMEDIATE_NOTIFY:
1354121186Ssimokawa			ccb->ccb_h.status = sbp_targ_abort_ccb(sc, ccb);
1355121186Ssimokawa			break;
1356121186Ssimokawa		case XPT_CONT_TARGET_IO:
1357121186Ssimokawa			/* XXX */
1358121186Ssimokawa			ccb->ccb_h.status = CAM_UA_ABORT;
1359121186Ssimokawa			break;
1360121186Ssimokawa		default:
1361121186Ssimokawa			printf("%s: aborting unknown function %d\n",
1362127468Ssimokawa				__func__, accb->ccb_h.func_code);
1363121186Ssimokawa			ccb->ccb_h.status = CAM_REQ_INVALID;
1364121186Ssimokawa			break;
1365121186Ssimokawa		}
1366121186Ssimokawa		xpt_done(ccb);
1367121186Ssimokawa		break;
1368121186Ssimokawa	}
1369230558Ssbruno#ifdef CAM_NEW_TRAN_CODE
1370230558Ssbruno	case XPT_SET_TRAN_SETTINGS:
1371230558Ssbruno		ccb->ccb_h.status = CAM_REQ_INVALID;
1372230558Ssbruno		xpt_done(ccb);
1373230558Ssbruno		break;
1374230558Ssbruno	case XPT_GET_TRAN_SETTINGS:
1375230558Ssbruno	{
1376230558Ssbruno		struct ccb_trans_settings *cts = &ccb->cts;
1377230558Ssbruno		struct ccb_trans_settings_scsi *scsi =
1378230558Ssbruno			&cts->proto_specific.scsi;
1379230558Ssbruno		struct ccb_trans_settings_spi *spi =
1380230558Ssbruno			&cts->xport_specific.spi;
1381230558Ssbruno
1382230558Ssbruno		cts->protocol = PROTO_SCSI;
1383230558Ssbruno		cts->protocol_version = SCSI_REV_2;
1384230558Ssbruno		cts->transport = XPORT_FW;     /* should have a FireWire */
1385230558Ssbruno		cts->transport_version = 2;
1386230558Ssbruno		spi->valid = CTS_SPI_VALID_DISC;
1387230558Ssbruno		spi->flags = CTS_SPI_FLAGS_DISC_ENB;
1388230558Ssbruno		scsi->valid = CTS_SCSI_VALID_TQ;
1389230558Ssbruno		scsi->flags = CTS_SCSI_FLAGS_TAG_ENB;
1390230558Ssbruno#if 0
1391230558Ssbruno		printf("%s:%d:%d XPT_GET_TRAN_SETTINGS:\n",
1392230558Ssbruno			device_get_nameunit(sc->fd.dev),
1393230558Ssbruno			ccb->ccb_h.target_id, ccb->ccb_h.target_lun);
1394230558Ssbruno#endif
1395230558Ssbruno		cts->ccb_h.status = CAM_REQ_CMP;
1396230558Ssbruno		xpt_done(ccb);
1397230558Ssbruno		break;
1398230558Ssbruno	}
1399230558Ssbruno#endif
1400230558Ssbruno
1401121186Ssimokawa	default:
1402230558Ssbruno		printf("%s: unknown function 0x%x\n",
1403127468Ssimokawa		    __func__, ccb->ccb_h.func_code);
1404230558Ssbruno		ccb->ccb_h.status = CAM_PROVIDE_FAIL;
1405121186Ssimokawa		xpt_done(ccb);
1406121186Ssimokawa		break;
1407121186Ssimokawa	}
1408121186Ssimokawa	return;
1409121186Ssimokawa}
1410121186Ssimokawa
1411121186Ssimokawastatic void
1412121186Ssimokawasbp_targ_action(struct cam_sim *sim, union ccb *ccb)
1413121186Ssimokawa{
1414121186Ssimokawa	int s;
1415121186Ssimokawa
1416121186Ssimokawa	s = splfw();
1417121186Ssimokawa	sbp_targ_action1(sim, ccb);
1418121186Ssimokawa	splx(s);
1419121186Ssimokawa}
1420121186Ssimokawa
1421121186Ssimokawastatic void
1422121186Ssimokawasbp_targ_poll(struct cam_sim *sim)
1423121186Ssimokawa{
1424121186Ssimokawa	/* XXX */
1425121186Ssimokawa	return;
1426121186Ssimokawa}
1427121186Ssimokawa
1428121186Ssimokawastatic void
1429121186Ssimokawasbp_targ_cmd_handler(struct fw_xfer *xfer)
1430121186Ssimokawa{
1431121186Ssimokawa	struct fw_pkt *fp;
1432129585Sdfr	uint32_t *orb;
1433121186Ssimokawa	struct corb4 *orb4;
1434121186Ssimokawa	struct orb_info *orbi;
1435121186Ssimokawa	struct ccb_accept_tio *atio;
1436121186Ssimokawa	u_char *bytes;
1437121186Ssimokawa	int i;
1438121186Ssimokawa
1439121186Ssimokawa	orbi = (struct orb_info *)xfer->sc;
1440121186Ssimokawa	if (xfer->resp != 0) {
1441127468Ssimokawa		printf("%s: xfer->resp = %d\n", __func__, xfer->resp);
1442121186Ssimokawa		orbi->status.resp = SBP_TRANS_FAIL;
1443124877Ssimokawa		orbi->status.status = OBJ_ORB | SBE_TIMEOUT/*XXX*/;
1444121186Ssimokawa		orbi->status.dead = 1;
1445121186Ssimokawa		orbi->status.len = 1;
1446170374Ssimokawa		sbp_targ_abort(orbi->sc, STAILQ_NEXT(orbi, link));
1447121186Ssimokawa
1448121186Ssimokawa		sbp_targ_status_FIFO(orbi,
1449123430Ssimokawa		    orbi->login->fifo_hi, orbi->login->fifo_lo, /*dequeue*/1);
1450121186Ssimokawa		fw_xfer_free(xfer);
1451121186Ssimokawa		return;
1452121186Ssimokawa	}
1453121186Ssimokawa	fp = &xfer->recv.hdr;
1454121186Ssimokawa
1455170374Ssimokawa	atio = orbi->atio;
1456170374Ssimokawa
1457121186Ssimokawa	if (orbi->state == ORBI_STATUS_ABORTED) {
1458127468Ssimokawa		printf("%s: aborted\n", __func__);
1459123430Ssimokawa		sbp_targ_remove_orb_info(orbi->login, orbi);
1460121186Ssimokawa		free(orbi, M_SBP_TARG);
1461170374Ssimokawa		atio->ccb_h.status = CAM_REQ_ABORTED;
1462170374Ssimokawa		SBP_LOCK(orbi->sc);
1463170374Ssimokawa		xpt_done((union ccb*)atio);
1464170374Ssimokawa		SBP_UNLOCK(orbi->sc);
1465121186Ssimokawa		goto done0;
1466121186Ssimokawa	}
1467121186Ssimokawa	orbi->state = ORBI_STATUS_ATIO;
1468121186Ssimokawa
1469121186Ssimokawa	orb = orbi->orb;
1470121186Ssimokawa	/* swap payload except SCSI command */
1471121186Ssimokawa	for (i = 0; i < 5; i ++)
1472121186Ssimokawa		orb[i] = ntohl(orb[i]);
1473121186Ssimokawa
1474121186Ssimokawa	orb4 = (struct corb4 *)&orb[4];
1475121186Ssimokawa	if (orb4->rq_fmt != 0) {
1476121186Ssimokawa		/* XXX */
1477127468Ssimokawa		printf("%s: rq_fmt(%d) != 0\n", __func__, orb4->rq_fmt);
1478121186Ssimokawa	}
1479121186Ssimokawa
1480121186Ssimokawa	atio->ccb_h.target_id = 0; /* XXX */
1481123430Ssimokawa	atio->ccb_h.target_lun = orbi->login->lstate->lun;
1482121186Ssimokawa	atio->sense_len = 0;
1483230558Ssbruno	atio->tag_action = MSG_SIMPLE_TASK;
1484121186Ssimokawa	atio->tag_id = orbi->orb_lo;
1485123430Ssimokawa	atio->init_id = orbi->login->id;
1486123430Ssimokawa
1487260342Smav	atio->ccb_h.flags |= CAM_TAG_ACTION_VALID;
1488170374Ssimokawa	bytes = (u_char *)&orb[5];
1489121186Ssimokawa	if (debug)
1490170374Ssimokawa		printf("%s: %p %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
1491170374Ssimokawa		    __func__, (void *)atio,
1492121186Ssimokawa		    bytes[0], bytes[1], bytes[2], bytes[3], bytes[4],
1493121186Ssimokawa		    bytes[5], bytes[6], bytes[7], bytes[8], bytes[9]);
1494121186Ssimokawa	switch (bytes[0] >> 5) {
1495121186Ssimokawa	case 0:
1496121186Ssimokawa		atio->cdb_len = 6;
1497121186Ssimokawa		break;
1498121186Ssimokawa	case 1:
1499121186Ssimokawa	case 2:
1500121186Ssimokawa		atio->cdb_len = 10;
1501121186Ssimokawa		break;
1502121186Ssimokawa	case 4:
1503121186Ssimokawa		atio->cdb_len = 16;
1504121186Ssimokawa		break;
1505121186Ssimokawa	case 5:
1506121186Ssimokawa		atio->cdb_len = 12;
1507121186Ssimokawa		break;
1508121186Ssimokawa	case 3:
1509121186Ssimokawa	default:
1510121186Ssimokawa		/* Only copy the opcode. */
1511121186Ssimokawa		atio->cdb_len = 1;
1512121186Ssimokawa		printf("Reserved or VU command code type encountered\n");
1513121186Ssimokawa		break;
1514121186Ssimokawa	}
1515121186Ssimokawa
1516121186Ssimokawa	memcpy(atio->cdb_io.cdb_bytes, bytes, atio->cdb_len);
1517121186Ssimokawa
1518121186Ssimokawa	atio->ccb_h.status |= CAM_CDB_RECVD;
1519121186Ssimokawa
1520121186Ssimokawa	/* next ORB */
1521121186Ssimokawa	if ((orb[0] & (1<<31)) == 0) {
1522121186Ssimokawa		if (debug)
1523127468Ssimokawa			printf("%s: fetch next orb\n", __func__);
1524121186Ssimokawa		orbi->status.src = SRC_NEXT_EXISTS;
1525121186Ssimokawa		sbp_targ_fetch_orb(orbi->sc, orbi->fwdev,
1526123430Ssimokawa		    orb[0], orb[1], orbi->login, FETCH_CMD);
1527121186Ssimokawa	} else {
1528121186Ssimokawa		orbi->status.src = SRC_NO_NEXT;
1529123430Ssimokawa		orbi->login->flags &= ~F_LINK_ACTIVE;
1530121186Ssimokawa	}
1531121186Ssimokawa
1532121186Ssimokawa	orbi->data_hi = orb[2];
1533121186Ssimokawa	orbi->data_lo = orb[3];
1534121186Ssimokawa	orbi->orb4 = *orb4;
1535121186Ssimokawa
1536170374Ssimokawa	SBP_LOCK(orbi->sc);
1537121186Ssimokawa	xpt_done((union ccb*)atio);
1538170374Ssimokawa	SBP_UNLOCK(orbi->sc);
1539121186Ssimokawadone0:
1540121186Ssimokawa	fw_xfer_free(xfer);
1541121186Ssimokawa	return;
1542121186Ssimokawa}
1543121186Ssimokawa
1544123430Ssimokawastatic struct sbp_targ_login *
1545123430Ssimokawasbp_targ_get_login(struct sbp_targ_softc *sc, struct fw_device *fwdev, int lun)
1546123430Ssimokawa{
1547123430Ssimokawa	struct sbp_targ_lstate *lstate;
1548123430Ssimokawa	struct sbp_targ_login *login;
1549123430Ssimokawa	int i;
1550123430Ssimokawa
1551123430Ssimokawa	lstate = sc->lstate[lun];
1552123430Ssimokawa
1553123430Ssimokawa	STAILQ_FOREACH(login, &lstate->logins, link)
1554123430Ssimokawa		if (login->fwdev == fwdev)
1555123430Ssimokawa			return (login);
1556123430Ssimokawa
1557123430Ssimokawa	for (i = 0; i < MAX_LOGINS; i ++)
1558123430Ssimokawa		if (sc->logins[i] == NULL)
1559123430Ssimokawa			goto found;
1560123430Ssimokawa
1561127468Ssimokawa	printf("%s: increase MAX_LOGIN\n", __func__);
1562123430Ssimokawa	return (NULL);
1563123430Ssimokawa
1564123430Ssimokawafound:
1565123430Ssimokawa	login = (struct sbp_targ_login *)malloc(
1566123430Ssimokawa	    sizeof(struct sbp_targ_login), M_SBP_TARG, M_NOWAIT | M_ZERO);
1567123430Ssimokawa
1568123430Ssimokawa	if (login == NULL) {
1569127468Ssimokawa		printf("%s: malloc failed\n", __func__);
1570123430Ssimokawa		return (NULL);
1571123430Ssimokawa	}
1572123430Ssimokawa
1573169475Ssimokawa	login->id = i;
1574123430Ssimokawa	login->fwdev = fwdev;
1575123430Ssimokawa	login->lstate = lstate;
1576123430Ssimokawa	login->last_hi = 0xffff;
1577123430Ssimokawa	login->last_lo = 0xffffffff;
1578123430Ssimokawa	login->hold_sec = 1;
1579123430Ssimokawa	STAILQ_INIT(&login->orbs);
1580123430Ssimokawa	CALLOUT_INIT(&login->hold_callout);
1581123430Ssimokawa	sc->logins[i] = login;
1582123430Ssimokawa	return (login);
1583123430Ssimokawa}
1584123430Ssimokawa
1585121186Ssimokawastatic void
1586121186Ssimokawasbp_targ_mgm_handler(struct fw_xfer *xfer)
1587121186Ssimokawa{
1588121186Ssimokawa	struct sbp_targ_lstate *lstate;
1589123430Ssimokawa	struct sbp_targ_login *login;
1590121186Ssimokawa	struct fw_pkt *fp;
1591129585Sdfr	uint32_t *orb;
1592121186Ssimokawa	struct morb4 *orb4;
1593121186Ssimokawa	struct orb_info *orbi;
1594121186Ssimokawa	int i;
1595121186Ssimokawa
1596121186Ssimokawa	orbi = (struct orb_info *)xfer->sc;
1597121186Ssimokawa	if (xfer->resp != 0) {
1598127468Ssimokawa		printf("%s: xfer->resp = %d\n", __func__, xfer->resp);
1599121186Ssimokawa		orbi->status.resp = SBP_TRANS_FAIL;
1600124877Ssimokawa		orbi->status.status = OBJ_ORB | SBE_TIMEOUT/*XXX*/;
1601121186Ssimokawa		orbi->status.dead = 1;
1602121186Ssimokawa		orbi->status.len = 1;
1603170374Ssimokawa		sbp_targ_abort(orbi->sc, STAILQ_NEXT(orbi, link));
1604121186Ssimokawa
1605121186Ssimokawa		sbp_targ_status_FIFO(orbi,
1606123430Ssimokawa		    orbi->login->fifo_hi, orbi->login->fifo_lo, /*dequeue*/0);
1607121186Ssimokawa		fw_xfer_free(xfer);
1608121186Ssimokawa		return;
1609121186Ssimokawa	}
1610121186Ssimokawa	fp = &xfer->recv.hdr;
1611121186Ssimokawa
1612121186Ssimokawa	orb = orbi->orb;
1613121186Ssimokawa	/* swap payload */
1614121186Ssimokawa	for (i = 0; i < 8; i ++) {
1615121186Ssimokawa		orb[i] = ntohl(orb[i]);
1616121186Ssimokawa	}
1617121186Ssimokawa	orb4 = (struct morb4 *)&orb[4];
1618121186Ssimokawa	if (debug)
1619127468Ssimokawa		printf("%s: %s\n", __func__, orb_fun_name[orb4->fun]);
1620121186Ssimokawa
1621121186Ssimokawa	orbi->status.src = SRC_NO_NEXT;
1622121186Ssimokawa
1623121186Ssimokawa	switch (orb4->fun << 16) {
1624121186Ssimokawa	case ORB_FUN_LGI:
1625121186Ssimokawa	{
1626123430Ssimokawa		int exclusive = 0, lun;
1627121186Ssimokawa
1628123430Ssimokawa		if (orb[4] & ORB_EXV)
1629123430Ssimokawa			exclusive = 1;
1630123430Ssimokawa
1631123430Ssimokawa		lun = orb4->id;
1632123430Ssimokawa		lstate = orbi->sc->lstate[lun];
1633123430Ssimokawa
1634123430Ssimokawa		if (lun >= MAX_LUN || lstate == NULL ||
1635123430Ssimokawa		    (exclusive &&
1636123430Ssimokawa		    STAILQ_FIRST(&lstate->logins) != NULL &&
1637123430Ssimokawa		    STAILQ_FIRST(&lstate->logins)->fwdev != orbi->fwdev)
1638123430Ssimokawa		    ) {
1639121186Ssimokawa			/* error */
1640121186Ssimokawa			orbi->status.dead = 1;
1641121186Ssimokawa			orbi->status.status = STATUS_ACCESS_DENY;
1642121186Ssimokawa			orbi->status.len = 1;
1643121186Ssimokawa			break;
1644121186Ssimokawa		}
1645123430Ssimokawa
1646123430Ssimokawa		/* allocate login */
1647123430Ssimokawa		login = sbp_targ_get_login(orbi->sc, orbi->fwdev, lun);
1648123430Ssimokawa		if (login == NULL) {
1649123430Ssimokawa			printf("%s: sbp_targ_get_login failed\n",
1650127468Ssimokawa			    __func__);
1651123430Ssimokawa			orbi->status.dead = 1;
1652123430Ssimokawa			orbi->status.status = STATUS_RES_UNAVAIL;
1653123430Ssimokawa			orbi->status.len = 1;
1654123430Ssimokawa			break;
1655123430Ssimokawa		}
1656170374Ssimokawa		printf("%s: login id=%d\n", __func__, login->id);
1657123430Ssimokawa
1658123430Ssimokawa		login->fifo_hi = orb[6];
1659123430Ssimokawa		login->fifo_lo = orb[7];
1660129585Sdfr		login->loginres.len = htons(sizeof(uint32_t) * 4);
1661123430Ssimokawa		login->loginres.id = htons(login->id);
1662123430Ssimokawa		login->loginres.cmd_hi = htons(SBP_TARG_BIND_HI);
1663123430Ssimokawa		login->loginres.cmd_lo = htonl(SBP_TARG_BIND_LO(login->id));
1664123430Ssimokawa		login->loginres.recon_hold = htons(login->hold_sec);
1665123430Ssimokawa
1666170374Ssimokawa		STAILQ_INSERT_TAIL(&lstate->logins, login, link);
1667230558Ssbruno		fwmem_write_block(orbi->fwdev, NULL, /*spd*/FWSPD_S400, orb[2], orb[3],
1668123430Ssimokawa		    sizeof(struct sbp_login_res), (void *)&login->loginres,
1669121186Ssimokawa		    fw_asy_callback_free);
1670123514Ssimokawa		/* XXX return status after loginres is successfully written */
1671121186Ssimokawa		break;
1672121186Ssimokawa	}
1673121186Ssimokawa	case ORB_FUN_RCN:
1674123430Ssimokawa		login = orbi->sc->logins[orb4->id];
1675123430Ssimokawa		if (login != NULL && login->fwdev == orbi->fwdev) {
1676123430Ssimokawa			login->flags &= ~F_HOLD;
1677123430Ssimokawa			callout_stop(&login->hold_callout);
1678123430Ssimokawa			printf("%s: reconnected id=%d\n",
1679127468Ssimokawa			    __func__, login->id);
1680123430Ssimokawa		} else {
1681123430Ssimokawa			orbi->status.dead = 1;
1682123430Ssimokawa			orbi->status.status = STATUS_ACCESS_DENY;
1683123430Ssimokawa			printf("%s: reconnection faild id=%d\n",
1684127468Ssimokawa			    __func__, orb4->id);
1685123430Ssimokawa		}
1686121186Ssimokawa		break;
1687123430Ssimokawa	case ORB_FUN_LGO:
1688123430Ssimokawa		login = orbi->sc->logins[orb4->id];
1689123430Ssimokawa		if (login->fwdev != orbi->fwdev) {
1690127468Ssimokawa			printf("%s: wrong initiator\n", __func__);
1691123430Ssimokawa			break;
1692123430Ssimokawa		}
1693123430Ssimokawa		sbp_targ_dealloc_login(login);
1694123430Ssimokawa		break;
1695121186Ssimokawa	default:
1696121186Ssimokawa		printf("%s: %s not implemented yet\n",
1697127468Ssimokawa		    __func__, orb_fun_name[orb4->fun]);
1698121186Ssimokawa		break;
1699121186Ssimokawa	}
1700121186Ssimokawa	orbi->status.len = 1;
1701121186Ssimokawa	sbp_targ_status_FIFO(orbi, orb[6], orb[7], /*dequeue*/0);
1702121186Ssimokawa	fw_xfer_free(xfer);
1703121186Ssimokawa	return;
1704121186Ssimokawa}
1705121186Ssimokawa
1706121186Ssimokawastatic void
1707121186Ssimokawasbp_targ_pointer_handler(struct fw_xfer *xfer)
1708121186Ssimokawa{
1709121186Ssimokawa	struct orb_info *orbi;
1710129585Sdfr	uint32_t orb0, orb1;
1711121186Ssimokawa
1712121186Ssimokawa	orbi = (struct orb_info *)xfer->sc;
1713121186Ssimokawa	if (xfer->resp != 0) {
1714127468Ssimokawa		printf("%s: xfer->resp = %d\n", __func__, xfer->resp);
1715121186Ssimokawa		goto done;
1716121186Ssimokawa	}
1717121186Ssimokawa
1718121186Ssimokawa	orb0 = ntohl(orbi->orb[0]);
1719121186Ssimokawa	orb1 = ntohl(orbi->orb[1]);
1720261455Seadler	if ((orb0 & (1U << 31)) != 0) {
1721127468Ssimokawa		printf("%s: invalid pointer\n", __func__);
1722121186Ssimokawa		goto done;
1723121186Ssimokawa	}
1724123430Ssimokawa	sbp_targ_fetch_orb(orbi->login->lstate->sc, orbi->fwdev,
1725129585Sdfr	    (uint16_t)orb0, orb1, orbi->login, FETCH_CMD);
1726121186Ssimokawadone:
1727121186Ssimokawa	free(orbi, M_SBP_TARG);
1728121186Ssimokawa	fw_xfer_free(xfer);
1729121186Ssimokawa	return;
1730121186Ssimokawa}
1731121186Ssimokawa
1732121186Ssimokawastatic void
1733121186Ssimokawasbp_targ_fetch_orb(struct sbp_targ_softc *sc, struct fw_device *fwdev,
1734129585Sdfr    uint16_t orb_hi, uint32_t orb_lo, struct sbp_targ_login *login,
1735121186Ssimokawa    int mode)
1736121186Ssimokawa{
1737121186Ssimokawa	struct orb_info *orbi;
1738121186Ssimokawa
1739121186Ssimokawa	if (debug)
1740127468Ssimokawa		printf("%s: fetch orb %04x:%08x\n", __func__, orb_hi, orb_lo);
1741121186Ssimokawa	orbi = malloc(sizeof(struct orb_info), M_SBP_TARG, M_NOWAIT | M_ZERO);
1742121186Ssimokawa	if (orbi == NULL) {
1743127468Ssimokawa		printf("%s: malloc failed\n", __func__);
1744121186Ssimokawa		return;
1745121186Ssimokawa	}
1746121186Ssimokawa	orbi->sc = sc;
1747121186Ssimokawa	orbi->fwdev = fwdev;
1748123430Ssimokawa	orbi->login = login;
1749121186Ssimokawa	orbi->orb_hi = orb_hi;
1750121186Ssimokawa	orbi->orb_lo = orb_lo;
1751121186Ssimokawa	orbi->status.orb_hi = htons(orb_hi);
1752121186Ssimokawa	orbi->status.orb_lo = htonl(orb_lo);
1753230558Ssbruno	orbi->page_table = NULL;
1754121186Ssimokawa
1755121186Ssimokawa	switch (mode) {
1756121186Ssimokawa	case FETCH_MGM:
1757230558Ssbruno		fwmem_read_block(fwdev, (void *)orbi, /*spd*/FWSPD_S400, orb_hi, orb_lo,
1758129585Sdfr		    sizeof(uint32_t) * 8, &orbi->orb[0],
1759121186Ssimokawa		    sbp_targ_mgm_handler);
1760121186Ssimokawa		break;
1761121186Ssimokawa	case FETCH_CMD:
1762121186Ssimokawa		orbi->state = ORBI_STATUS_FETCH;
1763123430Ssimokawa		login->last_hi = orb_hi;
1764123430Ssimokawa		login->last_lo = orb_lo;
1765123430Ssimokawa		login->flags |= F_LINK_ACTIVE;
1766121186Ssimokawa		/* dequeue */
1767170374Ssimokawa		SBP_LOCK(sc);
1768121186Ssimokawa		orbi->atio = (struct ccb_accept_tio *)
1769123430Ssimokawa		    SLIST_FIRST(&login->lstate->accept_tios);
1770121186Ssimokawa		if (orbi->atio == NULL) {
1771170374Ssimokawa			SBP_UNLOCK(sc);
1772127468Ssimokawa			printf("%s: no free atio\n", __func__);
1773123430Ssimokawa			login->lstate->flags |= F_ATIO_STARVED;
1774123430Ssimokawa			login->flags |= F_ATIO_STARVED;
1775123430Ssimokawa#if 0
1776123430Ssimokawa			/* XXX ?? */
1777123430Ssimokawa			login->fwdev = fwdev;
1778123430Ssimokawa#endif
1779121186Ssimokawa			break;
1780121186Ssimokawa		}
1781123430Ssimokawa		SLIST_REMOVE_HEAD(&login->lstate->accept_tios, sim_links.sle);
1782170374Ssimokawa		STAILQ_INSERT_TAIL(&login->orbs, orbi, link);
1783170374Ssimokawa		SBP_UNLOCK(sc);
1784230558Ssbruno		fwmem_read_block(fwdev, (void *)orbi, /*spd*/FWSPD_S400, orb_hi, orb_lo,
1785129585Sdfr		    sizeof(uint32_t) * 8, &orbi->orb[0],
1786121186Ssimokawa		    sbp_targ_cmd_handler);
1787121186Ssimokawa		break;
1788121186Ssimokawa	case FETCH_POINTER:
1789121186Ssimokawa		orbi->state = ORBI_STATUS_POINTER;
1790123430Ssimokawa		login->flags |= F_LINK_ACTIVE;
1791230558Ssbruno		fwmem_read_block(fwdev, (void *)orbi, /*spd*/FWSPD_S400, orb_hi, orb_lo,
1792129585Sdfr		    sizeof(uint32_t) * 2, &orbi->orb[0],
1793121186Ssimokawa		    sbp_targ_pointer_handler);
1794121186Ssimokawa		break;
1795121186Ssimokawa	default:
1796127468Ssimokawa		printf("%s: invalid mode %d\n", __func__, mode);
1797121186Ssimokawa	}
1798121186Ssimokawa}
1799121186Ssimokawa
1800121186Ssimokawastatic void
1801121186Ssimokawasbp_targ_resp_callback(struct fw_xfer *xfer)
1802121186Ssimokawa{
1803121186Ssimokawa	struct sbp_targ_softc *sc;
1804121186Ssimokawa	int s;
1805121186Ssimokawa
1806121186Ssimokawa	if (debug)
1807127468Ssimokawa		printf("%s: xfer=%p\n", __func__, xfer);
1808121186Ssimokawa	sc = (struct sbp_targ_softc *)xfer->sc;
1809121186Ssimokawa	fw_xfer_unload(xfer);
1810121186Ssimokawa	xfer->recv.pay_len = SBP_TARG_RECV_LEN;
1811167632Ssimokawa	xfer->hand = sbp_targ_recv;
1812121186Ssimokawa	s = splfw();
1813121186Ssimokawa	STAILQ_INSERT_TAIL(&sc->fwb.xferlist, xfer, link);
1814121186Ssimokawa	splx(s);
1815121186Ssimokawa}
1816121186Ssimokawa
1817121186Ssimokawastatic int
1818123430Ssimokawasbp_targ_cmd(struct fw_xfer *xfer, struct fw_device *fwdev, int login_id,
1819123430Ssimokawa    int reg)
1820121186Ssimokawa{
1821123430Ssimokawa	struct sbp_targ_login *login;
1822121186Ssimokawa	struct sbp_targ_softc *sc;
1823121186Ssimokawa	int rtcode = 0;
1824121186Ssimokawa
1825123430Ssimokawa	if (login_id < 0 || login_id >= MAX_LOGINS)
1826121186Ssimokawa		return(RESP_ADDRESS_ERROR);
1827121186Ssimokawa
1828121186Ssimokawa	sc = (struct sbp_targ_softc *)xfer->sc;
1829123430Ssimokawa	login = sc->logins[login_id];
1830123430Ssimokawa	if (login == NULL)
1831121186Ssimokawa		return(RESP_ADDRESS_ERROR);
1832121186Ssimokawa
1833123430Ssimokawa	if (login->fwdev != fwdev) {
1834123430Ssimokawa		/* XXX */
1835123430Ssimokawa		return(RESP_ADDRESS_ERROR);
1836123430Ssimokawa	}
1837123430Ssimokawa
1838121186Ssimokawa	switch (reg) {
1839121186Ssimokawa	case 0x08:	/* ORB_POINTER */
1840121186Ssimokawa		if (debug)
1841170374Ssimokawa			printf("%s: ORB_POINTER(%d)\n", __func__, login_id);
1842123430Ssimokawa		if ((login->flags & F_LINK_ACTIVE) != 0) {
1843123430Ssimokawa			if (debug)
1844123430Ssimokawa				printf("link active (ORB_POINTER)\n");
1845123430Ssimokawa			break;
1846123430Ssimokawa		}
1847123430Ssimokawa		sbp_targ_fetch_orb(sc, fwdev,
1848121186Ssimokawa		    ntohl(xfer->recv.payload[0]),
1849121186Ssimokawa		    ntohl(xfer->recv.payload[1]),
1850123430Ssimokawa		    login, FETCH_CMD);
1851121186Ssimokawa		break;
1852121186Ssimokawa	case 0x04:	/* AGENT_RESET */
1853121186Ssimokawa		if (debug)
1854170374Ssimokawa			printf("%s: AGENT RESET(%d)\n", __func__, login_id);
1855123430Ssimokawa		login->last_hi = 0xffff;
1856123430Ssimokawa		login->last_lo = 0xffffffff;
1857170374Ssimokawa		sbp_targ_abort(sc, STAILQ_FIRST(&login->orbs));
1858121186Ssimokawa		break;
1859121186Ssimokawa	case 0x10:	/* DOORBELL */
1860121186Ssimokawa		if (debug)
1861170374Ssimokawa			printf("%s: DOORBELL(%d)\n", __func__, login_id);
1862123430Ssimokawa		if (login->last_hi == 0xffff &&
1863123430Ssimokawa		    login->last_lo == 0xffffffff) {
1864121186Ssimokawa			printf("%s: no previous pointer(DOORBELL)\n",
1865127468Ssimokawa			    __func__);
1866121186Ssimokawa			break;
1867121186Ssimokawa		}
1868123430Ssimokawa		if ((login->flags & F_LINK_ACTIVE) != 0) {
1869121186Ssimokawa			if (debug)
1870121186Ssimokawa				printf("link active (DOORBELL)\n");
1871121186Ssimokawa			break;
1872121186Ssimokawa		}
1873123430Ssimokawa		sbp_targ_fetch_orb(sc, fwdev,
1874123430Ssimokawa		    login->last_hi, login->last_lo,
1875123430Ssimokawa		    login, FETCH_POINTER);
1876121186Ssimokawa		break;
1877121186Ssimokawa	case 0x00:	/* AGENT_STATE */
1878170374Ssimokawa		printf("%s: AGENT_STATE (%d:ignore)\n", __func__, login_id);
1879121186Ssimokawa		break;
1880121186Ssimokawa	case 0x14:	/* UNSOLICITED_STATE_ENABLE */
1881170374Ssimokawa		printf("%s: UNSOLICITED_STATE_ENABLE (%d:ignore)\n",
1882170374Ssimokawa							 __func__, login_id);
1883121186Ssimokawa		break;
1884121186Ssimokawa	default:
1885170374Ssimokawa		printf("%s: invalid register %d(%d)\n",
1886170374Ssimokawa						 __func__, reg, login_id);
1887121186Ssimokawa		rtcode = RESP_ADDRESS_ERROR;
1888121186Ssimokawa	}
1889121186Ssimokawa
1890121186Ssimokawa	return (rtcode);
1891121186Ssimokawa}
1892121186Ssimokawa
1893121186Ssimokawastatic int
1894121186Ssimokawasbp_targ_mgm(struct fw_xfer *xfer, struct fw_device *fwdev)
1895121186Ssimokawa{
1896121186Ssimokawa	struct sbp_targ_softc *sc;
1897121186Ssimokawa	struct fw_pkt *fp;
1898121186Ssimokawa
1899121186Ssimokawa	sc = (struct sbp_targ_softc *)xfer->sc;
1900121186Ssimokawa
1901121186Ssimokawa	fp = &xfer->recv.hdr;
1902121186Ssimokawa	if (fp->mode.wreqb.tcode != FWTCODE_WREQB){
1903127468Ssimokawa		printf("%s: tcode = %d\n", __func__, fp->mode.wreqb.tcode);
1904121186Ssimokawa		return(RESP_TYPE_ERROR);
1905121186Ssimokawa        }
1906121186Ssimokawa
1907121186Ssimokawa	sbp_targ_fetch_orb(sc, fwdev,
1908121186Ssimokawa	    ntohl(xfer->recv.payload[0]),
1909121186Ssimokawa	    ntohl(xfer->recv.payload[1]),
1910121186Ssimokawa	    NULL, FETCH_MGM);
1911121186Ssimokawa
1912121186Ssimokawa	return(0);
1913121186Ssimokawa}
1914121186Ssimokawa
1915121186Ssimokawastatic void
1916121186Ssimokawasbp_targ_recv(struct fw_xfer *xfer)
1917121186Ssimokawa{
1918121186Ssimokawa	struct fw_pkt *fp, *sfp;
1919121186Ssimokawa	struct fw_device *fwdev;
1920129585Sdfr	uint32_t lo;
1921121186Ssimokawa	int s, rtcode;
1922121186Ssimokawa	struct sbp_targ_softc *sc;
1923121186Ssimokawa
1924121186Ssimokawa	s = splfw();
1925121186Ssimokawa	sc = (struct sbp_targ_softc *)xfer->sc;
1926121186Ssimokawa	fp = &xfer->recv.hdr;
1927121186Ssimokawa	fwdev = fw_noderesolve_nodeid(sc->fd.fc, fp->mode.wreqb.src & 0x3f);
1928121186Ssimokawa	if (fwdev == NULL) {
1929121186Ssimokawa		printf("%s: cannot resolve nodeid=%d\n",
1930127468Ssimokawa		    __func__, fp->mode.wreqb.src & 0x3f);
1931121186Ssimokawa		rtcode = RESP_TYPE_ERROR; /* XXX */
1932121186Ssimokawa		goto done;
1933121186Ssimokawa	}
1934121186Ssimokawa	lo = fp->mode.wreqb.dest_lo;
1935170374Ssimokawa
1936121186Ssimokawa	if (lo == SBP_TARG_BIND_LO(-1))
1937121186Ssimokawa		rtcode = sbp_targ_mgm(xfer, fwdev);
1938121186Ssimokawa	else if (lo >= SBP_TARG_BIND_LO(0))
1939123430Ssimokawa		rtcode = sbp_targ_cmd(xfer, fwdev, SBP_TARG_LOGIN_ID(lo),
1940123430Ssimokawa		    lo % 0x20);
1941121186Ssimokawa	else
1942121186Ssimokawa		rtcode = RESP_ADDRESS_ERROR;
1943121186Ssimokawa
1944121186Ssimokawadone:
1945121186Ssimokawa	if (rtcode != 0)
1946127468Ssimokawa		printf("%s: rtcode = %d\n", __func__, rtcode);
1947121186Ssimokawa	sfp = &xfer->send.hdr;
1948230558Ssbruno	xfer->send.spd = FWSPD_S400;
1949167632Ssimokawa	xfer->hand = sbp_targ_resp_callback;
1950121186Ssimokawa	sfp->mode.wres.dst = fp->mode.wreqb.src;
1951121186Ssimokawa	sfp->mode.wres.tlrt = fp->mode.wreqb.tlrt;
1952121186Ssimokawa	sfp->mode.wres.tcode = FWTCODE_WRES;
1953121186Ssimokawa	sfp->mode.wres.rtcode = rtcode;
1954121186Ssimokawa	sfp->mode.wres.pri = 0;
1955121186Ssimokawa
1956121186Ssimokawa	fw_asyreq(xfer->fc, -1, xfer);
1957121186Ssimokawa	splx(s);
1958121186Ssimokawa}
1959121186Ssimokawa
1960121186Ssimokawastatic int
1961121186Ssimokawasbp_targ_attach(device_t dev)
1962121186Ssimokawa{
1963121186Ssimokawa	struct sbp_targ_softc *sc;
1964121186Ssimokawa	struct cam_devq *devq;
1965170374Ssimokawa	struct firewire_comm *fc;
1966121186Ssimokawa
1967121186Ssimokawa        sc = (struct sbp_targ_softc *) device_get_softc(dev);
1968121186Ssimokawa	bzero((void *)sc, sizeof(struct sbp_targ_softc));
1969121186Ssimokawa
1970170374Ssimokawa	mtx_init(&sc->mtx, "sbp_targ", NULL, MTX_DEF);
1971170374Ssimokawa	sc->fd.fc = fc = device_get_ivars(dev);
1972121186Ssimokawa	sc->fd.dev = dev;
1973123430Ssimokawa	sc->fd.post_explore = (void *) sbp_targ_post_explore;
1974121186Ssimokawa	sc->fd.post_busreset = (void *) sbp_targ_post_busreset;
1975121186Ssimokawa
1976169475Ssimokawa        devq = cam_simq_alloc(/*maxopenings*/MAX_LUN*MAX_INITIATORS);
1977121186Ssimokawa	if (devq == NULL)
1978121186Ssimokawa		return (ENXIO);
1979121186Ssimokawa
1980121186Ssimokawa	sc->sim = cam_sim_alloc(sbp_targ_action, sbp_targ_poll,
1981170374Ssimokawa	    "sbp_targ", sc, device_get_unit(dev), &sc->mtx,
1982121186Ssimokawa	    /*untagged*/ 1, /*tagged*/ 1, devq);
1983121186Ssimokawa	if (sc->sim == NULL) {
1984121186Ssimokawa		cam_simq_free(devq);
1985121186Ssimokawa		return (ENXIO);
1986121186Ssimokawa	}
1987121186Ssimokawa
1988170374Ssimokawa	SBP_LOCK(sc);
1989170872Sscottl	if (xpt_bus_register(sc->sim, dev, /*bus*/0) != CAM_SUCCESS)
1990121186Ssimokawa		goto fail;
1991121186Ssimokawa
1992121186Ssimokawa	if (xpt_create_path(&sc->path, /*periph*/ NULL, cam_sim_path(sc->sim),
1993121186Ssimokawa	    CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
1994121186Ssimokawa		xpt_bus_deregister(cam_sim_path(sc->sim));
1995121186Ssimokawa		goto fail;
1996121186Ssimokawa	}
1997170374Ssimokawa	SBP_UNLOCK(sc);
1998121186Ssimokawa
1999121186Ssimokawa	sc->fwb.start = SBP_TARG_BIND_START;
2000121186Ssimokawa	sc->fwb.end = SBP_TARG_BIND_END;
2001121186Ssimokawa
2002121186Ssimokawa	/* pre-allocate xfer */
2003121186Ssimokawa	STAILQ_INIT(&sc->fwb.xferlist);
2004169130Ssimokawa	fw_xferlist_add(&sc->fwb.xferlist, M_SBP_TARG,
2005169130Ssimokawa	    /*send*/ 0, /*recv*/ SBP_TARG_RECV_LEN, MAX_LUN /* XXX */,
2006170374Ssimokawa	    fc, (void *)sc, sbp_targ_recv);
2007170374Ssimokawa	fw_bindadd(fc, &sc->fwb);
2008121186Ssimokawa	return 0;
2009121186Ssimokawa
2010121186Ssimokawafail:
2011170374Ssimokawa	SBP_UNLOCK(sc);
2012121186Ssimokawa	cam_sim_free(sc->sim, /*free_devq*/TRUE);
2013121186Ssimokawa	return (ENXIO);
2014121186Ssimokawa}
2015121186Ssimokawa
2016121186Ssimokawastatic int
2017121186Ssimokawasbp_targ_detach(device_t dev)
2018121186Ssimokawa{
2019121186Ssimokawa	struct sbp_targ_softc *sc;
2020121186Ssimokawa	struct sbp_targ_lstate *lstate;
2021121186Ssimokawa	int i;
2022121186Ssimokawa
2023121186Ssimokawa	sc = (struct sbp_targ_softc *)device_get_softc(dev);
2024121186Ssimokawa	sc->fd.post_busreset = NULL;
2025121186Ssimokawa
2026170374Ssimokawa	SBP_LOCK(sc);
2027121186Ssimokawa	xpt_free_path(sc->path);
2028121186Ssimokawa	xpt_bus_deregister(cam_sim_path(sc->sim));
2029170374Ssimokawa	SBP_UNLOCK(sc);
2030121186Ssimokawa	cam_sim_free(sc->sim, /*free_devq*/TRUE);
2031121186Ssimokawa
2032121186Ssimokawa	for (i = 0; i < MAX_LUN; i ++) {
2033121186Ssimokawa		lstate = sc->lstate[i];
2034121186Ssimokawa		if (lstate != NULL) {
2035121186Ssimokawa			xpt_free_path(lstate->path);
2036121186Ssimokawa			free(lstate, M_SBP_TARG);
2037121186Ssimokawa		}
2038121186Ssimokawa	}
2039121186Ssimokawa	if (sc->black_hole != NULL) {
2040121186Ssimokawa		xpt_free_path(sc->black_hole->path);
2041121186Ssimokawa		free(sc->black_hole, M_SBP_TARG);
2042121186Ssimokawa	}
2043121186Ssimokawa
2044121186Ssimokawa	fw_bindremove(sc->fd.fc, &sc->fwb);
2045169130Ssimokawa	fw_xferlist_remove(&sc->fwb.xferlist);
2046121186Ssimokawa
2047170374Ssimokawa	mtx_destroy(&sc->mtx);
2048170374Ssimokawa
2049121186Ssimokawa	return 0;
2050121186Ssimokawa}
2051121186Ssimokawa
2052121186Ssimokawastatic devclass_t sbp_targ_devclass;
2053121186Ssimokawa
2054121186Ssimokawastatic device_method_t sbp_targ_methods[] = {
2055121186Ssimokawa	/* device interface */
2056121186Ssimokawa	DEVMETHOD(device_identify,	sbp_targ_identify),
2057121186Ssimokawa	DEVMETHOD(device_probe,		sbp_targ_probe),
2058121186Ssimokawa	DEVMETHOD(device_attach,	sbp_targ_attach),
2059121186Ssimokawa	DEVMETHOD(device_detach,	sbp_targ_detach),
2060121186Ssimokawa	{ 0, 0 }
2061121186Ssimokawa};
2062121186Ssimokawa
2063121186Ssimokawastatic driver_t sbp_targ_driver = {
2064121186Ssimokawa	"sbp_targ",
2065121186Ssimokawa	sbp_targ_methods,
2066121186Ssimokawa	sizeof(struct sbp_targ_softc),
2067121186Ssimokawa};
2068121186Ssimokawa
2069121186SsimokawaDRIVER_MODULE(sbp_targ, firewire, sbp_targ_driver, sbp_targ_devclass, 0, 0);
2070121186SsimokawaMODULE_VERSION(sbp_targ, 1);
2071121186SsimokawaMODULE_DEPEND(sbp_targ, firewire, 1, 1, 1);
2072121186SsimokawaMODULE_DEPEND(sbp_targ, cam, 1, 1, 1);
2073