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