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