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