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