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$
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>
44226067Sken#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>
65121186Ssimokawa
66123430Ssimokawa#define SBP_TARG_RECV_LEN	8
67123430Ssimokawa#define MAX_INITIATORS		8
68123430Ssimokawa#define MAX_LUN			63
69123430Ssimokawa#define MAX_LOGINS		63
70123430Ssimokawa#define MAX_NODES		63
71121186Ssimokawa/*
72121186Ssimokawa * management/command block agent registers
73121186Ssimokawa *
74121186Ssimokawa * BASE 0xffff f001 0000 management port
75123430Ssimokawa * BASE 0xffff f001 0020 command port for login id 0
76123430Ssimokawa * BASE 0xffff f001 0040 command port for login id 1
77121186Ssimokawa *
78121186Ssimokawa */
79121186Ssimokawa#define SBP_TARG_MGM	 0x10000	/* offset from 0xffff f000 000 */
80121186Ssimokawa#define SBP_TARG_BIND_HI	0xffff
81121186Ssimokawa#define SBP_TARG_BIND_LO(l)	(0xf0000000 + SBP_TARG_MGM + 0x20 * ((l) + 1))
82121186Ssimokawa#define SBP_TARG_BIND_START	(((u_int64_t)SBP_TARG_BIND_HI << 32) | \
83121186Ssimokawa				    SBP_TARG_BIND_LO(-1))
84121186Ssimokawa#define SBP_TARG_BIND_END	(((u_int64_t)SBP_TARG_BIND_HI << 32) | \
85123430Ssimokawa				    SBP_TARG_BIND_LO(MAX_LOGINS))
86123430Ssimokawa#define SBP_TARG_LOGIN_ID(lo)	(((lo) - SBP_TARG_BIND_LO(0))/0x20)
87121186Ssimokawa
88121186Ssimokawa#define FETCH_MGM	0
89121186Ssimokawa#define FETCH_CMD	1
90121186Ssimokawa#define FETCH_POINTER	2
91121186Ssimokawa
92123430Ssimokawa#define F_LINK_ACTIVE	(1 << 0)
93123430Ssimokawa#define F_ATIO_STARVED	(1 << 1)
94123430Ssimokawa#define F_LOGIN		(1 << 2)
95123430Ssimokawa#define F_HOLD		(1 << 3)
96123430Ssimokawa#define F_FREEZED	(1 << 4)
97123430Ssimokawa
98249132Smavstatic MALLOC_DEFINE(M_SBP_TARG, "sbp_targ", "SBP-II/FireWire target mode");
99121186Ssimokawa
100121186Ssimokawastatic int debug = 0;
101121186Ssimokawa
102121186SsimokawaSYSCTL_INT(_debug, OID_AUTO, sbp_targ_debug, CTLFLAG_RW, &debug, 0,
103121186Ssimokawa        "SBP target mode debug flag");
104121186Ssimokawa
105123430Ssimokawastruct sbp_targ_login {
106123430Ssimokawa	struct sbp_targ_lstate *lstate;
107123430Ssimokawa	struct fw_device *fwdev;
108123430Ssimokawa	struct sbp_login_res loginres;
109129585Sdfr	uint16_t fifo_hi;
110129585Sdfr	uint16_t last_hi;
111129585Sdfr	uint32_t fifo_lo;
112129585Sdfr	uint32_t last_lo;
113123430Ssimokawa	STAILQ_HEAD(, orb_info) orbs;
114124877Ssimokawa	STAILQ_ENTRY(sbp_targ_login) link;
115129585Sdfr	uint16_t hold_sec;
116129585Sdfr	uint16_t id;
117129585Sdfr	uint8_t flags;
118129585Sdfr	uint8_t spd;
119123430Ssimokawa	struct callout hold_callout;
120123430Ssimokawa};
121123430Ssimokawa
122123430Ssimokawastruct sbp_targ_lstate {
123129585Sdfr	uint16_t lun;
124123430Ssimokawa	struct sbp_targ_softc *sc;
125123430Ssimokawa	struct cam_path *path;
126123430Ssimokawa	struct ccb_hdr_slist accept_tios;
127123430Ssimokawa	struct ccb_hdr_slist immed_notifies;
128123430Ssimokawa	struct crom_chunk model;
129129585Sdfr	uint32_t flags;
130123430Ssimokawa	STAILQ_HEAD(, sbp_targ_login) logins;
131123430Ssimokawa};
132123430Ssimokawa
133121186Ssimokawastruct sbp_targ_softc {
134121186Ssimokawa        struct firewire_dev_comm fd;
135121186Ssimokawa	struct cam_sim *sim;
136121186Ssimokawa	struct cam_path *path;
137121186Ssimokawa	struct fw_bind fwb;
138121186Ssimokawa	int ndevs;
139123430Ssimokawa	int flags;
140121186Ssimokawa	struct crom_chunk unit;
141121186Ssimokawa	struct sbp_targ_lstate *lstate[MAX_LUN];
142121186Ssimokawa	struct sbp_targ_lstate *black_hole;
143123430Ssimokawa	struct sbp_targ_login *logins[MAX_LOGINS];
144170374Ssimokawa	struct mtx mtx;
145121186Ssimokawa};
146170374Ssimokawa#define SBP_LOCK(sc) mtx_lock(&(sc)->mtx)
147170374Ssimokawa#define SBP_UNLOCK(sc) mtx_unlock(&(sc)->mtx)
148121186Ssimokawa
149121186Ssimokawastruct corb4 {
150121186Ssimokawa#if BYTE_ORDER == BIG_ENDIAN
151129585Sdfr	uint32_t n:1,
152121186Ssimokawa		  rq_fmt:2,
153121186Ssimokawa		  :1,
154121186Ssimokawa		  dir:1,
155121186Ssimokawa		  spd:3,
156121186Ssimokawa		  max_payload:4,
157121186Ssimokawa		  page_table_present:1,
158121186Ssimokawa		  page_size:3,
159121186Ssimokawa		  data_size:16;
160121186Ssimokawa#else
161129585Sdfr	uint32_t data_size:16,
162121186Ssimokawa		  page_size:3,
163121186Ssimokawa		  page_table_present:1,
164121186Ssimokawa		  max_payload:4,
165121186Ssimokawa		  spd:3,
166121186Ssimokawa		  dir:1,
167121186Ssimokawa		  :1,
168121186Ssimokawa		  rq_fmt:2,
169121186Ssimokawa		  n:1;
170121186Ssimokawa#endif
171121186Ssimokawa};
172121186Ssimokawa
173121186Ssimokawastruct morb4 {
174121186Ssimokawa#if BYTE_ORDER == BIG_ENDIAN
175129585Sdfr	uint32_t n:1,
176121186Ssimokawa		  rq_fmt:2,
177121186Ssimokawa		  :9,
178121186Ssimokawa		  fun:4,
179121186Ssimokawa		  id:16;
180121186Ssimokawa#else
181129585Sdfr	uint32_t id:16,
182121186Ssimokawa		  fun:4,
183121186Ssimokawa		  :9,
184121186Ssimokawa		  rq_fmt:2,
185121186Ssimokawa		  n:1;
186121186Ssimokawa#endif
187121186Ssimokawa};
188121186Ssimokawa
189121186Ssimokawastruct orb_info {
190121186Ssimokawa	struct sbp_targ_softc *sc;
191121186Ssimokawa	struct fw_device *fwdev;
192123430Ssimokawa	struct sbp_targ_login *login;
193121186Ssimokawa	union ccb *ccb;
194121186Ssimokawa	struct ccb_accept_tio *atio;
195129585Sdfr	uint8_t state;
196121186Ssimokawa#define ORBI_STATUS_NONE	0
197121186Ssimokawa#define ORBI_STATUS_FETCH	1
198121186Ssimokawa#define ORBI_STATUS_ATIO	2
199121186Ssimokawa#define ORBI_STATUS_CTIO	3
200121186Ssimokawa#define ORBI_STATUS_STATUS	4
201121186Ssimokawa#define ORBI_STATUS_POINTER	5
202121186Ssimokawa#define ORBI_STATUS_ABORTED	7
203129585Sdfr	uint8_t refcount;
204129585Sdfr	uint16_t orb_hi;
205129585Sdfr	uint32_t orb_lo;
206129585Sdfr	uint32_t data_hi;
207129585Sdfr	uint32_t data_lo;
208121186Ssimokawa	struct corb4 orb4;
209121186Ssimokawa	STAILQ_ENTRY(orb_info) link;
210129585Sdfr	uint32_t orb[8];
211129585Sdfr	uint32_t *page_table;
212121186Ssimokawa	struct sbp_status status;
213121186Ssimokawa};
214121186Ssimokawa
215121186Ssimokawastatic char *orb_fun_name[] = {
216121186Ssimokawa	ORB_FUN_NAMES
217121186Ssimokawa};
218121186Ssimokawa
219121186Ssimokawastatic void sbp_targ_recv(struct fw_xfer *);
220121186Ssimokawastatic void sbp_targ_fetch_orb(struct sbp_targ_softc *, struct fw_device *,
221129585Sdfr    uint16_t, uint32_t, struct sbp_targ_login *, int);
222170374Ssimokawastatic void sbp_targ_abort(struct sbp_targ_softc *, struct orb_info *);
223121186Ssimokawa
224121186Ssimokawastatic void
225121186Ssimokawasbp_targ_identify(driver_t *driver, device_t parent)
226121186Ssimokawa{
227121186Ssimokawa	BUS_ADD_CHILD(parent, 0, "sbp_targ", device_get_unit(parent));
228121186Ssimokawa}
229121186Ssimokawa
230121186Ssimokawastatic int
231121186Ssimokawasbp_targ_probe(device_t dev)
232121186Ssimokawa{
233121186Ssimokawa	device_t pa;
234121186Ssimokawa
235121186Ssimokawa	pa = device_get_parent(dev);
236121186Ssimokawa	if(device_get_unit(dev) != device_get_unit(pa)){
237121186Ssimokawa		return(ENXIO);
238121186Ssimokawa	}
239121186Ssimokawa
240121186Ssimokawa	device_set_desc(dev, "SBP-2/SCSI over FireWire target mode");
241121186Ssimokawa	return (0);
242121186Ssimokawa}
243121186Ssimokawa
244121186Ssimokawastatic void
245123430Ssimokawasbp_targ_dealloc_login(struct sbp_targ_login *login)
246123430Ssimokawa{
247123430Ssimokawa	struct orb_info *orbi, *next;
248123430Ssimokawa
249123430Ssimokawa	if (login == NULL) {
250127468Ssimokawa		printf("%s: login = NULL\n", __func__);
251123430Ssimokawa		return;
252123430Ssimokawa	}
253123430Ssimokawa	for (orbi = STAILQ_FIRST(&login->orbs); orbi != NULL; orbi = next) {
254123430Ssimokawa		next = STAILQ_NEXT(orbi, link);
255123430Ssimokawa		free(orbi, M_SBP_TARG);
256123430Ssimokawa	}
257123430Ssimokawa	callout_stop(&login->hold_callout);
258123430Ssimokawa
259123430Ssimokawa	STAILQ_REMOVE(&login->lstate->logins, login, sbp_targ_login, link);
260123430Ssimokawa	login->lstate->sc->logins[login->id] = NULL;
261123430Ssimokawa	free((void *)login, M_SBP_TARG);
262123430Ssimokawa}
263123430Ssimokawa
264123430Ssimokawastatic void
265123430Ssimokawasbp_targ_hold_expire(void *arg)
266123430Ssimokawa{
267123430Ssimokawa	struct sbp_targ_login *login;
268123430Ssimokawa
269123430Ssimokawa	login = (struct sbp_targ_login *)arg;
270123430Ssimokawa
271123430Ssimokawa	if (login->flags & F_HOLD) {
272127468Ssimokawa		printf("%s: login_id=%d expired\n", __func__, login->id);
273123430Ssimokawa		sbp_targ_dealloc_login(login);
274123430Ssimokawa	} else {
275127468Ssimokawa		printf("%s: login_id=%d not hold\n", __func__, login->id);
276123430Ssimokawa	}
277123430Ssimokawa}
278123430Ssimokawa
279123430Ssimokawastatic void
280121186Ssimokawasbp_targ_post_busreset(void *arg)
281121186Ssimokawa{
282121186Ssimokawa	struct sbp_targ_softc *sc;
283121186Ssimokawa	struct crom_src *src;
284121186Ssimokawa	struct crom_chunk *root;
285121186Ssimokawa	struct crom_chunk *unit;
286121186Ssimokawa	struct sbp_targ_lstate *lstate;
287123430Ssimokawa	struct sbp_targ_login *login;
288121186Ssimokawa	int i;
289121186Ssimokawa
290123430Ssimokawa	sc = (struct sbp_targ_softc *)arg;
291121186Ssimokawa	src = sc->fd.fc->crom_src;
292121186Ssimokawa	root = sc->fd.fc->crom_root;
293121186Ssimokawa
294121186Ssimokawa	unit = &sc->unit;
295121186Ssimokawa
296123430Ssimokawa	if ((sc->flags & F_FREEZED) == 0) {
297170374Ssimokawa		SBP_LOCK(sc);
298123430Ssimokawa		sc->flags |= F_FREEZED;
299123430Ssimokawa		xpt_freeze_simq(sc->sim, /*count*/1);
300170374Ssimokawa		SBP_UNLOCK(sc);
301123430Ssimokawa	} else {
302127468Ssimokawa		printf("%s: already freezed\n", __func__);
303123430Ssimokawa	}
304123430Ssimokawa
305121186Ssimokawa	bzero(unit, sizeof(struct crom_chunk));
306121186Ssimokawa
307121186Ssimokawa	crom_add_chunk(src, root, unit, CROM_UDIR);
308121186Ssimokawa	crom_add_entry(unit, CSRKEY_SPEC, CSRVAL_ANSIT10);
309121186Ssimokawa	crom_add_entry(unit, CSRKEY_VER, CSRVAL_T10SBP2);
310121186Ssimokawa	crom_add_entry(unit, CSRKEY_COM_SPEC, CSRVAL_ANSIT10);
311121186Ssimokawa	crom_add_entry(unit, CSRKEY_COM_SET, CSRVAL_SCSI);
312121186Ssimokawa
313121186Ssimokawa	crom_add_entry(unit, CROM_MGM, SBP_TARG_MGM >> 2);
314121186Ssimokawa	crom_add_entry(unit, CSRKEY_UNIT_CH, (10<<8) | 8);
315121186Ssimokawa
316121186Ssimokawa	for (i = 0; i < MAX_LUN; i ++) {
317121186Ssimokawa		lstate = sc->lstate[i];
318121186Ssimokawa		if (lstate == NULL)
319121186Ssimokawa			continue;
320121186Ssimokawa		crom_add_entry(unit, CSRKEY_FIRM_VER, 1);
321121186Ssimokawa		crom_add_entry(unit, CROM_LUN, i);
322121186Ssimokawa		crom_add_entry(unit, CSRKEY_MODEL, 1);
323121186Ssimokawa		crom_add_simple_text(src, unit, &lstate->model, "TargetMode");
324121186Ssimokawa	}
325123430Ssimokawa
326123430Ssimokawa	/* Process for reconnection hold time */
327123430Ssimokawa	for (i = 0; i < MAX_LOGINS; i ++) {
328123430Ssimokawa		login = sc->logins[i];
329123430Ssimokawa		if (login == NULL)
330123430Ssimokawa			continue;
331170374Ssimokawa		sbp_targ_abort(sc, STAILQ_FIRST(&login->orbs));
332123430Ssimokawa		if (login->flags & F_LOGIN) {
333123430Ssimokawa			login->flags |= F_HOLD;
334123430Ssimokawa			callout_reset(&login->hold_callout,
335123430Ssimokawa			    hz * login->hold_sec,
336123430Ssimokawa			    sbp_targ_hold_expire, (void *)login);
337123430Ssimokawa		}
338123430Ssimokawa	}
339121186Ssimokawa}
340121186Ssimokawa
341123430Ssimokawastatic void
342123430Ssimokawasbp_targ_post_explore(void *arg)
343123430Ssimokawa{
344123430Ssimokawa	struct sbp_targ_softc *sc;
345123430Ssimokawa
346123430Ssimokawa	sc = (struct sbp_targ_softc *)arg;
347170374Ssimokawa	SBP_LOCK(sc);
348123430Ssimokawa	sc->flags &= ~F_FREEZED;
349123430Ssimokawa	xpt_release_simq(sc->sim, /*run queue*/TRUE);
350170374Ssimokawa	SBP_UNLOCK(sc);
351123430Ssimokawa	return;
352123430Ssimokawa}
353123430Ssimokawa
354121186Ssimokawastatic cam_status
355121186Ssimokawasbp_targ_find_devs(struct sbp_targ_softc *sc, union ccb *ccb,
356121186Ssimokawa    struct sbp_targ_lstate **lstate, int notfound_failure)
357121186Ssimokawa{
358121186Ssimokawa	u_int lun;
359121186Ssimokawa
360121186Ssimokawa	/* XXX 0 is the only vaild target_id */
361121186Ssimokawa	if (ccb->ccb_h.target_id == CAM_TARGET_WILDCARD &&
362121186Ssimokawa	    ccb->ccb_h.target_lun == CAM_LUN_WILDCARD) {
363121186Ssimokawa		*lstate = sc->black_hole;
364121186Ssimokawa		return (CAM_REQ_CMP);
365121186Ssimokawa	}
366121186Ssimokawa
367121186Ssimokawa	if (ccb->ccb_h.target_id != 0)
368121186Ssimokawa		return (CAM_TID_INVALID);
369121186Ssimokawa
370121186Ssimokawa	lun = ccb->ccb_h.target_lun;
371121186Ssimokawa	if (lun >= MAX_LUN)
372121186Ssimokawa		return (CAM_LUN_INVALID);
373121186Ssimokawa
374121186Ssimokawa	*lstate = sc->lstate[lun];
375121186Ssimokawa
376121186Ssimokawa	if (notfound_failure != 0 && *lstate == NULL)
377121186Ssimokawa		return (CAM_PATH_INVALID);
378121186Ssimokawa
379121186Ssimokawa	return (CAM_REQ_CMP);
380121186Ssimokawa}
381121186Ssimokawa
382121186Ssimokawastatic void
383121186Ssimokawasbp_targ_en_lun(struct sbp_targ_softc *sc, union ccb *ccb)
384121186Ssimokawa{
385121186Ssimokawa	struct ccb_en_lun *cel = &ccb->cel;
386121186Ssimokawa	struct sbp_targ_lstate *lstate;
387121186Ssimokawa	cam_status status;
388121186Ssimokawa
389121186Ssimokawa	status = sbp_targ_find_devs(sc, ccb, &lstate, 0);
390121186Ssimokawa	if (status != CAM_REQ_CMP) {
391121186Ssimokawa		ccb->ccb_h.status = status;
392121186Ssimokawa		return;
393121186Ssimokawa	}
394121186Ssimokawa
395121186Ssimokawa	if (cel->enable != 0) {
396121186Ssimokawa		if (lstate != NULL) {
397121186Ssimokawa			xpt_print_path(ccb->ccb_h.path);
398121186Ssimokawa			printf("Lun already enabled\n");
399121186Ssimokawa			ccb->ccb_h.status = CAM_LUN_ALRDY_ENA;
400121186Ssimokawa			return;
401121186Ssimokawa		}
402121186Ssimokawa		if (cel->grp6_len != 0 || cel->grp7_len != 0) {
403121186Ssimokawa			ccb->ccb_h.status = CAM_REQ_INVALID;
404121186Ssimokawa			printf("Non-zero Group Codes\n");
405121186Ssimokawa			return;
406121186Ssimokawa		}
407121186Ssimokawa		lstate = (struct sbp_targ_lstate *)
408121186Ssimokawa		    malloc(sizeof(*lstate), M_SBP_TARG, M_NOWAIT | M_ZERO);
409121186Ssimokawa		if (lstate == NULL) {
410121186Ssimokawa			xpt_print_path(ccb->ccb_h.path);
411121186Ssimokawa			printf("Couldn't allocate lstate\n");
412121186Ssimokawa			ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
413121186Ssimokawa			return;
414121186Ssimokawa		}
415121186Ssimokawa		if (ccb->ccb_h.target_id == CAM_TARGET_WILDCARD)
416121186Ssimokawa			sc->black_hole = lstate;
417121186Ssimokawa		else
418121186Ssimokawa			sc->lstate[ccb->ccb_h.target_lun] = lstate;
419121186Ssimokawa		memset(lstate, 0, sizeof(*lstate));
420121186Ssimokawa		lstate->sc = sc;
421121186Ssimokawa		status = xpt_create_path(&lstate->path, /*periph*/NULL,
422121186Ssimokawa					 xpt_path_path_id(ccb->ccb_h.path),
423121186Ssimokawa					 xpt_path_target_id(ccb->ccb_h.path),
424121186Ssimokawa					 xpt_path_lun_id(ccb->ccb_h.path));
425121186Ssimokawa		if (status != CAM_REQ_CMP) {
426121186Ssimokawa			free(lstate, M_SBP_TARG);
427121186Ssimokawa			xpt_print_path(ccb->ccb_h.path);
428121186Ssimokawa			printf("Couldn't allocate path\n");
429121186Ssimokawa			ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
430121186Ssimokawa			return;
431121186Ssimokawa		}
432121186Ssimokawa		SLIST_INIT(&lstate->accept_tios);
433121186Ssimokawa		SLIST_INIT(&lstate->immed_notifies);
434123430Ssimokawa		STAILQ_INIT(&lstate->logins);
435121186Ssimokawa
436121186Ssimokawa		ccb->ccb_h.status = CAM_REQ_CMP;
437121186Ssimokawa		xpt_print_path(ccb->ccb_h.path);
438121186Ssimokawa		printf("Lun now enabled for target mode\n");
439121186Ssimokawa		/* bus reset */
440121186Ssimokawa		sc->fd.fc->ibr(sc->fd.fc);
441121186Ssimokawa	} else {
442123430Ssimokawa		struct sbp_targ_login *login, *next;
443123430Ssimokawa
444121186Ssimokawa		if (lstate == NULL) {
445121186Ssimokawa			ccb->ccb_h.status = CAM_LUN_INVALID;
446121186Ssimokawa			return;
447121186Ssimokawa		}
448121186Ssimokawa		ccb->ccb_h.status = CAM_REQ_CMP;
449121186Ssimokawa
450121186Ssimokawa		if (SLIST_FIRST(&lstate->accept_tios) != NULL) {
451121186Ssimokawa			printf("ATIOs pending\n");
452121186Ssimokawa			ccb->ccb_h.status = CAM_REQ_INVALID;
453121186Ssimokawa		}
454121186Ssimokawa
455121186Ssimokawa		if (SLIST_FIRST(&lstate->immed_notifies) != NULL) {
456121186Ssimokawa			printf("INOTs pending\n");
457121186Ssimokawa			ccb->ccb_h.status = CAM_REQ_INVALID;
458121186Ssimokawa		}
459121186Ssimokawa
460121186Ssimokawa		if (ccb->ccb_h.status != CAM_REQ_CMP) {
461121186Ssimokawa			return;
462121186Ssimokawa		}
463121186Ssimokawa
464121186Ssimokawa		xpt_print_path(ccb->ccb_h.path);
465121186Ssimokawa		printf("Target mode disabled\n");
466121186Ssimokawa		xpt_free_path(lstate->path);
467121186Ssimokawa
468123430Ssimokawa		for (login = STAILQ_FIRST(&lstate->logins); login != NULL;
469123430Ssimokawa		    login = next) {
470123430Ssimokawa			next = STAILQ_NEXT(login, link);
471123430Ssimokawa			sbp_targ_dealloc_login(login);
472121186Ssimokawa		}
473121186Ssimokawa
474121186Ssimokawa		if (ccb->ccb_h.target_id == CAM_TARGET_WILDCARD)
475121186Ssimokawa			sc->black_hole = NULL;
476121186Ssimokawa		else
477121186Ssimokawa			sc->lstate[ccb->ccb_h.target_lun] = NULL;
478121186Ssimokawa		free(lstate, M_SBP_TARG);
479121186Ssimokawa
480121186Ssimokawa		/* bus reset */
481121186Ssimokawa		sc->fd.fc->ibr(sc->fd.fc);
482121186Ssimokawa	}
483121186Ssimokawa}
484121186Ssimokawa
485121186Ssimokawastatic void
486121186Ssimokawasbp_targ_send_lstate_events(struct sbp_targ_softc *sc,
487121186Ssimokawa    struct sbp_targ_lstate *lstate)
488121186Ssimokawa{
489121186Ssimokawa#if 0
490121186Ssimokawa	struct ccb_hdr *ccbh;
491237825Sken	struct ccb_immediate_notify *inot;
492121186Ssimokawa
493127468Ssimokawa	printf("%s: not implemented yet\n", __func__);
494121186Ssimokawa#endif
495121186Ssimokawa}
496121186Ssimokawa
497170374Ssimokawa
498121186Ssimokawastatic __inline void
499170374Ssimokawasbp_targ_remove_orb_info_locked(struct sbp_targ_login *login, struct orb_info *orbi)
500170374Ssimokawa{
501170374Ssimokawa	STAILQ_REMOVE(&login->orbs, orbi, orb_info, link);
502170374Ssimokawa}
503170374Ssimokawa
504170374Ssimokawastatic __inline void
505123430Ssimokawasbp_targ_remove_orb_info(struct sbp_targ_login *login, struct orb_info *orbi)
506121186Ssimokawa{
507170374Ssimokawa	SBP_LOCK(orbi->sc);
508123430Ssimokawa	STAILQ_REMOVE(&login->orbs, orbi, orb_info, link);
509170374Ssimokawa	SBP_UNLOCK(orbi->sc);
510121186Ssimokawa}
511121186Ssimokawa
512121186Ssimokawa/*
513121186Ssimokawa * tag_id/init_id encoding
514121186Ssimokawa *
515121186Ssimokawa * tag_id and init_id has only 32bit for each.
516121186Ssimokawa * scsi_target can handle very limited number(up to 15) of init_id.
517121186Ssimokawa * we have to encode 48bit orb and 64bit EUI64 into these
518121186Ssimokawa * variables.
519121186Ssimokawa *
520121186Ssimokawa * tag_id represents lower 32bit of ORB address.
521123430Ssimokawa * init_id represents login_id.
522121186Ssimokawa *
523121186Ssimokawa */
524121186Ssimokawa
525121186Ssimokawastatic struct orb_info *
526121186Ssimokawasbp_targ_get_orb_info(struct sbp_targ_lstate *lstate,
527121186Ssimokawa    u_int tag_id, u_int init_id)
528121186Ssimokawa{
529123430Ssimokawa	struct sbp_targ_login *login;
530121186Ssimokawa	struct orb_info *orbi;
531121186Ssimokawa
532123430Ssimokawa	login = lstate->sc->logins[init_id];
533123430Ssimokawa	if (login == NULL) {
534127468Ssimokawa		printf("%s: no such login\n", __func__);
535123430Ssimokawa		return (NULL);
536123430Ssimokawa	}
537123430Ssimokawa	STAILQ_FOREACH(orbi, &login->orbs, link)
538123430Ssimokawa		if (orbi->orb_lo == tag_id)
539121186Ssimokawa			goto found;
540170374Ssimokawa	printf("%s: orb not found tag_id=0x%08x init_id=%d\n",
541170374Ssimokawa				 __func__, tag_id, init_id);
542121186Ssimokawa	return (NULL);
543121186Ssimokawafound:
544121186Ssimokawa	return (orbi);
545121186Ssimokawa}
546121186Ssimokawa
547121186Ssimokawastatic void
548170374Ssimokawasbp_targ_abort(struct sbp_targ_softc *sc, struct orb_info *orbi)
549121186Ssimokawa{
550121186Ssimokawa	struct orb_info *norbi;
551121186Ssimokawa
552170374Ssimokawa	SBP_LOCK(sc);
553121186Ssimokawa	for (; orbi != NULL; orbi = norbi) {
554170374Ssimokawa		printf("%s: status=%d ccb=%p\n", __func__, orbi->state, orbi->ccb);
555121186Ssimokawa		norbi = STAILQ_NEXT(orbi, link);
556121186Ssimokawa		if (orbi->state != ORBI_STATUS_ABORTED) {
557121186Ssimokawa			if (orbi->ccb != NULL) {
558121186Ssimokawa				orbi->ccb->ccb_h.status = CAM_REQ_ABORTED;
559121186Ssimokawa				xpt_done(orbi->ccb);
560121186Ssimokawa				orbi->ccb = NULL;
561121186Ssimokawa			}
562170374Ssimokawa#if 0
563121186Ssimokawa			if (orbi->state <= ORBI_STATUS_ATIO) {
564170374Ssimokawa				sbp_targ_remove_orb_info_locked(orbi->login, orbi);
565121186Ssimokawa				free(orbi, M_SBP_TARG);
566121186Ssimokawa			} else
567170374Ssimokawa#endif
568121186Ssimokawa				orbi->state = ORBI_STATUS_ABORTED;
569121186Ssimokawa		}
570121186Ssimokawa	}
571170374Ssimokawa	SBP_UNLOCK(sc);
572121186Ssimokawa}
573121186Ssimokawa
574121186Ssimokawastatic void
575121186Ssimokawasbp_targ_free_orbi(struct fw_xfer *xfer)
576121186Ssimokawa{
577121186Ssimokawa	struct orb_info *orbi;
578121186Ssimokawa
579121186Ssimokawa	orbi = (struct orb_info *)xfer->sc;
580121186Ssimokawa	if (xfer->resp != 0) {
581121186Ssimokawa		/* XXX */
582127468Ssimokawa		printf("%s: xfer->resp = %d\n", __func__, xfer->resp);
583121186Ssimokawa	}
584121186Ssimokawa	free(orbi, M_SBP_TARG);
585121186Ssimokawa	fw_xfer_free(xfer);
586121186Ssimokawa}
587121186Ssimokawa
588121186Ssimokawastatic void
589121186Ssimokawasbp_targ_status_FIFO(struct orb_info *orbi,
590129585Sdfr    uint32_t fifo_hi, uint32_t fifo_lo, int dequeue)
591121186Ssimokawa{
592121186Ssimokawa	struct fw_xfer *xfer;
593121186Ssimokawa
594121186Ssimokawa	if (dequeue)
595123430Ssimokawa		sbp_targ_remove_orb_info(orbi->login, orbi);
596121186Ssimokawa
597121186Ssimokawa	xfer = fwmem_write_block(orbi->fwdev, (void *)orbi,
598121186Ssimokawa	    /*spd*/2, fifo_hi, fifo_lo,
599129585Sdfr	    sizeof(uint32_t) * (orbi->status.len + 1), (char *)&orbi->status,
600121186Ssimokawa	    sbp_targ_free_orbi);
601121186Ssimokawa
602121186Ssimokawa	if (xfer == NULL) {
603121186Ssimokawa		/* XXX */
604127468Ssimokawa		printf("%s: xfer == NULL\n", __func__);
605121186Ssimokawa	}
606121186Ssimokawa}
607121186Ssimokawa
608121186Ssimokawastatic void
609121186Ssimokawasbp_targ_send_status(struct orb_info *orbi, union ccb *ccb)
610121186Ssimokawa{
611121186Ssimokawa	struct sbp_status *sbp_status;
612170410Smjacob#if	0
613170374Ssimokawa	struct orb_info *norbi;
614170410Smjacob#endif
615121186Ssimokawa
616121186Ssimokawa	sbp_status = &orbi->status;
617121186Ssimokawa
618121186Ssimokawa	orbi->state = ORBI_STATUS_STATUS;
619121186Ssimokawa
620121186Ssimokawa	sbp_status->resp = 0; /* XXX */
621121186Ssimokawa	sbp_status->status = 0; /* XXX */
622121186Ssimokawa	sbp_status->dead = 0; /* XXX */
623121186Ssimokawa
624121186Ssimokawa	switch (ccb->csio.scsi_status) {
625121186Ssimokawa	case SCSI_STATUS_OK:
626121186Ssimokawa		if (debug)
627127468Ssimokawa			printf("%s: STATUS_OK\n", __func__);
628121186Ssimokawa		sbp_status->len = 1;
629121186Ssimokawa		break;
630121186Ssimokawa	case SCSI_STATUS_CHECK_COND:
631121186Ssimokawa	case SCSI_STATUS_BUSY:
632121186Ssimokawa	case SCSI_STATUS_CMD_TERMINATED:
633121186Ssimokawa	{
634121186Ssimokawa		struct sbp_cmd_status *sbp_cmd_status;
635121186Ssimokawa		struct scsi_sense_data *sense;
636226067Sken		int error_code, sense_key, asc, ascq;
637226067Sken		uint8_t stream_bits;
638226067Sken		uint8_t sks[3];
639226067Sken		uint64_t info;
640226067Sken		int64_t sinfo;
641226067Sken		int sense_len;
642121186Ssimokawa
643121186Ssimokawa		if (debug)
644127468Ssimokawa			printf("%s: STATUS %d\n", __func__,
645121186Ssimokawa			    ccb->csio.scsi_status);
646121186Ssimokawa		sbp_cmd_status = (struct sbp_cmd_status *)&sbp_status->data[0];
647121186Ssimokawa		sbp_cmd_status->status = ccb->csio.scsi_status;
648121186Ssimokawa		sense = &ccb->csio.sense_data;
649121186Ssimokawa
650170374Ssimokawa#if 0		/* XXX What we should do? */
651170374Ssimokawa#if 0
652170374Ssimokawa		sbp_targ_abort(orbi->sc, STAILQ_NEXT(orbi, link));
653170374Ssimokawa#else
654170374Ssimokawa		norbi = STAILQ_NEXT(orbi, link);
655170374Ssimokawa		while (norbi) {
656170374Ssimokawa			printf("%s: status=%d\n", __func__, norbi->state);
657170374Ssimokawa			if (norbi->ccb != NULL) {
658170374Ssimokawa				norbi->ccb->ccb_h.status = CAM_REQ_ABORTED;
659170374Ssimokawa				xpt_done(norbi->ccb);
660170374Ssimokawa				norbi->ccb = NULL;
661170374Ssimokawa			}
662170374Ssimokawa			sbp_targ_remove_orb_info_locked(orbi->login, norbi);
663170374Ssimokawa			norbi = STAILQ_NEXT(norbi, link);
664170374Ssimokawa			free(norbi, M_SBP_TARG);
665170374Ssimokawa		}
666170374Ssimokawa#endif
667170374Ssimokawa#endif
668121186Ssimokawa
669226067Sken		sense_len = ccb->csio.sense_len - ccb->csio.sense_resid;
670226067Sken		scsi_extract_sense_len(sense, sense_len, &error_code,
671226067Sken		    &sense_key, &asc, &ascq, /*show_errors*/ 0);
672226067Sken
673226067Sken		switch (error_code) {
674226067Sken		case SSD_CURRENT_ERROR:
675226067Sken		case SSD_DESC_CURRENT_ERROR:
676121186Ssimokawa			sbp_cmd_status->sfmt = SBP_SFMT_CURR;
677226067Sken			break;
678226067Sken		default:
679121186Ssimokawa			sbp_cmd_status->sfmt = SBP_SFMT_DEFER;
680226067Sken			break;
681226067Sken		}
682121186Ssimokawa
683226067Sken		if (scsi_get_sense_info(sense, sense_len, SSD_DESC_INFO, &info,
684226067Sken					&sinfo) == 0) {
685226067Sken			uint32_t info_trunc;
686226067Sken			sbp_cmd_status->valid = 1;
687226067Sken			info_trunc = info;
688121186Ssimokawa
689226067Sken			sbp_cmd_status->info = htobe32(info_trunc);
690226067Sken		} else {
691226067Sken			sbp_cmd_status->valid = 0;
692226067Sken		}
693121186Ssimokawa
694226067Sken		sbp_cmd_status->s_key = sense_key;
695226067Sken
696226067Sken		if (scsi_get_stream_info(sense, sense_len, NULL,
697226067Sken					 &stream_bits) == 0) {
698226067Sken			sbp_cmd_status->mark =
699226067Sken			    (stream_bits & SSD_FILEMARK) ? 1 : 0;
700226067Sken			sbp_cmd_status->eom =
701226067Sken			    (stream_bits & SSD_EOM) ? 1 : 0;
702226067Sken			sbp_cmd_status->ill_len =
703226067Sken			    (stream_bits & SSD_ILI) ? 1 : 0;
704226067Sken		} else {
705226067Sken			sbp_cmd_status->mark = 0;
706226067Sken			sbp_cmd_status->eom = 0;
707226067Sken			sbp_cmd_status->ill_len = 0;
708226067Sken		}
709226067Sken
710226067Sken
711226067Sken		/* add_sense_code(_qual), info, cmd_spec_info */
712226067Sken		sbp_status->len = 4;
713226067Sken
714226067Sken		if (scsi_get_sense_info(sense, sense_len, SSD_DESC_COMMAND,
715226067Sken					&info, &sinfo) == 0) {
716226067Sken			uint32_t cmdspec_trunc;
717226067Sken
718226067Sken			cmdspec_trunc = info;
719226067Sken
720226067Sken			sbp_cmd_status->cdb = htobe32(cmdspec_trunc);
721226067Sken		}
722226067Sken
723226067Sken		sbp_cmd_status->s_code = asc;
724226067Sken		sbp_cmd_status->s_qlfr = ascq;
725226067Sken
726226067Sken		if (scsi_get_sense_info(sense, sense_len, SSD_DESC_FRU, &info,
727226067Sken					&sinfo) == 0) {
728226067Sken			sbp_cmd_status->fru = (uint8_t)info;
729121186Ssimokawa			sbp_status->len = 5;
730226067Sken		} else {
731226067Sken			sbp_cmd_status->fru = 0;
732226067Sken		}
733121186Ssimokawa
734226067Sken		if (scsi_get_sks(sense, sense_len, sks) == 0) {
735226067Sken			bcopy(sks, &sbp_cmd_status->s_keydep[0], sizeof(sks));
736226067Sken			sbp_status->len = 5;
737226067Sken		}
738121186Ssimokawa
739121186Ssimokawa		break;
740121186Ssimokawa	}
741121186Ssimokawa	default:
742127468Ssimokawa		printf("%s: unknown scsi status 0x%x\n", __func__,
743121186Ssimokawa		    sbp_status->status);
744121186Ssimokawa	}
745121186Ssimokawa
746170374Ssimokawa	if (orbi->page_table != NULL)
747170374Ssimokawa		free(orbi->page_table, M_SBP_TARG);
748170374Ssimokawa
749121186Ssimokawa	sbp_targ_status_FIFO(orbi,
750123430Ssimokawa	    orbi->login->fifo_hi, orbi->login->fifo_lo, /*dequeue*/1);
751121186Ssimokawa}
752121186Ssimokawa
753121186Ssimokawastatic void
754121186Ssimokawasbp_targ_cam_done(struct fw_xfer *xfer)
755121186Ssimokawa{
756121186Ssimokawa	struct orb_info *orbi;
757121186Ssimokawa	union ccb *ccb;
758121186Ssimokawa
759121186Ssimokawa	orbi = (struct orb_info *)xfer->sc;
760121186Ssimokawa
761123430Ssimokawa	if (debug > 1)
762127468Ssimokawa		printf("%s: resp=%d refcount=%d\n", __func__,
763121186Ssimokawa			xfer->resp, orbi->refcount);
764121186Ssimokawa
765121186Ssimokawa	if (xfer->resp != 0) {
766127468Ssimokawa		printf("%s: xfer->resp = %d\n", __func__, xfer->resp);
767121186Ssimokawa		orbi->status.resp = SBP_TRANS_FAIL;
768124877Ssimokawa		orbi->status.status = OBJ_DATA | SBE_TIMEOUT/*XXX*/;
769121186Ssimokawa		orbi->status.dead = 1;
770170374Ssimokawa		sbp_targ_abort(orbi->sc, STAILQ_NEXT(orbi, link));
771121186Ssimokawa	}
772121186Ssimokawa
773121186Ssimokawa	orbi->refcount --;
774121186Ssimokawa
775121186Ssimokawa	ccb = orbi->ccb;
776121186Ssimokawa	if (orbi->refcount == 0) {
777170374Ssimokawa		orbi->ccb = NULL;
778121186Ssimokawa		if (orbi->state == ORBI_STATUS_ABORTED) {
779121186Ssimokawa			if (debug)
780127468Ssimokawa				printf("%s: orbi aborted\n", __func__);
781123430Ssimokawa			sbp_targ_remove_orb_info(orbi->login, orbi);
782121186Ssimokawa			if (orbi->page_table != NULL)
783121186Ssimokawa				free(orbi->page_table, M_SBP_TARG);
784121186Ssimokawa			free(orbi, M_SBP_TARG);
785121186Ssimokawa		} else if (orbi->status.resp == 0) {
786121186Ssimokawa			if ((ccb->ccb_h.flags & CAM_SEND_STATUS) != 0)
787121186Ssimokawa				sbp_targ_send_status(orbi, ccb);
788121186Ssimokawa			ccb->ccb_h.status = CAM_REQ_CMP;
789170374Ssimokawa			SBP_LOCK(orbi->sc);
790121186Ssimokawa			xpt_done(ccb);
791170374Ssimokawa			SBP_UNLOCK(orbi->sc);
792121186Ssimokawa		} else {
793121186Ssimokawa			orbi->status.len = 1;
794121186Ssimokawa			sbp_targ_status_FIFO(orbi,
795123430Ssimokawa		    	    orbi->login->fifo_hi, orbi->login->fifo_lo,
796121186Ssimokawa			    /*dequeue*/1);
797121186Ssimokawa			ccb->ccb_h.status = CAM_REQ_ABORTED;
798170374Ssimokawa			SBP_LOCK(orbi->sc);
799121186Ssimokawa			xpt_done(ccb);
800170374Ssimokawa			SBP_UNLOCK(orbi->sc);
801121186Ssimokawa		}
802121186Ssimokawa	}
803121186Ssimokawa
804121186Ssimokawa	fw_xfer_free(xfer);
805121186Ssimokawa}
806121186Ssimokawa
807121186Ssimokawastatic cam_status
808121186Ssimokawasbp_targ_abort_ccb(struct sbp_targ_softc *sc, union ccb *ccb)
809121186Ssimokawa{
810121186Ssimokawa	union ccb *accb;
811121186Ssimokawa	struct sbp_targ_lstate *lstate;
812121186Ssimokawa	struct ccb_hdr_slist *list;
813121186Ssimokawa	struct ccb_hdr *curelm;
814121186Ssimokawa	int found;
815121186Ssimokawa	cam_status status;
816121186Ssimokawa
817121186Ssimokawa	status = sbp_targ_find_devs(sc, ccb, &lstate, 0);
818121186Ssimokawa	if (status != CAM_REQ_CMP)
819121186Ssimokawa		return (status);
820121186Ssimokawa
821121186Ssimokawa	accb = ccb->cab.abort_ccb;
822121186Ssimokawa
823121186Ssimokawa	if (accb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO)
824121186Ssimokawa		list = &lstate->accept_tios;
825237825Sken	else if (accb->ccb_h.func_code == XPT_IMMEDIATE_NOTIFY)
826121186Ssimokawa		list = &lstate->immed_notifies;
827121186Ssimokawa	else
828121186Ssimokawa		return (CAM_UA_ABORT);
829121186Ssimokawa
830121186Ssimokawa	curelm = SLIST_FIRST(list);
831121186Ssimokawa	found = 0;
832121186Ssimokawa	if (curelm == &accb->ccb_h) {
833121186Ssimokawa		found = 1;
834121186Ssimokawa		SLIST_REMOVE_HEAD(list, sim_links.sle);
835121186Ssimokawa	} else {
836121186Ssimokawa		while(curelm != NULL) {
837121186Ssimokawa			struct ccb_hdr *nextelm;
838121186Ssimokawa
839121186Ssimokawa			nextelm = SLIST_NEXT(curelm, sim_links.sle);
840121186Ssimokawa			if (nextelm == &accb->ccb_h) {
841121186Ssimokawa				found = 1;
842121186Ssimokawa				SLIST_NEXT(curelm, sim_links.sle) =
843121186Ssimokawa				    SLIST_NEXT(nextelm, sim_links.sle);
844121186Ssimokawa				break;
845121186Ssimokawa			}
846121186Ssimokawa			curelm = nextelm;
847121186Ssimokawa		}
848121186Ssimokawa	}
849121186Ssimokawa	if (found) {
850121186Ssimokawa		accb->ccb_h.status = CAM_REQ_ABORTED;
851121186Ssimokawa		xpt_done(accb);
852121186Ssimokawa		return (CAM_REQ_CMP);
853121186Ssimokawa	}
854127468Ssimokawa	printf("%s: not found\n", __func__);
855121186Ssimokawa	return (CAM_PATH_INVALID);
856121186Ssimokawa}
857121186Ssimokawa
858121186Ssimokawastatic void
859121186Ssimokawasbp_targ_xfer_buf(struct orb_info *orbi, u_int offset,
860129585Sdfr    uint16_t dst_hi, uint32_t dst_lo, u_int size,
861121186Ssimokawa    void (*hand)(struct fw_xfer *))
862121186Ssimokawa{
863121186Ssimokawa	struct fw_xfer *xfer;
864121186Ssimokawa	u_int len, ccb_dir, off = 0;
865121186Ssimokawa	char *ptr;
866121186Ssimokawa
867123430Ssimokawa	if (debug > 1)
868127468Ssimokawa		printf("%s: offset=%d size=%d\n", __func__, offset, size);
869121186Ssimokawa	ccb_dir = orbi->ccb->ccb_h.flags & CAM_DIR_MASK;
870121186Ssimokawa	ptr = (char *)orbi->ccb->csio.data_ptr + offset;
871121186Ssimokawa
872121186Ssimokawa	while (size > 0) {
873121186Ssimokawa		/* XXX assume dst_lo + off doesn't overflow */
874121186Ssimokawa		len = MIN(size, 2048 /* XXX */);
875121186Ssimokawa		size -= len;
876121186Ssimokawa		orbi->refcount ++;
877121186Ssimokawa		if (ccb_dir == CAM_DIR_OUT)
878121186Ssimokawa			xfer = fwmem_read_block(orbi->fwdev,
879121186Ssimokawa			   (void *)orbi, /*spd*/2,
880121186Ssimokawa			    dst_hi, dst_lo + off, len,
881121186Ssimokawa			    ptr + off, hand);
882121186Ssimokawa		else
883121186Ssimokawa			xfer = fwmem_write_block(orbi->fwdev,
884121186Ssimokawa			   (void *)orbi, /*spd*/2,
885121186Ssimokawa			    dst_hi, dst_lo + off, len,
886121186Ssimokawa			    ptr + off, hand);
887121186Ssimokawa		if (xfer == NULL) {
888127468Ssimokawa			printf("%s: xfer == NULL", __func__);
889121186Ssimokawa			/* XXX what should we do?? */
890121186Ssimokawa			orbi->refcount --;
891121186Ssimokawa		}
892121186Ssimokawa		off += len;
893121186Ssimokawa	}
894121186Ssimokawa}
895121186Ssimokawa
896121186Ssimokawastatic void
897121186Ssimokawasbp_targ_pt_done(struct fw_xfer *xfer)
898121186Ssimokawa{
899121186Ssimokawa	struct orb_info *orbi;
900121186Ssimokawa	union ccb *ccb;
901121186Ssimokawa	u_int i, offset, res, len;
902129585Sdfr	uint32_t t1, t2, *p;
903121186Ssimokawa
904121186Ssimokawa	orbi = (struct orb_info *)xfer->sc;
905121186Ssimokawa	ccb = orbi->ccb;
906121186Ssimokawa	if (orbi->state == ORBI_STATUS_ABORTED) {
907121186Ssimokawa		if (debug)
908127468Ssimokawa			printf("%s: orbi aborted\n", __func__);
909123430Ssimokawa		sbp_targ_remove_orb_info(orbi->login, orbi);
910121186Ssimokawa		free(orbi->page_table, M_SBP_TARG);
911121186Ssimokawa		free(orbi, M_SBP_TARG);
912121186Ssimokawa		fw_xfer_free(xfer);
913121186Ssimokawa		return;
914121186Ssimokawa	}
915121186Ssimokawa	if (xfer->resp != 0) {
916127468Ssimokawa		printf("%s: xfer->resp = %d\n", __func__, xfer->resp);
917121186Ssimokawa		orbi->status.resp = SBP_TRANS_FAIL;
918124877Ssimokawa		orbi->status.status = OBJ_PT | SBE_TIMEOUT/*XXX*/;
919121186Ssimokawa		orbi->status.dead = 1;
920121186Ssimokawa		orbi->status.len = 1;
921170374Ssimokawa		sbp_targ_abort(orbi->sc, STAILQ_NEXT(orbi, link));
922121186Ssimokawa
923121186Ssimokawa		sbp_targ_status_FIFO(orbi,
924123430Ssimokawa		    orbi->login->fifo_hi, orbi->login->fifo_lo, /*dequeue*/1);
925121186Ssimokawa		free(orbi->page_table, M_SBP_TARG);
926121186Ssimokawa		fw_xfer_free(xfer);
927121186Ssimokawa		return;
928121186Ssimokawa	}
929121186Ssimokawa	res = ccb->csio.dxfer_len;
930121186Ssimokawa	offset = 0;
931121186Ssimokawa	if (debug)
932127468Ssimokawa		printf("%s: dxfer_len=%d\n", __func__, res);
933121186Ssimokawa	orbi->refcount ++;
934121186Ssimokawa	for (p = orbi->page_table, i = orbi->orb4.data_size; i > 0; i --) {
935121186Ssimokawa		t1 = ntohl(*p++);
936121186Ssimokawa		t2 = ntohl(*p++);
937123430Ssimokawa		if (debug > 1)
938121186Ssimokawa			printf("page_table: %04x:%08x %d\n",
939121186Ssimokawa			    t1 & 0xffff, t2, t1>>16);
940121186Ssimokawa		len = MIN(t1 >> 16, res);
941121186Ssimokawa		res -= len;
942121186Ssimokawa		sbp_targ_xfer_buf(orbi, offset, t1 & 0xffff, t2, len,
943121186Ssimokawa		    sbp_targ_cam_done);
944121186Ssimokawa		offset += len;
945121186Ssimokawa		if (res == 0)
946121186Ssimokawa			break;
947121186Ssimokawa	}
948121186Ssimokawa	orbi->refcount --;
949121186Ssimokawa	if (orbi->refcount == 0)
950127468Ssimokawa		printf("%s: refcount == 0\n", __func__);
951121186Ssimokawa	if (res !=0)
952121186Ssimokawa		/* XXX handle res != 0 case */
953127468Ssimokawa		printf("%s: page table is too small(%d)\n", __func__, res);
954121186Ssimokawa
955121186Ssimokawa	fw_xfer_free(xfer);
956121186Ssimokawa	return;
957121186Ssimokawa}
958121186Ssimokawa
959121186Ssimokawastatic void
960121186Ssimokawasbp_targ_fetch_pt(struct orb_info *orbi)
961121186Ssimokawa{
962121186Ssimokawa	struct fw_xfer *xfer;
963121186Ssimokawa
964121186Ssimokawa	if (debug)
965121186Ssimokawa		printf("%s: page_table_size=%d\n",
966127468Ssimokawa		    __func__, orbi->orb4.data_size);
967121186Ssimokawa	orbi->page_table = malloc(orbi->orb4.data_size*8, M_SBP_TARG, M_NOWAIT);
968121186Ssimokawa	if (orbi->page_table == NULL)
969121186Ssimokawa		goto error;
970121186Ssimokawa	xfer = fwmem_read_block(orbi->fwdev, (void *)orbi, /*spd*/2,
971121186Ssimokawa		    orbi->data_hi, orbi->data_lo, orbi->orb4.data_size*8,
972121186Ssimokawa			    (void *)orbi->page_table, sbp_targ_pt_done);
973121186Ssimokawa	if (xfer != NULL)
974121186Ssimokawa		return;
975121186Ssimokawaerror:
976121186Ssimokawa	orbi->ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
977121186Ssimokawa	xpt_done(orbi->ccb);
978121186Ssimokawa	return;
979121186Ssimokawa}
980121186Ssimokawa
981121186Ssimokawastatic void
982121186Ssimokawasbp_targ_action1(struct cam_sim *sim, union ccb *ccb)
983121186Ssimokawa{
984121186Ssimokawa	struct sbp_targ_softc *sc;
985121186Ssimokawa	struct sbp_targ_lstate *lstate;
986121186Ssimokawa	cam_status status;
987121186Ssimokawa	u_int ccb_dir;
988121186Ssimokawa
989121186Ssimokawa	sc =  (struct sbp_targ_softc *)cam_sim_softc(sim);
990121186Ssimokawa
991121186Ssimokawa	status = sbp_targ_find_devs(sc, ccb, &lstate, TRUE);
992121186Ssimokawa
993121186Ssimokawa	switch (ccb->ccb_h.func_code) {
994121186Ssimokawa	case XPT_CONT_TARGET_IO:
995121186Ssimokawa	{
996121186Ssimokawa		struct orb_info *orbi;
997121186Ssimokawa
998121186Ssimokawa		if (debug)
999170374Ssimokawa			printf("%s: XPT_CONT_TARGET_IO (0x%08x)\n",
1000170374Ssimokawa					 __func__, ccb->csio.tag_id);
1001121186Ssimokawa
1002121186Ssimokawa		if (status != CAM_REQ_CMP) {
1003121186Ssimokawa			ccb->ccb_h.status = status;
1004121186Ssimokawa			xpt_done(ccb);
1005121186Ssimokawa			break;
1006121186Ssimokawa		}
1007121186Ssimokawa		/* XXX transfer from/to initiator */
1008121186Ssimokawa		orbi = sbp_targ_get_orb_info(lstate,
1009121186Ssimokawa		    ccb->csio.tag_id, ccb->csio.init_id);
1010121186Ssimokawa		if (orbi == NULL) {
1011121186Ssimokawa			ccb->ccb_h.status = CAM_REQ_ABORTED; /* XXX */
1012121186Ssimokawa			xpt_done(ccb);
1013121186Ssimokawa			break;
1014121186Ssimokawa		}
1015121186Ssimokawa		if (orbi->state == ORBI_STATUS_ABORTED) {
1016121186Ssimokawa			if (debug)
1017127468Ssimokawa				printf("%s: ctio aborted\n", __func__);
1018170374Ssimokawa			sbp_targ_remove_orb_info_locked(orbi->login, orbi);
1019121186Ssimokawa			free(orbi, M_SBP_TARG);
1020170374Ssimokawa			ccb->ccb_h.status = CAM_REQ_ABORTED;
1021170374Ssimokawa			xpt_done(ccb);
1022121186Ssimokawa			break;
1023121186Ssimokawa		}
1024121186Ssimokawa		orbi->state = ORBI_STATUS_CTIO;
1025121186Ssimokawa
1026121186Ssimokawa		orbi->ccb = ccb;
1027121186Ssimokawa		ccb_dir = ccb->ccb_h.flags & CAM_DIR_MASK;
1028121186Ssimokawa
1029121186Ssimokawa		/* XXX */
1030121186Ssimokawa		if (ccb->csio.dxfer_len == 0)
1031121186Ssimokawa			ccb_dir = CAM_DIR_NONE;
1032121186Ssimokawa
1033121186Ssimokawa		/* Sanity check */
1034121186Ssimokawa		if (ccb_dir == CAM_DIR_IN && orbi->orb4.dir == 0)
1035127468Ssimokawa			printf("%s: direction mismatch\n", __func__);
1036121186Ssimokawa
1037121186Ssimokawa		/* check page table */
1038121186Ssimokawa		if (ccb_dir != CAM_DIR_NONE && orbi->orb4.page_table_present) {
1039121186Ssimokawa			if (debug)
1040121186Ssimokawa				printf("%s: page_table_present\n",
1041127468Ssimokawa				    __func__);
1042121186Ssimokawa			if (orbi->orb4.page_size != 0) {
1043121186Ssimokawa				printf("%s: unsupported pagesize %d != 0\n",
1044127468Ssimokawa			 	    __func__, orbi->orb4.page_size);
1045121186Ssimokawa				ccb->ccb_h.status = CAM_REQ_INVALID;
1046121186Ssimokawa				xpt_done(ccb);
1047121186Ssimokawa				break;
1048121186Ssimokawa			}
1049121186Ssimokawa			sbp_targ_fetch_pt(orbi);
1050121186Ssimokawa			break;
1051121186Ssimokawa		}
1052121186Ssimokawa
1053121186Ssimokawa		/* Sanity check */
1054121186Ssimokawa		if (ccb_dir != CAM_DIR_NONE &&
1055121186Ssimokawa		    orbi->orb4.data_size != ccb->csio.dxfer_len)
1056121186Ssimokawa			printf("%s: data_size(%d) != dxfer_len(%d)\n",
1057127468Ssimokawa			    __func__, orbi->orb4.data_size,
1058121186Ssimokawa			    ccb->csio.dxfer_len);
1059121186Ssimokawa
1060121186Ssimokawa		if (ccb_dir != CAM_DIR_NONE)
1061121186Ssimokawa			sbp_targ_xfer_buf(orbi, 0, orbi->data_hi,
1062121186Ssimokawa			    orbi->data_lo,
1063121186Ssimokawa			    MIN(orbi->orb4.data_size, ccb->csio.dxfer_len),
1064121186Ssimokawa			    sbp_targ_cam_done);
1065121186Ssimokawa
1066121186Ssimokawa		if (ccb_dir == CAM_DIR_NONE) {
1067170374Ssimokawa			if ((ccb->ccb_h.flags & CAM_SEND_STATUS) != 0) {
1068170374Ssimokawa				/* XXX */
1069170374Ssimokawa				SBP_UNLOCK(sc);
1070121186Ssimokawa				sbp_targ_send_status(orbi, ccb);
1071170374Ssimokawa				SBP_LOCK(sc);
1072170374Ssimokawa			}
1073121186Ssimokawa			ccb->ccb_h.status = CAM_REQ_CMP;
1074121186Ssimokawa			xpt_done(ccb);
1075121186Ssimokawa		}
1076121186Ssimokawa		break;
1077121186Ssimokawa	}
1078121186Ssimokawa	case XPT_ACCEPT_TARGET_IO:	/* Add Accept Target IO Resource */
1079121186Ssimokawa		if (status != CAM_REQ_CMP) {
1080121186Ssimokawa			ccb->ccb_h.status = status;
1081121186Ssimokawa			xpt_done(ccb);
1082121186Ssimokawa			break;
1083121186Ssimokawa		}
1084121186Ssimokawa		SLIST_INSERT_HEAD(&lstate->accept_tios, &ccb->ccb_h,
1085121186Ssimokawa		    sim_links.sle);
1086121186Ssimokawa		ccb->ccb_h.status = CAM_REQ_INPROG;
1087123430Ssimokawa		if ((lstate->flags & F_ATIO_STARVED) != 0) {
1088123430Ssimokawa			struct sbp_targ_login *login;
1089123430Ssimokawa
1090121186Ssimokawa			if (debug)
1091127468Ssimokawa				printf("%s: new atio arrived\n", __func__);
1092123430Ssimokawa			lstate->flags &= ~F_ATIO_STARVED;
1093123430Ssimokawa			STAILQ_FOREACH(login, &lstate->logins, link)
1094123430Ssimokawa				if ((login->flags & F_ATIO_STARVED) != 0) {
1095123430Ssimokawa					login->flags &= ~F_ATIO_STARVED;
1096123430Ssimokawa					sbp_targ_fetch_orb(lstate->sc,
1097123430Ssimokawa					    login->fwdev,
1098123430Ssimokawa					    login->last_hi, login->last_lo,
1099123430Ssimokawa					    login, FETCH_CMD);
1100123430Ssimokawa				}
1101121186Ssimokawa		}
1102121186Ssimokawa		break;
1103237825Sken	case XPT_NOTIFY_ACKNOWLEDGE:	/* recycle notify ack */
1104237825Sken	case XPT_IMMEDIATE_NOTIFY:	/* Add Immediate Notify Resource */
1105121186Ssimokawa		if (status != CAM_REQ_CMP) {
1106121186Ssimokawa			ccb->ccb_h.status = status;
1107121186Ssimokawa			xpt_done(ccb);
1108121186Ssimokawa			break;
1109121186Ssimokawa		}
1110121186Ssimokawa		SLIST_INSERT_HEAD(&lstate->immed_notifies, &ccb->ccb_h,
1111121186Ssimokawa		    sim_links.sle);
1112121186Ssimokawa		ccb->ccb_h.status = CAM_REQ_INPROG;
1113121186Ssimokawa		sbp_targ_send_lstate_events(sc, lstate);
1114121186Ssimokawa		break;
1115121186Ssimokawa	case XPT_EN_LUN:
1116121186Ssimokawa		sbp_targ_en_lun(sc, ccb);
1117121186Ssimokawa		xpt_done(ccb);
1118121186Ssimokawa		break;
1119121186Ssimokawa	case XPT_PATH_INQ:
1120121186Ssimokawa	{
1121121186Ssimokawa		struct ccb_pathinq *cpi = &ccb->cpi;
1122121186Ssimokawa
1123121186Ssimokawa		cpi->version_num = 1; /* XXX??? */
1124121186Ssimokawa		cpi->hba_inquiry = PI_TAG_ABLE;
1125121186Ssimokawa		cpi->target_sprt = PIT_PROCESSOR
1126121186Ssimokawa				 | PIT_DISCONNECT
1127121186Ssimokawa				 | PIT_TERM_IO;
1128121186Ssimokawa		cpi->hba_misc = PIM_NOBUSRESET | PIM_NO_6_BYTE;
1129121186Ssimokawa		cpi->hba_eng_cnt = 0;
1130121186Ssimokawa		cpi->max_target = 7; /* XXX */
1131121186Ssimokawa		cpi->max_lun = MAX_LUN - 1;
1132121186Ssimokawa		cpi->initiator_id = 7; /* XXX */
1133121186Ssimokawa		cpi->bus_id = sim->bus_id;
1134121186Ssimokawa		cpi->base_transfer_speed = 400 * 1000 / 8;
1135121186Ssimokawa		strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
1136121186Ssimokawa		strncpy(cpi->hba_vid, "SBP_TARG", HBA_IDLEN);
1137121186Ssimokawa		strncpy(cpi->dev_name, sim->sim_name, DEV_IDLEN);
1138121186Ssimokawa		cpi->unit_number = sim->unit_number;
1139121186Ssimokawa
1140121186Ssimokawa		cpi->ccb_h.status = CAM_REQ_CMP;
1141121186Ssimokawa		xpt_done(ccb);
1142121186Ssimokawa		break;
1143121186Ssimokawa	}
1144121186Ssimokawa	case XPT_ABORT:
1145121186Ssimokawa	{
1146121186Ssimokawa		union ccb *accb = ccb->cab.abort_ccb;
1147121186Ssimokawa
1148121186Ssimokawa		switch (accb->ccb_h.func_code) {
1149121186Ssimokawa		case XPT_ACCEPT_TARGET_IO:
1150237825Sken		case XPT_IMMEDIATE_NOTIFY:
1151121186Ssimokawa			ccb->ccb_h.status = sbp_targ_abort_ccb(sc, ccb);
1152121186Ssimokawa			break;
1153121186Ssimokawa		case XPT_CONT_TARGET_IO:
1154121186Ssimokawa			/* XXX */
1155121186Ssimokawa			ccb->ccb_h.status = CAM_UA_ABORT;
1156121186Ssimokawa			break;
1157121186Ssimokawa		default:
1158121186Ssimokawa			printf("%s: aborting unknown function %d\n",
1159127468Ssimokawa				__func__, accb->ccb_h.func_code);
1160121186Ssimokawa			ccb->ccb_h.status = CAM_REQ_INVALID;
1161121186Ssimokawa			break;
1162121186Ssimokawa		}
1163121186Ssimokawa		xpt_done(ccb);
1164121186Ssimokawa		break;
1165121186Ssimokawa	}
1166121186Ssimokawa	default:
1167121186Ssimokawa		printf("%s: unknown function %d\n",
1168127468Ssimokawa		    __func__, ccb->ccb_h.func_code);
1169121186Ssimokawa		ccb->ccb_h.status = CAM_REQ_INVALID;
1170121186Ssimokawa		xpt_done(ccb);
1171121186Ssimokawa		break;
1172121186Ssimokawa	}
1173121186Ssimokawa	return;
1174121186Ssimokawa}
1175121186Ssimokawa
1176121186Ssimokawastatic void
1177121186Ssimokawasbp_targ_action(struct cam_sim *sim, union ccb *ccb)
1178121186Ssimokawa{
1179121186Ssimokawa	int s;
1180121186Ssimokawa
1181121186Ssimokawa	s = splfw();
1182121186Ssimokawa	sbp_targ_action1(sim, ccb);
1183121186Ssimokawa	splx(s);
1184121186Ssimokawa}
1185121186Ssimokawa
1186121186Ssimokawastatic void
1187121186Ssimokawasbp_targ_poll(struct cam_sim *sim)
1188121186Ssimokawa{
1189121186Ssimokawa	/* XXX */
1190121186Ssimokawa	return;
1191121186Ssimokawa}
1192121186Ssimokawa
1193121186Ssimokawastatic void
1194121186Ssimokawasbp_targ_cmd_handler(struct fw_xfer *xfer)
1195121186Ssimokawa{
1196121186Ssimokawa	struct fw_pkt *fp;
1197129585Sdfr	uint32_t *orb;
1198121186Ssimokawa	struct corb4 *orb4;
1199121186Ssimokawa	struct orb_info *orbi;
1200121186Ssimokawa	struct ccb_accept_tio *atio;
1201121186Ssimokawa	u_char *bytes;
1202121186Ssimokawa	int i;
1203121186Ssimokawa
1204121186Ssimokawa	orbi = (struct orb_info *)xfer->sc;
1205121186Ssimokawa	if (xfer->resp != 0) {
1206127468Ssimokawa		printf("%s: xfer->resp = %d\n", __func__, xfer->resp);
1207121186Ssimokawa		orbi->status.resp = SBP_TRANS_FAIL;
1208124877Ssimokawa		orbi->status.status = OBJ_ORB | SBE_TIMEOUT/*XXX*/;
1209121186Ssimokawa		orbi->status.dead = 1;
1210121186Ssimokawa		orbi->status.len = 1;
1211170374Ssimokawa		sbp_targ_abort(orbi->sc, STAILQ_NEXT(orbi, link));
1212121186Ssimokawa
1213121186Ssimokawa		sbp_targ_status_FIFO(orbi,
1214123430Ssimokawa		    orbi->login->fifo_hi, orbi->login->fifo_lo, /*dequeue*/1);
1215121186Ssimokawa		fw_xfer_free(xfer);
1216121186Ssimokawa		return;
1217121186Ssimokawa	}
1218121186Ssimokawa	fp = &xfer->recv.hdr;
1219121186Ssimokawa
1220170374Ssimokawa	atio = orbi->atio;
1221170374Ssimokawa
1222121186Ssimokawa	if (orbi->state == ORBI_STATUS_ABORTED) {
1223127468Ssimokawa		printf("%s: aborted\n", __func__);
1224123430Ssimokawa		sbp_targ_remove_orb_info(orbi->login, orbi);
1225121186Ssimokawa		free(orbi, M_SBP_TARG);
1226170374Ssimokawa		atio->ccb_h.status = CAM_REQ_ABORTED;
1227170374Ssimokawa		SBP_LOCK(orbi->sc);
1228170374Ssimokawa		xpt_done((union ccb*)atio);
1229170374Ssimokawa		SBP_UNLOCK(orbi->sc);
1230121186Ssimokawa		goto done0;
1231121186Ssimokawa	}
1232121186Ssimokawa	orbi->state = ORBI_STATUS_ATIO;
1233121186Ssimokawa
1234121186Ssimokawa	orb = orbi->orb;
1235121186Ssimokawa	/* swap payload except SCSI command */
1236121186Ssimokawa	for (i = 0; i < 5; i ++)
1237121186Ssimokawa		orb[i] = ntohl(orb[i]);
1238121186Ssimokawa
1239121186Ssimokawa	orb4 = (struct corb4 *)&orb[4];
1240121186Ssimokawa	if (orb4->rq_fmt != 0) {
1241121186Ssimokawa		/* XXX */
1242127468Ssimokawa		printf("%s: rq_fmt(%d) != 0\n", __func__, orb4->rq_fmt);
1243121186Ssimokawa	}
1244121186Ssimokawa
1245121186Ssimokawa	atio->ccb_h.target_id = 0; /* XXX */
1246123430Ssimokawa	atio->ccb_h.target_lun = orbi->login->lstate->lun;
1247121186Ssimokawa	atio->sense_len = 0;
1248121186Ssimokawa	atio->tag_action = 1; /* XXX */
1249121186Ssimokawa	atio->tag_id = orbi->orb_lo;
1250123430Ssimokawa	atio->init_id = orbi->login->id;
1251123430Ssimokawa
1252121186Ssimokawa	atio->ccb_h.flags = CAM_TAG_ACTION_VALID;
1253170374Ssimokawa	bytes = (u_char *)&orb[5];
1254121186Ssimokawa	if (debug)
1255170374Ssimokawa		printf("%s: %p %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
1256170374Ssimokawa		    __func__, (void *)atio,
1257121186Ssimokawa		    bytes[0], bytes[1], bytes[2], bytes[3], bytes[4],
1258121186Ssimokawa		    bytes[5], bytes[6], bytes[7], bytes[8], bytes[9]);
1259121186Ssimokawa	switch (bytes[0] >> 5) {
1260121186Ssimokawa	case 0:
1261121186Ssimokawa		atio->cdb_len = 6;
1262121186Ssimokawa		break;
1263121186Ssimokawa	case 1:
1264121186Ssimokawa	case 2:
1265121186Ssimokawa		atio->cdb_len = 10;
1266121186Ssimokawa		break;
1267121186Ssimokawa	case 4:
1268121186Ssimokawa		atio->cdb_len = 16;
1269121186Ssimokawa		break;
1270121186Ssimokawa	case 5:
1271121186Ssimokawa		atio->cdb_len = 12;
1272121186Ssimokawa		break;
1273121186Ssimokawa	case 3:
1274121186Ssimokawa	default:
1275121186Ssimokawa		/* Only copy the opcode. */
1276121186Ssimokawa		atio->cdb_len = 1;
1277121186Ssimokawa		printf("Reserved or VU command code type encountered\n");
1278121186Ssimokawa		break;
1279121186Ssimokawa	}
1280121186Ssimokawa
1281121186Ssimokawa	memcpy(atio->cdb_io.cdb_bytes, bytes, atio->cdb_len);
1282121186Ssimokawa
1283121186Ssimokawa	atio->ccb_h.status |= CAM_CDB_RECVD;
1284121186Ssimokawa
1285121186Ssimokawa	/* next ORB */
1286121186Ssimokawa	if ((orb[0] & (1<<31)) == 0) {
1287121186Ssimokawa		if (debug)
1288127468Ssimokawa			printf("%s: fetch next orb\n", __func__);
1289121186Ssimokawa		orbi->status.src = SRC_NEXT_EXISTS;
1290121186Ssimokawa		sbp_targ_fetch_orb(orbi->sc, orbi->fwdev,
1291123430Ssimokawa		    orb[0], orb[1], orbi->login, FETCH_CMD);
1292121186Ssimokawa	} else {
1293121186Ssimokawa		orbi->status.src = SRC_NO_NEXT;
1294123430Ssimokawa		orbi->login->flags &= ~F_LINK_ACTIVE;
1295121186Ssimokawa	}
1296121186Ssimokawa
1297121186Ssimokawa	orbi->data_hi = orb[2];
1298121186Ssimokawa	orbi->data_lo = orb[3];
1299121186Ssimokawa	orbi->orb4 = *orb4;
1300121186Ssimokawa
1301170374Ssimokawa	SBP_LOCK(orbi->sc);
1302121186Ssimokawa	xpt_done((union ccb*)atio);
1303170374Ssimokawa	SBP_UNLOCK(orbi->sc);
1304121186Ssimokawadone0:
1305121186Ssimokawa	fw_xfer_free(xfer);
1306121186Ssimokawa	return;
1307121186Ssimokawa}
1308121186Ssimokawa
1309123430Ssimokawastatic struct sbp_targ_login *
1310123430Ssimokawasbp_targ_get_login(struct sbp_targ_softc *sc, struct fw_device *fwdev, int lun)
1311123430Ssimokawa{
1312123430Ssimokawa	struct sbp_targ_lstate *lstate;
1313123430Ssimokawa	struct sbp_targ_login *login;
1314123430Ssimokawa	int i;
1315123430Ssimokawa
1316123430Ssimokawa	lstate = sc->lstate[lun];
1317123430Ssimokawa
1318123430Ssimokawa	STAILQ_FOREACH(login, &lstate->logins, link)
1319123430Ssimokawa		if (login->fwdev == fwdev)
1320123430Ssimokawa			return (login);
1321123430Ssimokawa
1322123430Ssimokawa	for (i = 0; i < MAX_LOGINS; i ++)
1323123430Ssimokawa		if (sc->logins[i] == NULL)
1324123430Ssimokawa			goto found;
1325123430Ssimokawa
1326127468Ssimokawa	printf("%s: increase MAX_LOGIN\n", __func__);
1327123430Ssimokawa	return (NULL);
1328123430Ssimokawa
1329123430Ssimokawafound:
1330123430Ssimokawa	login = (struct sbp_targ_login *)malloc(
1331123430Ssimokawa	    sizeof(struct sbp_targ_login), M_SBP_TARG, M_NOWAIT | M_ZERO);
1332123430Ssimokawa
1333123430Ssimokawa	if (login == NULL) {
1334127468Ssimokawa		printf("%s: malloc failed\n", __func__);
1335123430Ssimokawa		return (NULL);
1336123430Ssimokawa	}
1337123430Ssimokawa
1338169475Ssimokawa	login->id = i;
1339123430Ssimokawa	login->fwdev = fwdev;
1340123430Ssimokawa	login->lstate = lstate;
1341123430Ssimokawa	login->last_hi = 0xffff;
1342123430Ssimokawa	login->last_lo = 0xffffffff;
1343123430Ssimokawa	login->hold_sec = 1;
1344123430Ssimokawa	STAILQ_INIT(&login->orbs);
1345123430Ssimokawa	CALLOUT_INIT(&login->hold_callout);
1346123430Ssimokawa	sc->logins[i] = login;
1347123430Ssimokawa	return (login);
1348123430Ssimokawa}
1349123430Ssimokawa
1350121186Ssimokawastatic void
1351121186Ssimokawasbp_targ_mgm_handler(struct fw_xfer *xfer)
1352121186Ssimokawa{
1353121186Ssimokawa	struct sbp_targ_lstate *lstate;
1354123430Ssimokawa	struct sbp_targ_login *login;
1355121186Ssimokawa	struct fw_pkt *fp;
1356129585Sdfr	uint32_t *orb;
1357121186Ssimokawa	struct morb4 *orb4;
1358121186Ssimokawa	struct orb_info *orbi;
1359121186Ssimokawa	int i;
1360121186Ssimokawa
1361121186Ssimokawa	orbi = (struct orb_info *)xfer->sc;
1362121186Ssimokawa	if (xfer->resp != 0) {
1363127468Ssimokawa		printf("%s: xfer->resp = %d\n", __func__, xfer->resp);
1364121186Ssimokawa		orbi->status.resp = SBP_TRANS_FAIL;
1365124877Ssimokawa		orbi->status.status = OBJ_ORB | SBE_TIMEOUT/*XXX*/;
1366121186Ssimokawa		orbi->status.dead = 1;
1367121186Ssimokawa		orbi->status.len = 1;
1368170374Ssimokawa		sbp_targ_abort(orbi->sc, STAILQ_NEXT(orbi, link));
1369121186Ssimokawa
1370121186Ssimokawa		sbp_targ_status_FIFO(orbi,
1371123430Ssimokawa		    orbi->login->fifo_hi, orbi->login->fifo_lo, /*dequeue*/0);
1372121186Ssimokawa		fw_xfer_free(xfer);
1373121186Ssimokawa		return;
1374121186Ssimokawa	}
1375121186Ssimokawa	fp = &xfer->recv.hdr;
1376121186Ssimokawa
1377121186Ssimokawa	orb = orbi->orb;
1378121186Ssimokawa	/* swap payload */
1379121186Ssimokawa	for (i = 0; i < 8; i ++) {
1380121186Ssimokawa		orb[i] = ntohl(orb[i]);
1381121186Ssimokawa	}
1382121186Ssimokawa	orb4 = (struct morb4 *)&orb[4];
1383121186Ssimokawa	if (debug)
1384127468Ssimokawa		printf("%s: %s\n", __func__, orb_fun_name[orb4->fun]);
1385121186Ssimokawa
1386121186Ssimokawa	orbi->status.src = SRC_NO_NEXT;
1387121186Ssimokawa
1388121186Ssimokawa	switch (orb4->fun << 16) {
1389121186Ssimokawa	case ORB_FUN_LGI:
1390121186Ssimokawa	{
1391123430Ssimokawa		int exclusive = 0, lun;
1392121186Ssimokawa
1393123430Ssimokawa		if (orb[4] & ORB_EXV)
1394123430Ssimokawa			exclusive = 1;
1395123430Ssimokawa
1396123430Ssimokawa		lun = orb4->id;
1397123430Ssimokawa		lstate = orbi->sc->lstate[lun];
1398123430Ssimokawa
1399123430Ssimokawa		if (lun >= MAX_LUN || lstate == NULL ||
1400123430Ssimokawa		    (exclusive &&
1401123430Ssimokawa		    STAILQ_FIRST(&lstate->logins) != NULL &&
1402123430Ssimokawa		    STAILQ_FIRST(&lstate->logins)->fwdev != orbi->fwdev)
1403123430Ssimokawa		    ) {
1404121186Ssimokawa			/* error */
1405121186Ssimokawa			orbi->status.dead = 1;
1406121186Ssimokawa			orbi->status.status = STATUS_ACCESS_DENY;
1407121186Ssimokawa			orbi->status.len = 1;
1408121186Ssimokawa			break;
1409121186Ssimokawa		}
1410123430Ssimokawa
1411123430Ssimokawa		/* allocate login */
1412123430Ssimokawa		login = sbp_targ_get_login(orbi->sc, orbi->fwdev, lun);
1413123430Ssimokawa		if (login == NULL) {
1414123430Ssimokawa			printf("%s: sbp_targ_get_login failed\n",
1415127468Ssimokawa			    __func__);
1416123430Ssimokawa			orbi->status.dead = 1;
1417123430Ssimokawa			orbi->status.status = STATUS_RES_UNAVAIL;
1418123430Ssimokawa			orbi->status.len = 1;
1419123430Ssimokawa			break;
1420123430Ssimokawa		}
1421170374Ssimokawa		printf("%s: login id=%d\n", __func__, login->id);
1422123430Ssimokawa
1423123430Ssimokawa		login->fifo_hi = orb[6];
1424123430Ssimokawa		login->fifo_lo = orb[7];
1425129585Sdfr		login->loginres.len = htons(sizeof(uint32_t) * 4);
1426123430Ssimokawa		login->loginres.id = htons(login->id);
1427123430Ssimokawa		login->loginres.cmd_hi = htons(SBP_TARG_BIND_HI);
1428123430Ssimokawa		login->loginres.cmd_lo = htonl(SBP_TARG_BIND_LO(login->id));
1429123430Ssimokawa		login->loginres.recon_hold = htons(login->hold_sec);
1430123430Ssimokawa
1431170374Ssimokawa		STAILQ_INSERT_TAIL(&lstate->logins, login, link);
1432121186Ssimokawa		fwmem_write_block(orbi->fwdev, NULL, /*spd*/2, orb[2], orb[3],
1433123430Ssimokawa		    sizeof(struct sbp_login_res), (void *)&login->loginres,
1434121186Ssimokawa		    fw_asy_callback_free);
1435123514Ssimokawa		/* XXX return status after loginres is successfully written */
1436121186Ssimokawa		break;
1437121186Ssimokawa	}
1438121186Ssimokawa	case ORB_FUN_RCN:
1439123430Ssimokawa		login = orbi->sc->logins[orb4->id];
1440123430Ssimokawa		if (login != NULL && login->fwdev == orbi->fwdev) {
1441123430Ssimokawa			login->flags &= ~F_HOLD;
1442123430Ssimokawa			callout_stop(&login->hold_callout);
1443123430Ssimokawa			printf("%s: reconnected id=%d\n",
1444127468Ssimokawa			    __func__, login->id);
1445123430Ssimokawa		} else {
1446123430Ssimokawa			orbi->status.dead = 1;
1447123430Ssimokawa			orbi->status.status = STATUS_ACCESS_DENY;
1448123430Ssimokawa			printf("%s: reconnection faild id=%d\n",
1449127468Ssimokawa			    __func__, orb4->id);
1450123430Ssimokawa		}
1451121186Ssimokawa		break;
1452123430Ssimokawa	case ORB_FUN_LGO:
1453123430Ssimokawa		login = orbi->sc->logins[orb4->id];
1454123430Ssimokawa		if (login->fwdev != orbi->fwdev) {
1455127468Ssimokawa			printf("%s: wrong initiator\n", __func__);
1456123430Ssimokawa			break;
1457123430Ssimokawa		}
1458123430Ssimokawa		sbp_targ_dealloc_login(login);
1459123430Ssimokawa		break;
1460121186Ssimokawa	default:
1461121186Ssimokawa		printf("%s: %s not implemented yet\n",
1462127468Ssimokawa		    __func__, orb_fun_name[orb4->fun]);
1463121186Ssimokawa		break;
1464121186Ssimokawa	}
1465121186Ssimokawa	orbi->status.len = 1;
1466121186Ssimokawa	sbp_targ_status_FIFO(orbi, orb[6], orb[7], /*dequeue*/0);
1467121186Ssimokawa	fw_xfer_free(xfer);
1468121186Ssimokawa	return;
1469121186Ssimokawa}
1470121186Ssimokawa
1471121186Ssimokawastatic void
1472121186Ssimokawasbp_targ_pointer_handler(struct fw_xfer *xfer)
1473121186Ssimokawa{
1474121186Ssimokawa	struct orb_info *orbi;
1475129585Sdfr	uint32_t orb0, orb1;
1476121186Ssimokawa
1477121186Ssimokawa	orbi = (struct orb_info *)xfer->sc;
1478121186Ssimokawa	if (xfer->resp != 0) {
1479127468Ssimokawa		printf("%s: xfer->resp = %d\n", __func__, xfer->resp);
1480121186Ssimokawa		goto done;
1481121186Ssimokawa	}
1482121186Ssimokawa
1483121186Ssimokawa	orb0 = ntohl(orbi->orb[0]);
1484121186Ssimokawa	orb1 = ntohl(orbi->orb[1]);
1485121186Ssimokawa	if ((orb0 & (1 << 31)) != 0) {
1486127468Ssimokawa		printf("%s: invalid pointer\n", __func__);
1487121186Ssimokawa		goto done;
1488121186Ssimokawa	}
1489123430Ssimokawa	sbp_targ_fetch_orb(orbi->login->lstate->sc, orbi->fwdev,
1490129585Sdfr	    (uint16_t)orb0, orb1, orbi->login, FETCH_CMD);
1491121186Ssimokawadone:
1492121186Ssimokawa	free(orbi, M_SBP_TARG);
1493121186Ssimokawa	fw_xfer_free(xfer);
1494121186Ssimokawa	return;
1495121186Ssimokawa}
1496121186Ssimokawa
1497121186Ssimokawastatic void
1498121186Ssimokawasbp_targ_fetch_orb(struct sbp_targ_softc *sc, struct fw_device *fwdev,
1499129585Sdfr    uint16_t orb_hi, uint32_t orb_lo, struct sbp_targ_login *login,
1500121186Ssimokawa    int mode)
1501121186Ssimokawa{
1502121186Ssimokawa	struct orb_info *orbi;
1503121186Ssimokawa
1504121186Ssimokawa	if (debug)
1505127468Ssimokawa		printf("%s: fetch orb %04x:%08x\n", __func__, orb_hi, orb_lo);
1506121186Ssimokawa	orbi = malloc(sizeof(struct orb_info), M_SBP_TARG, M_NOWAIT | M_ZERO);
1507121186Ssimokawa	if (orbi == NULL) {
1508127468Ssimokawa		printf("%s: malloc failed\n", __func__);
1509121186Ssimokawa		return;
1510121186Ssimokawa	}
1511121186Ssimokawa	orbi->sc = sc;
1512121186Ssimokawa	orbi->fwdev = fwdev;
1513123430Ssimokawa	orbi->login = login;
1514121186Ssimokawa	orbi->orb_hi = orb_hi;
1515121186Ssimokawa	orbi->orb_lo = orb_lo;
1516121186Ssimokawa	orbi->status.orb_hi = htons(orb_hi);
1517121186Ssimokawa	orbi->status.orb_lo = htonl(orb_lo);
1518121186Ssimokawa
1519121186Ssimokawa	switch (mode) {
1520121186Ssimokawa	case FETCH_MGM:
1521121186Ssimokawa		fwmem_read_block(fwdev, (void *)orbi, /*spd*/2, orb_hi, orb_lo,
1522129585Sdfr		    sizeof(uint32_t) * 8, &orbi->orb[0],
1523121186Ssimokawa		    sbp_targ_mgm_handler);
1524121186Ssimokawa		break;
1525121186Ssimokawa	case FETCH_CMD:
1526121186Ssimokawa		orbi->state = ORBI_STATUS_FETCH;
1527123430Ssimokawa		login->last_hi = orb_hi;
1528123430Ssimokawa		login->last_lo = orb_lo;
1529123430Ssimokawa		login->flags |= F_LINK_ACTIVE;
1530121186Ssimokawa		/* dequeue */
1531170374Ssimokawa		SBP_LOCK(sc);
1532121186Ssimokawa		orbi->atio = (struct ccb_accept_tio *)
1533123430Ssimokawa		    SLIST_FIRST(&login->lstate->accept_tios);
1534121186Ssimokawa		if (orbi->atio == NULL) {
1535170374Ssimokawa			SBP_UNLOCK(sc);
1536127468Ssimokawa			printf("%s: no free atio\n", __func__);
1537123430Ssimokawa			login->lstate->flags |= F_ATIO_STARVED;
1538123430Ssimokawa			login->flags |= F_ATIO_STARVED;
1539123430Ssimokawa#if 0
1540123430Ssimokawa			/* XXX ?? */
1541123430Ssimokawa			login->fwdev = fwdev;
1542123430Ssimokawa#endif
1543121186Ssimokawa			break;
1544121186Ssimokawa		}
1545123430Ssimokawa		SLIST_REMOVE_HEAD(&login->lstate->accept_tios, sim_links.sle);
1546170374Ssimokawa		STAILQ_INSERT_TAIL(&login->orbs, orbi, link);
1547170374Ssimokawa		SBP_UNLOCK(sc);
1548121186Ssimokawa		fwmem_read_block(fwdev, (void *)orbi, /*spd*/2, orb_hi, orb_lo,
1549129585Sdfr		    sizeof(uint32_t) * 8, &orbi->orb[0],
1550121186Ssimokawa		    sbp_targ_cmd_handler);
1551121186Ssimokawa		break;
1552121186Ssimokawa	case FETCH_POINTER:
1553121186Ssimokawa		orbi->state = ORBI_STATUS_POINTER;
1554123430Ssimokawa		login->flags |= F_LINK_ACTIVE;
1555121186Ssimokawa		fwmem_read_block(fwdev, (void *)orbi, /*spd*/2, orb_hi, orb_lo,
1556129585Sdfr		    sizeof(uint32_t) * 2, &orbi->orb[0],
1557121186Ssimokawa		    sbp_targ_pointer_handler);
1558121186Ssimokawa		break;
1559121186Ssimokawa	default:
1560127468Ssimokawa		printf("%s: invalid mode %d\n", __func__, mode);
1561121186Ssimokawa	}
1562121186Ssimokawa}
1563121186Ssimokawa
1564121186Ssimokawastatic void
1565121186Ssimokawasbp_targ_resp_callback(struct fw_xfer *xfer)
1566121186Ssimokawa{
1567121186Ssimokawa	struct sbp_targ_softc *sc;
1568121186Ssimokawa	int s;
1569121186Ssimokawa
1570121186Ssimokawa	if (debug)
1571127468Ssimokawa		printf("%s: xfer=%p\n", __func__, xfer);
1572121186Ssimokawa	sc = (struct sbp_targ_softc *)xfer->sc;
1573121186Ssimokawa	fw_xfer_unload(xfer);
1574121186Ssimokawa	xfer->recv.pay_len = SBP_TARG_RECV_LEN;
1575167632Ssimokawa	xfer->hand = sbp_targ_recv;
1576121186Ssimokawa	s = splfw();
1577121186Ssimokawa	STAILQ_INSERT_TAIL(&sc->fwb.xferlist, xfer, link);
1578121186Ssimokawa	splx(s);
1579121186Ssimokawa}
1580121186Ssimokawa
1581121186Ssimokawastatic int
1582123430Ssimokawasbp_targ_cmd(struct fw_xfer *xfer, struct fw_device *fwdev, int login_id,
1583123430Ssimokawa    int reg)
1584121186Ssimokawa{
1585123430Ssimokawa	struct sbp_targ_login *login;
1586121186Ssimokawa	struct sbp_targ_softc *sc;
1587121186Ssimokawa	int rtcode = 0;
1588121186Ssimokawa
1589123430Ssimokawa	if (login_id < 0 || login_id >= MAX_LOGINS)
1590121186Ssimokawa		return(RESP_ADDRESS_ERROR);
1591121186Ssimokawa
1592121186Ssimokawa	sc = (struct sbp_targ_softc *)xfer->sc;
1593123430Ssimokawa	login = sc->logins[login_id];
1594123430Ssimokawa	if (login == NULL)
1595121186Ssimokawa		return(RESP_ADDRESS_ERROR);
1596121186Ssimokawa
1597123430Ssimokawa	if (login->fwdev != fwdev) {
1598123430Ssimokawa		/* XXX */
1599123430Ssimokawa		return(RESP_ADDRESS_ERROR);
1600123430Ssimokawa	}
1601123430Ssimokawa
1602121186Ssimokawa	switch (reg) {
1603121186Ssimokawa	case 0x08:	/* ORB_POINTER */
1604121186Ssimokawa		if (debug)
1605170374Ssimokawa			printf("%s: ORB_POINTER(%d)\n", __func__, login_id);
1606123430Ssimokawa		if ((login->flags & F_LINK_ACTIVE) != 0) {
1607123430Ssimokawa			if (debug)
1608123430Ssimokawa				printf("link active (ORB_POINTER)\n");
1609123430Ssimokawa			break;
1610123430Ssimokawa		}
1611123430Ssimokawa		sbp_targ_fetch_orb(sc, fwdev,
1612121186Ssimokawa		    ntohl(xfer->recv.payload[0]),
1613121186Ssimokawa		    ntohl(xfer->recv.payload[1]),
1614123430Ssimokawa		    login, FETCH_CMD);
1615121186Ssimokawa		break;
1616121186Ssimokawa	case 0x04:	/* AGENT_RESET */
1617121186Ssimokawa		if (debug)
1618170374Ssimokawa			printf("%s: AGENT RESET(%d)\n", __func__, login_id);
1619123430Ssimokawa		login->last_hi = 0xffff;
1620123430Ssimokawa		login->last_lo = 0xffffffff;
1621170374Ssimokawa		sbp_targ_abort(sc, STAILQ_FIRST(&login->orbs));
1622121186Ssimokawa		break;
1623121186Ssimokawa	case 0x10:	/* DOORBELL */
1624121186Ssimokawa		if (debug)
1625170374Ssimokawa			printf("%s: DOORBELL(%d)\n", __func__, login_id);
1626123430Ssimokawa		if (login->last_hi == 0xffff &&
1627123430Ssimokawa		    login->last_lo == 0xffffffff) {
1628121186Ssimokawa			printf("%s: no previous pointer(DOORBELL)\n",
1629127468Ssimokawa			    __func__);
1630121186Ssimokawa			break;
1631121186Ssimokawa		}
1632123430Ssimokawa		if ((login->flags & F_LINK_ACTIVE) != 0) {
1633121186Ssimokawa			if (debug)
1634121186Ssimokawa				printf("link active (DOORBELL)\n");
1635121186Ssimokawa			break;
1636121186Ssimokawa		}
1637123430Ssimokawa		sbp_targ_fetch_orb(sc, fwdev,
1638123430Ssimokawa		    login->last_hi, login->last_lo,
1639123430Ssimokawa		    login, FETCH_POINTER);
1640121186Ssimokawa		break;
1641121186Ssimokawa	case 0x00:	/* AGENT_STATE */
1642170374Ssimokawa		printf("%s: AGENT_STATE (%d:ignore)\n", __func__, login_id);
1643121186Ssimokawa		break;
1644121186Ssimokawa	case 0x14:	/* UNSOLICITED_STATE_ENABLE */
1645170374Ssimokawa		printf("%s: UNSOLICITED_STATE_ENABLE (%d:ignore)\n",
1646170374Ssimokawa							 __func__, login_id);
1647121186Ssimokawa		break;
1648121186Ssimokawa	default:
1649170374Ssimokawa		printf("%s: invalid register %d(%d)\n",
1650170374Ssimokawa						 __func__, reg, login_id);
1651121186Ssimokawa		rtcode = RESP_ADDRESS_ERROR;
1652121186Ssimokawa	}
1653121186Ssimokawa
1654121186Ssimokawa	return (rtcode);
1655121186Ssimokawa}
1656121186Ssimokawa
1657121186Ssimokawastatic int
1658121186Ssimokawasbp_targ_mgm(struct fw_xfer *xfer, struct fw_device *fwdev)
1659121186Ssimokawa{
1660121186Ssimokawa	struct sbp_targ_softc *sc;
1661121186Ssimokawa	struct fw_pkt *fp;
1662121186Ssimokawa
1663121186Ssimokawa	sc = (struct sbp_targ_softc *)xfer->sc;
1664121186Ssimokawa
1665121186Ssimokawa	fp = &xfer->recv.hdr;
1666121186Ssimokawa	if (fp->mode.wreqb.tcode != FWTCODE_WREQB){
1667127468Ssimokawa		printf("%s: tcode = %d\n", __func__, fp->mode.wreqb.tcode);
1668121186Ssimokawa		return(RESP_TYPE_ERROR);
1669121186Ssimokawa        }
1670121186Ssimokawa
1671121186Ssimokawa	sbp_targ_fetch_orb(sc, fwdev,
1672121186Ssimokawa	    ntohl(xfer->recv.payload[0]),
1673121186Ssimokawa	    ntohl(xfer->recv.payload[1]),
1674121186Ssimokawa	    NULL, FETCH_MGM);
1675121186Ssimokawa
1676121186Ssimokawa	return(0);
1677121186Ssimokawa}
1678121186Ssimokawa
1679121186Ssimokawastatic void
1680121186Ssimokawasbp_targ_recv(struct fw_xfer *xfer)
1681121186Ssimokawa{
1682121186Ssimokawa	struct fw_pkt *fp, *sfp;
1683121186Ssimokawa	struct fw_device *fwdev;
1684129585Sdfr	uint32_t lo;
1685121186Ssimokawa	int s, rtcode;
1686121186Ssimokawa	struct sbp_targ_softc *sc;
1687121186Ssimokawa
1688121186Ssimokawa	s = splfw();
1689121186Ssimokawa	sc = (struct sbp_targ_softc *)xfer->sc;
1690121186Ssimokawa	fp = &xfer->recv.hdr;
1691121186Ssimokawa	fwdev = fw_noderesolve_nodeid(sc->fd.fc, fp->mode.wreqb.src & 0x3f);
1692121186Ssimokawa	if (fwdev == NULL) {
1693121186Ssimokawa		printf("%s: cannot resolve nodeid=%d\n",
1694127468Ssimokawa		    __func__, fp->mode.wreqb.src & 0x3f);
1695121186Ssimokawa		rtcode = RESP_TYPE_ERROR; /* XXX */
1696121186Ssimokawa		goto done;
1697121186Ssimokawa	}
1698121186Ssimokawa	lo = fp->mode.wreqb.dest_lo;
1699170374Ssimokawa
1700121186Ssimokawa	if (lo == SBP_TARG_BIND_LO(-1))
1701121186Ssimokawa		rtcode = sbp_targ_mgm(xfer, fwdev);
1702121186Ssimokawa	else if (lo >= SBP_TARG_BIND_LO(0))
1703123430Ssimokawa		rtcode = sbp_targ_cmd(xfer, fwdev, SBP_TARG_LOGIN_ID(lo),
1704123430Ssimokawa		    lo % 0x20);
1705121186Ssimokawa	else
1706121186Ssimokawa		rtcode = RESP_ADDRESS_ERROR;
1707121186Ssimokawa
1708121186Ssimokawadone:
1709121186Ssimokawa	if (rtcode != 0)
1710127468Ssimokawa		printf("%s: rtcode = %d\n", __func__, rtcode);
1711121186Ssimokawa	sfp = &xfer->send.hdr;
1712121186Ssimokawa	xfer->send.spd = 2; /* XXX */
1713167632Ssimokawa	xfer->hand = sbp_targ_resp_callback;
1714121186Ssimokawa	sfp->mode.wres.dst = fp->mode.wreqb.src;
1715121186Ssimokawa	sfp->mode.wres.tlrt = fp->mode.wreqb.tlrt;
1716121186Ssimokawa	sfp->mode.wres.tcode = FWTCODE_WRES;
1717121186Ssimokawa	sfp->mode.wres.rtcode = rtcode;
1718121186Ssimokawa	sfp->mode.wres.pri = 0;
1719121186Ssimokawa
1720121186Ssimokawa	fw_asyreq(xfer->fc, -1, xfer);
1721121186Ssimokawa	splx(s);
1722121186Ssimokawa}
1723121186Ssimokawa
1724121186Ssimokawastatic int
1725121186Ssimokawasbp_targ_attach(device_t dev)
1726121186Ssimokawa{
1727121186Ssimokawa	struct sbp_targ_softc *sc;
1728121186Ssimokawa	struct cam_devq *devq;
1729170374Ssimokawa	struct firewire_comm *fc;
1730121186Ssimokawa
1731121186Ssimokawa        sc = (struct sbp_targ_softc *) device_get_softc(dev);
1732121186Ssimokawa	bzero((void *)sc, sizeof(struct sbp_targ_softc));
1733121186Ssimokawa
1734170374Ssimokawa	mtx_init(&sc->mtx, "sbp_targ", NULL, MTX_DEF);
1735170374Ssimokawa	sc->fd.fc = fc = device_get_ivars(dev);
1736121186Ssimokawa	sc->fd.dev = dev;
1737123430Ssimokawa	sc->fd.post_explore = (void *) sbp_targ_post_explore;
1738121186Ssimokawa	sc->fd.post_busreset = (void *) sbp_targ_post_busreset;
1739121186Ssimokawa
1740169475Ssimokawa        devq = cam_simq_alloc(/*maxopenings*/MAX_LUN*MAX_INITIATORS);
1741121186Ssimokawa	if (devq == NULL)
1742121186Ssimokawa		return (ENXIO);
1743121186Ssimokawa
1744121186Ssimokawa	sc->sim = cam_sim_alloc(sbp_targ_action, sbp_targ_poll,
1745170374Ssimokawa	    "sbp_targ", sc, device_get_unit(dev), &sc->mtx,
1746121186Ssimokawa	    /*untagged*/ 1, /*tagged*/ 1, devq);
1747121186Ssimokawa	if (sc->sim == NULL) {
1748121186Ssimokawa		cam_simq_free(devq);
1749121186Ssimokawa		return (ENXIO);
1750121186Ssimokawa	}
1751121186Ssimokawa
1752170374Ssimokawa	SBP_LOCK(sc);
1753170872Sscottl	if (xpt_bus_register(sc->sim, dev, /*bus*/0) != CAM_SUCCESS)
1754121186Ssimokawa		goto fail;
1755121186Ssimokawa
1756121186Ssimokawa	if (xpt_create_path(&sc->path, /*periph*/ NULL, cam_sim_path(sc->sim),
1757121186Ssimokawa	    CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
1758121186Ssimokawa		xpt_bus_deregister(cam_sim_path(sc->sim));
1759121186Ssimokawa		goto fail;
1760121186Ssimokawa	}
1761170374Ssimokawa	SBP_UNLOCK(sc);
1762121186Ssimokawa
1763121186Ssimokawa	sc->fwb.start = SBP_TARG_BIND_START;
1764121186Ssimokawa	sc->fwb.end = SBP_TARG_BIND_END;
1765121186Ssimokawa
1766121186Ssimokawa	/* pre-allocate xfer */
1767121186Ssimokawa	STAILQ_INIT(&sc->fwb.xferlist);
1768169130Ssimokawa	fw_xferlist_add(&sc->fwb.xferlist, M_SBP_TARG,
1769169130Ssimokawa	    /*send*/ 0, /*recv*/ SBP_TARG_RECV_LEN, MAX_LUN /* XXX */,
1770170374Ssimokawa	    fc, (void *)sc, sbp_targ_recv);
1771170374Ssimokawa	fw_bindadd(fc, &sc->fwb);
1772121186Ssimokawa	return 0;
1773121186Ssimokawa
1774121186Ssimokawafail:
1775170374Ssimokawa	SBP_UNLOCK(sc);
1776121186Ssimokawa	cam_sim_free(sc->sim, /*free_devq*/TRUE);
1777121186Ssimokawa	return (ENXIO);
1778121186Ssimokawa}
1779121186Ssimokawa
1780121186Ssimokawastatic int
1781121186Ssimokawasbp_targ_detach(device_t dev)
1782121186Ssimokawa{
1783121186Ssimokawa	struct sbp_targ_softc *sc;
1784121186Ssimokawa	struct sbp_targ_lstate *lstate;
1785121186Ssimokawa	int i;
1786121186Ssimokawa
1787121186Ssimokawa	sc = (struct sbp_targ_softc *)device_get_softc(dev);
1788121186Ssimokawa	sc->fd.post_busreset = NULL;
1789121186Ssimokawa
1790170374Ssimokawa	SBP_LOCK(sc);
1791121186Ssimokawa	xpt_free_path(sc->path);
1792121186Ssimokawa	xpt_bus_deregister(cam_sim_path(sc->sim));
1793170374Ssimokawa	SBP_UNLOCK(sc);
1794121186Ssimokawa	cam_sim_free(sc->sim, /*free_devq*/TRUE);
1795121186Ssimokawa
1796121186Ssimokawa	for (i = 0; i < MAX_LUN; i ++) {
1797121186Ssimokawa		lstate = sc->lstate[i];
1798121186Ssimokawa		if (lstate != NULL) {
1799121186Ssimokawa			xpt_free_path(lstate->path);
1800121186Ssimokawa			free(lstate, M_SBP_TARG);
1801121186Ssimokawa		}
1802121186Ssimokawa	}
1803121186Ssimokawa	if (sc->black_hole != NULL) {
1804121186Ssimokawa		xpt_free_path(sc->black_hole->path);
1805121186Ssimokawa		free(sc->black_hole, M_SBP_TARG);
1806121186Ssimokawa	}
1807121186Ssimokawa
1808121186Ssimokawa	fw_bindremove(sc->fd.fc, &sc->fwb);
1809169130Ssimokawa	fw_xferlist_remove(&sc->fwb.xferlist);
1810121186Ssimokawa
1811170374Ssimokawa	mtx_destroy(&sc->mtx);
1812170374Ssimokawa
1813121186Ssimokawa	return 0;
1814121186Ssimokawa}
1815121186Ssimokawa
1816121186Ssimokawastatic devclass_t sbp_targ_devclass;
1817121186Ssimokawa
1818121186Ssimokawastatic device_method_t sbp_targ_methods[] = {
1819121186Ssimokawa	/* device interface */
1820121186Ssimokawa	DEVMETHOD(device_identify,	sbp_targ_identify),
1821121186Ssimokawa	DEVMETHOD(device_probe,		sbp_targ_probe),
1822121186Ssimokawa	DEVMETHOD(device_attach,	sbp_targ_attach),
1823121186Ssimokawa	DEVMETHOD(device_detach,	sbp_targ_detach),
1824121186Ssimokawa	{ 0, 0 }
1825121186Ssimokawa};
1826121186Ssimokawa
1827121186Ssimokawastatic driver_t sbp_targ_driver = {
1828121186Ssimokawa	"sbp_targ",
1829121186Ssimokawa	sbp_targ_methods,
1830121186Ssimokawa	sizeof(struct sbp_targ_softc),
1831121186Ssimokawa};
1832121186Ssimokawa
1833121186SsimokawaDRIVER_MODULE(sbp_targ, firewire, sbp_targ_driver, sbp_targ_devclass, 0, 0);
1834121186SsimokawaMODULE_VERSION(sbp_targ, 1);
1835121186SsimokawaMODULE_DEPEND(sbp_targ, firewire, 1, 1, 1);
1836121186SsimokawaMODULE_DEPEND(sbp_targ, cam, 1, 1, 1);
1837