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