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