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