xref: /freebsd/sys/dev/firewire/sbp_targ.c (revision 7a22215c5346c9009d1dfa4d3c118ff99f89d184)
1098ca2bdSWarner Losh /*-
2e9e688e2SHidetoshi Shimokawa  * Copyright (C) 2003
3e9e688e2SHidetoshi Shimokawa  * 	Hidetoshi Shimokawa. All rights reserved.
4e9e688e2SHidetoshi Shimokawa  *
5e9e688e2SHidetoshi Shimokawa  * Redistribution and use in source and binary forms, with or without
6e9e688e2SHidetoshi Shimokawa  * modification, are permitted provided that the following conditions
7e9e688e2SHidetoshi Shimokawa  * are met:
8e9e688e2SHidetoshi Shimokawa  * 1. Redistributions of source code must retain the above copyright
9e9e688e2SHidetoshi Shimokawa  *    notice, this list of conditions and the following disclaimer.
10e9e688e2SHidetoshi Shimokawa  * 2. Redistributions in binary form must reproduce the above copyright
11e9e688e2SHidetoshi Shimokawa  *    notice, this list of conditions and the following disclaimer in the
12e9e688e2SHidetoshi Shimokawa  *    documentation and/or other materials provided with the distribution.
13e9e688e2SHidetoshi Shimokawa  * 3. All advertising materials mentioning features or use of this software
14e9e688e2SHidetoshi Shimokawa  *    must display the following acknowledgement:
15e9e688e2SHidetoshi Shimokawa  *
16e9e688e2SHidetoshi Shimokawa  *	This product includes software developed by Hidetoshi Shimokawa.
17e9e688e2SHidetoshi Shimokawa  *
18e9e688e2SHidetoshi Shimokawa  * 4. Neither the name of the author nor the names of its contributors
19e9e688e2SHidetoshi Shimokawa  *    may be used to endorse or promote products derived from this software
20e9e688e2SHidetoshi Shimokawa  *    without specific prior written permission.
21e9e688e2SHidetoshi Shimokawa  *
22e9e688e2SHidetoshi Shimokawa  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23e9e688e2SHidetoshi Shimokawa  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24e9e688e2SHidetoshi Shimokawa  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25e9e688e2SHidetoshi Shimokawa  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26e9e688e2SHidetoshi Shimokawa  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27e9e688e2SHidetoshi Shimokawa  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28e9e688e2SHidetoshi Shimokawa  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29e9e688e2SHidetoshi Shimokawa  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30e9e688e2SHidetoshi Shimokawa  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31e9e688e2SHidetoshi Shimokawa  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32e9e688e2SHidetoshi Shimokawa  * SUCH DAMAGE.
33e9e688e2SHidetoshi Shimokawa  *
34e9e688e2SHidetoshi Shimokawa  * $FreeBSD$
35e9e688e2SHidetoshi Shimokawa  */
36e9e688e2SHidetoshi Shimokawa 
37e9e688e2SHidetoshi Shimokawa #include <sys/param.h>
38e9e688e2SHidetoshi Shimokawa #include <sys/kernel.h>
39e9e688e2SHidetoshi Shimokawa #include <sys/systm.h>
40e9e688e2SHidetoshi Shimokawa #include <sys/sysctl.h>
41e9e688e2SHidetoshi Shimokawa #include <sys/types.h>
42e9e688e2SHidetoshi Shimokawa #include <sys/conf.h>
43e9e688e2SHidetoshi Shimokawa #include <sys/malloc.h>
441cc052e8SKenneth D. Merry #include <sys/endian.h>
45e9e688e2SHidetoshi Shimokawa #if __FreeBSD_version < 500000
46e9e688e2SHidetoshi Shimokawa #include <sys/devicestat.h>
47e9e688e2SHidetoshi Shimokawa #endif
48e9e688e2SHidetoshi Shimokawa 
49e9e688e2SHidetoshi Shimokawa #include <sys/bus.h>
50e9e688e2SHidetoshi Shimokawa #include <machine/bus.h>
51e9e688e2SHidetoshi Shimokawa 
52e9e688e2SHidetoshi Shimokawa #include <dev/firewire/firewire.h>
53e9e688e2SHidetoshi Shimokawa #include <dev/firewire/firewirereg.h>
54e9e688e2SHidetoshi Shimokawa #include <dev/firewire/iec13213.h>
55e9e688e2SHidetoshi Shimokawa #include <dev/firewire/sbp.h>
56e9e688e2SHidetoshi Shimokawa #include <dev/firewire/fwmem.h>
57e9e688e2SHidetoshi Shimokawa 
58e9e688e2SHidetoshi Shimokawa #include <cam/cam.h>
59e9e688e2SHidetoshi Shimokawa #include <cam/cam_ccb.h>
60e9e688e2SHidetoshi Shimokawa #include <cam/cam_sim.h>
61e9e688e2SHidetoshi Shimokawa #include <cam/cam_xpt_sim.h>
62e9e688e2SHidetoshi Shimokawa #include <cam/cam_debug.h>
63e9e688e2SHidetoshi Shimokawa #include <cam/cam_periph.h>
64e9e688e2SHidetoshi Shimokawa #include <cam/scsi/scsi_all.h>
654636d244SSean Bruno #include <cam/scsi/scsi_message.h>
66e9e688e2SHidetoshi Shimokawa 
67a73ff510SHidetoshi Shimokawa #define SBP_TARG_RECV_LEN	8
68a73ff510SHidetoshi Shimokawa #define MAX_INITIATORS		8
69e9e688e2SHidetoshi Shimokawa #define MAX_LUN			63
70a73ff510SHidetoshi Shimokawa #define MAX_LOGINS		63
71a73ff510SHidetoshi Shimokawa #define MAX_NODES		63
72e9e688e2SHidetoshi Shimokawa /*
73e9e688e2SHidetoshi Shimokawa  * management/command block agent registers
74e9e688e2SHidetoshi Shimokawa  *
75e9e688e2SHidetoshi Shimokawa  * BASE 0xffff f001 0000 management port
76a73ff510SHidetoshi Shimokawa  * BASE 0xffff f001 0020 command port for login id 0
77a73ff510SHidetoshi Shimokawa  * BASE 0xffff f001 0040 command port for login id 1
78e9e688e2SHidetoshi Shimokawa  *
79e9e688e2SHidetoshi Shimokawa  */
80e9e688e2SHidetoshi Shimokawa #define SBP_TARG_MGM	 0x10000	/* offset from 0xffff f000 000 */
81e9e688e2SHidetoshi Shimokawa #define SBP_TARG_BIND_HI	0xffff
82e9e688e2SHidetoshi Shimokawa #define SBP_TARG_BIND_LO(l)	(0xf0000000 + SBP_TARG_MGM + 0x20 * ((l) + 1))
83e9e688e2SHidetoshi Shimokawa #define SBP_TARG_BIND_START	(((u_int64_t)SBP_TARG_BIND_HI << 32) | \
84e9e688e2SHidetoshi Shimokawa 				    SBP_TARG_BIND_LO(-1))
85e9e688e2SHidetoshi Shimokawa #define SBP_TARG_BIND_END	(((u_int64_t)SBP_TARG_BIND_HI << 32) | \
86a73ff510SHidetoshi Shimokawa 				    SBP_TARG_BIND_LO(MAX_LOGINS))
87a73ff510SHidetoshi Shimokawa #define SBP_TARG_LOGIN_ID(lo)	(((lo) - SBP_TARG_BIND_LO(0))/0x20)
88e9e688e2SHidetoshi Shimokawa 
89e9e688e2SHidetoshi Shimokawa #define FETCH_MGM	0
90e9e688e2SHidetoshi Shimokawa #define FETCH_CMD	1
91e9e688e2SHidetoshi Shimokawa #define FETCH_POINTER	2
92e9e688e2SHidetoshi Shimokawa 
93a73ff510SHidetoshi Shimokawa #define F_LINK_ACTIVE	(1 << 0)
94a73ff510SHidetoshi Shimokawa #define F_ATIO_STARVED	(1 << 1)
95a73ff510SHidetoshi Shimokawa #define F_LOGIN		(1 << 2)
96a73ff510SHidetoshi Shimokawa #define F_HOLD		(1 << 3)
97a73ff510SHidetoshi Shimokawa #define F_FREEZED	(1 << 4)
98a73ff510SHidetoshi Shimokawa 
99d745c852SEd Schouten static MALLOC_DEFINE(M_SBP_TARG, "sbp_targ", "SBP-II/FireWire target mode");
100e9e688e2SHidetoshi Shimokawa 
101e9e688e2SHidetoshi Shimokawa static int debug = 0;
102e9e688e2SHidetoshi Shimokawa 
103e9e688e2SHidetoshi Shimokawa SYSCTL_INT(_debug, OID_AUTO, sbp_targ_debug, CTLFLAG_RW, &debug, 0,
104e9e688e2SHidetoshi Shimokawa         "SBP target mode debug flag");
105e9e688e2SHidetoshi Shimokawa 
106a73ff510SHidetoshi Shimokawa struct sbp_targ_login {
107a73ff510SHidetoshi Shimokawa 	struct sbp_targ_lstate *lstate;
108a73ff510SHidetoshi Shimokawa 	struct fw_device *fwdev;
109a73ff510SHidetoshi Shimokawa 	struct sbp_login_res loginres;
11003161bbcSDoug Rabson 	uint16_t fifo_hi;
11103161bbcSDoug Rabson 	uint16_t last_hi;
11203161bbcSDoug Rabson 	uint32_t fifo_lo;
11303161bbcSDoug Rabson 	uint32_t last_lo;
114a73ff510SHidetoshi Shimokawa 	STAILQ_HEAD(, orb_info) orbs;
115a73ff510SHidetoshi Shimokawa 	STAILQ_ENTRY(sbp_targ_login) link;
11603161bbcSDoug Rabson 	uint16_t hold_sec;
11703161bbcSDoug Rabson 	uint16_t id;
11803161bbcSDoug Rabson 	uint8_t flags;
11903161bbcSDoug Rabson 	uint8_t spd;
120a73ff510SHidetoshi Shimokawa 	struct callout hold_callout;
121a73ff510SHidetoshi Shimokawa };
122a73ff510SHidetoshi Shimokawa 
123a73ff510SHidetoshi Shimokawa struct sbp_targ_lstate {
12403161bbcSDoug Rabson 	uint16_t lun;
125a73ff510SHidetoshi Shimokawa 	struct sbp_targ_softc *sc;
126a73ff510SHidetoshi Shimokawa 	struct cam_path *path;
127a73ff510SHidetoshi Shimokawa 	struct ccb_hdr_slist accept_tios;
128a73ff510SHidetoshi Shimokawa 	struct ccb_hdr_slist immed_notifies;
129a73ff510SHidetoshi Shimokawa 	struct crom_chunk model;
13003161bbcSDoug Rabson 	uint32_t flags;
131a73ff510SHidetoshi Shimokawa 	STAILQ_HEAD(, sbp_targ_login) logins;
132a73ff510SHidetoshi Shimokawa };
133a73ff510SHidetoshi Shimokawa 
134e9e688e2SHidetoshi Shimokawa struct sbp_targ_softc {
135e9e688e2SHidetoshi Shimokawa         struct firewire_dev_comm fd;
136e9e688e2SHidetoshi Shimokawa 	struct cam_sim *sim;
137e9e688e2SHidetoshi Shimokawa 	struct cam_path *path;
138e9e688e2SHidetoshi Shimokawa 	struct fw_bind fwb;
139e9e688e2SHidetoshi Shimokawa 	int ndevs;
140a73ff510SHidetoshi Shimokawa 	int flags;
141e9e688e2SHidetoshi Shimokawa 	struct crom_chunk unit;
142e9e688e2SHidetoshi Shimokawa 	struct sbp_targ_lstate *lstate[MAX_LUN];
143e9e688e2SHidetoshi Shimokawa 	struct sbp_targ_lstate *black_hole;
144a73ff510SHidetoshi Shimokawa 	struct sbp_targ_login *logins[MAX_LOGINS];
1459950b741SHidetoshi Shimokawa 	struct mtx mtx;
146e9e688e2SHidetoshi Shimokawa };
1479950b741SHidetoshi Shimokawa #define SBP_LOCK(sc) mtx_lock(&(sc)->mtx)
1489950b741SHidetoshi Shimokawa #define SBP_UNLOCK(sc) mtx_unlock(&(sc)->mtx)
149e9e688e2SHidetoshi Shimokawa 
150e9e688e2SHidetoshi Shimokawa struct corb4 {
151e9e688e2SHidetoshi Shimokawa #if BYTE_ORDER == BIG_ENDIAN
15203161bbcSDoug Rabson 	uint32_t n:1,
153e9e688e2SHidetoshi Shimokawa 		  rq_fmt:2,
154e9e688e2SHidetoshi Shimokawa 		  :1,
155e9e688e2SHidetoshi Shimokawa 		  dir:1,
156e9e688e2SHidetoshi Shimokawa 		  spd:3,
157e9e688e2SHidetoshi Shimokawa 		  max_payload:4,
158e9e688e2SHidetoshi Shimokawa 		  page_table_present:1,
159e9e688e2SHidetoshi Shimokawa 		  page_size:3,
160e9e688e2SHidetoshi Shimokawa 		  data_size:16;
161e9e688e2SHidetoshi Shimokawa #else
16203161bbcSDoug Rabson 	uint32_t data_size:16,
163e9e688e2SHidetoshi Shimokawa 		  page_size:3,
164e9e688e2SHidetoshi Shimokawa 		  page_table_present:1,
165e9e688e2SHidetoshi Shimokawa 		  max_payload:4,
166e9e688e2SHidetoshi Shimokawa 		  spd:3,
167e9e688e2SHidetoshi Shimokawa 		  dir:1,
168e9e688e2SHidetoshi Shimokawa 		  :1,
169e9e688e2SHidetoshi Shimokawa 		  rq_fmt:2,
170e9e688e2SHidetoshi Shimokawa 		  n:1;
171e9e688e2SHidetoshi Shimokawa #endif
172e9e688e2SHidetoshi Shimokawa };
173e9e688e2SHidetoshi Shimokawa 
174e9e688e2SHidetoshi Shimokawa struct morb4 {
175e9e688e2SHidetoshi Shimokawa #if BYTE_ORDER == BIG_ENDIAN
17603161bbcSDoug Rabson 	uint32_t n:1,
177e9e688e2SHidetoshi Shimokawa 		  rq_fmt:2,
178e9e688e2SHidetoshi Shimokawa 		  :9,
179e9e688e2SHidetoshi Shimokawa 		  fun:4,
180e9e688e2SHidetoshi Shimokawa 		  id:16;
181e9e688e2SHidetoshi Shimokawa #else
18203161bbcSDoug Rabson 	uint32_t id:16,
183e9e688e2SHidetoshi Shimokawa 		  fun:4,
184e9e688e2SHidetoshi Shimokawa 		  :9,
185e9e688e2SHidetoshi Shimokawa 		  rq_fmt:2,
186e9e688e2SHidetoshi Shimokawa 		  n:1;
187e9e688e2SHidetoshi Shimokawa #endif
188e9e688e2SHidetoshi Shimokawa };
189e9e688e2SHidetoshi Shimokawa 
1904636d244SSean Bruno 
1914636d244SSean Bruno /*
1924636d244SSean Bruno  * Urestricted page table format
1934636d244SSean Bruno  * states that the segment length
1944636d244SSean Bruno  * and high base addr are in the first
1954636d244SSean Bruno  * 32 bits and the base low is in
1964636d244SSean Bruno  * the second
1974636d244SSean Bruno  */
1984636d244SSean Bruno struct unrestricted_page_table_fmt {
1994636d244SSean Bruno 	uint16_t segment_len;
2004636d244SSean Bruno 	uint16_t segment_base_high;
2014636d244SSean Bruno 	uint32_t segment_base_low;
2024636d244SSean Bruno };
2034636d244SSean Bruno 
2044636d244SSean Bruno 
205e9e688e2SHidetoshi Shimokawa struct orb_info {
206e9e688e2SHidetoshi Shimokawa 	struct sbp_targ_softc *sc;
207e9e688e2SHidetoshi Shimokawa 	struct fw_device *fwdev;
208a73ff510SHidetoshi Shimokawa 	struct sbp_targ_login *login;
209e9e688e2SHidetoshi Shimokawa 	union ccb *ccb;
210e9e688e2SHidetoshi Shimokawa 	struct ccb_accept_tio *atio;
21103161bbcSDoug Rabson 	uint8_t state;
212e9e688e2SHidetoshi Shimokawa #define ORBI_STATUS_NONE	0
213e9e688e2SHidetoshi Shimokawa #define ORBI_STATUS_FETCH	1
214e9e688e2SHidetoshi Shimokawa #define ORBI_STATUS_ATIO	2
215e9e688e2SHidetoshi Shimokawa #define ORBI_STATUS_CTIO	3
216e9e688e2SHidetoshi Shimokawa #define ORBI_STATUS_STATUS	4
217e9e688e2SHidetoshi Shimokawa #define ORBI_STATUS_POINTER	5
218e9e688e2SHidetoshi Shimokawa #define ORBI_STATUS_ABORTED	7
21903161bbcSDoug Rabson 	uint8_t refcount;
22003161bbcSDoug Rabson 	uint16_t orb_hi;
22103161bbcSDoug Rabson 	uint32_t orb_lo;
22203161bbcSDoug Rabson 	uint32_t data_hi;
22303161bbcSDoug Rabson 	uint32_t data_lo;
224e9e688e2SHidetoshi Shimokawa 	struct corb4 orb4;
225e9e688e2SHidetoshi Shimokawa 	STAILQ_ENTRY(orb_info) link;
22603161bbcSDoug Rabson 	uint32_t orb[8];
2274636d244SSean Bruno 	struct unrestricted_page_table_fmt *page_table;
2284636d244SSean Bruno 	struct unrestricted_page_table_fmt *cur_pte;
2294636d244SSean Bruno 	struct unrestricted_page_table_fmt *last_pte;
2304636d244SSean Bruno 	uint32_t  last_block_read;
231e9e688e2SHidetoshi Shimokawa 	struct sbp_status status;
232e9e688e2SHidetoshi Shimokawa };
233e9e688e2SHidetoshi Shimokawa 
234e9e688e2SHidetoshi Shimokawa static char *orb_fun_name[] = {
235e9e688e2SHidetoshi Shimokawa 	ORB_FUN_NAMES
236e9e688e2SHidetoshi Shimokawa };
237e9e688e2SHidetoshi Shimokawa 
238e9e688e2SHidetoshi Shimokawa static void sbp_targ_recv(struct fw_xfer *);
239e9e688e2SHidetoshi Shimokawa static void sbp_targ_fetch_orb(struct sbp_targ_softc *, struct fw_device *,
24003161bbcSDoug Rabson     uint16_t, uint32_t, struct sbp_targ_login *, int);
2414636d244SSean Bruno static void sbp_targ_xfer_pt(struct orb_info *);
2429950b741SHidetoshi Shimokawa static void sbp_targ_abort(struct sbp_targ_softc *, struct orb_info *);
243e9e688e2SHidetoshi Shimokawa 
244e9e688e2SHidetoshi Shimokawa static void
245e9e688e2SHidetoshi Shimokawa sbp_targ_identify(driver_t *driver, device_t parent)
246e9e688e2SHidetoshi Shimokawa {
247e9e688e2SHidetoshi Shimokawa 	BUS_ADD_CHILD(parent, 0, "sbp_targ", device_get_unit(parent));
248e9e688e2SHidetoshi Shimokawa }
249e9e688e2SHidetoshi Shimokawa 
250e9e688e2SHidetoshi Shimokawa static int
251e9e688e2SHidetoshi Shimokawa sbp_targ_probe(device_t dev)
252e9e688e2SHidetoshi Shimokawa {
253e9e688e2SHidetoshi Shimokawa 	device_t pa;
254e9e688e2SHidetoshi Shimokawa 
255e9e688e2SHidetoshi Shimokawa 	pa = device_get_parent(dev);
256e9e688e2SHidetoshi Shimokawa 	if(device_get_unit(dev) != device_get_unit(pa)){
257e9e688e2SHidetoshi Shimokawa 		return(ENXIO);
258e9e688e2SHidetoshi Shimokawa 	}
259e9e688e2SHidetoshi Shimokawa 
260e9e688e2SHidetoshi Shimokawa 	device_set_desc(dev, "SBP-2/SCSI over FireWire target mode");
261e9e688e2SHidetoshi Shimokawa 	return (0);
262e9e688e2SHidetoshi Shimokawa }
263e9e688e2SHidetoshi Shimokawa 
264a73ff510SHidetoshi Shimokawa static void
265a73ff510SHidetoshi Shimokawa sbp_targ_dealloc_login(struct sbp_targ_login *login)
266a73ff510SHidetoshi Shimokawa {
267a73ff510SHidetoshi Shimokawa 	struct orb_info *orbi, *next;
268a73ff510SHidetoshi Shimokawa 
269a73ff510SHidetoshi Shimokawa 	if (login == NULL) {
27010d3ed64SHidetoshi Shimokawa 		printf("%s: login = NULL\n", __func__);
271a73ff510SHidetoshi Shimokawa 		return;
272a73ff510SHidetoshi Shimokawa 	}
273a73ff510SHidetoshi Shimokawa 	for (orbi = STAILQ_FIRST(&login->orbs); orbi != NULL; orbi = next) {
274a73ff510SHidetoshi Shimokawa 		next = STAILQ_NEXT(orbi, link);
2754636d244SSean Bruno 		if (debug)
2764636d244SSean Bruno 			printf("%s: free orbi %p\n", __func__, orbi);
277a73ff510SHidetoshi Shimokawa 		free(orbi, M_SBP_TARG);
2784636d244SSean Bruno 		orbi = NULL;
279a73ff510SHidetoshi Shimokawa 	}
280a73ff510SHidetoshi Shimokawa 	callout_stop(&login->hold_callout);
281a73ff510SHidetoshi Shimokawa 
282a73ff510SHidetoshi Shimokawa 	STAILQ_REMOVE(&login->lstate->logins, login, sbp_targ_login, link);
283a73ff510SHidetoshi Shimokawa 	login->lstate->sc->logins[login->id] = NULL;
2844636d244SSean Bruno 	if (debug)
2854636d244SSean Bruno 		printf("%s: free login %p\n", __func__, login);
286a73ff510SHidetoshi Shimokawa 	free((void *)login, M_SBP_TARG);
2874636d244SSean Bruno 	login = NULL;
288a73ff510SHidetoshi Shimokawa }
289a73ff510SHidetoshi Shimokawa 
290a73ff510SHidetoshi Shimokawa static void
291a73ff510SHidetoshi Shimokawa sbp_targ_hold_expire(void *arg)
292a73ff510SHidetoshi Shimokawa {
293a73ff510SHidetoshi Shimokawa 	struct sbp_targ_login *login;
294a73ff510SHidetoshi Shimokawa 
295a73ff510SHidetoshi Shimokawa 	login = (struct sbp_targ_login *)arg;
296a73ff510SHidetoshi Shimokawa 
297a73ff510SHidetoshi Shimokawa 	if (login->flags & F_HOLD) {
29810d3ed64SHidetoshi Shimokawa 		printf("%s: login_id=%d expired\n", __func__, login->id);
299a73ff510SHidetoshi Shimokawa 		sbp_targ_dealloc_login(login);
300a73ff510SHidetoshi Shimokawa 	} else {
30110d3ed64SHidetoshi Shimokawa 		printf("%s: login_id=%d not hold\n", __func__, login->id);
302a73ff510SHidetoshi Shimokawa 	}
303a73ff510SHidetoshi Shimokawa }
304a73ff510SHidetoshi Shimokawa 
305e9e688e2SHidetoshi Shimokawa static void
306e9e688e2SHidetoshi Shimokawa sbp_targ_post_busreset(void *arg)
307e9e688e2SHidetoshi Shimokawa {
308e9e688e2SHidetoshi Shimokawa 	struct sbp_targ_softc *sc;
309e9e688e2SHidetoshi Shimokawa 	struct crom_src *src;
310e9e688e2SHidetoshi Shimokawa 	struct crom_chunk *root;
311e9e688e2SHidetoshi Shimokawa 	struct crom_chunk *unit;
312e9e688e2SHidetoshi Shimokawa 	struct sbp_targ_lstate *lstate;
313a73ff510SHidetoshi Shimokawa 	struct sbp_targ_login *login;
314e9e688e2SHidetoshi Shimokawa 	int i;
315e9e688e2SHidetoshi Shimokawa 
316e9e688e2SHidetoshi Shimokawa 	sc = (struct sbp_targ_softc *)arg;
317e9e688e2SHidetoshi Shimokawa 	src = sc->fd.fc->crom_src;
318e9e688e2SHidetoshi Shimokawa 	root = sc->fd.fc->crom_root;
319e9e688e2SHidetoshi Shimokawa 
320e9e688e2SHidetoshi Shimokawa 	unit = &sc->unit;
321e9e688e2SHidetoshi Shimokawa 
322a73ff510SHidetoshi Shimokawa 	if ((sc->flags & F_FREEZED) == 0) {
3239950b741SHidetoshi Shimokawa 		SBP_LOCK(sc);
324a73ff510SHidetoshi Shimokawa 		sc->flags |= F_FREEZED;
325a73ff510SHidetoshi Shimokawa 		xpt_freeze_simq(sc->sim, /*count*/1);
3269950b741SHidetoshi Shimokawa 		SBP_UNLOCK(sc);
327a73ff510SHidetoshi Shimokawa 	} else {
32810d3ed64SHidetoshi Shimokawa 		printf("%s: already freezed\n", __func__);
329a73ff510SHidetoshi Shimokawa 	}
330a73ff510SHidetoshi Shimokawa 
331e9e688e2SHidetoshi Shimokawa 	bzero(unit, sizeof(struct crom_chunk));
332e9e688e2SHidetoshi Shimokawa 
333e9e688e2SHidetoshi Shimokawa 	crom_add_chunk(src, root, unit, CROM_UDIR);
334e9e688e2SHidetoshi Shimokawa 	crom_add_entry(unit, CSRKEY_SPEC, CSRVAL_ANSIT10);
335e9e688e2SHidetoshi Shimokawa 	crom_add_entry(unit, CSRKEY_VER, CSRVAL_T10SBP2);
336e9e688e2SHidetoshi Shimokawa 	crom_add_entry(unit, CSRKEY_COM_SPEC, CSRVAL_ANSIT10);
337e9e688e2SHidetoshi Shimokawa 	crom_add_entry(unit, CSRKEY_COM_SET, CSRVAL_SCSI);
338e9e688e2SHidetoshi Shimokawa 
339e9e688e2SHidetoshi Shimokawa 	crom_add_entry(unit, CROM_MGM, SBP_TARG_MGM >> 2);
340e9e688e2SHidetoshi Shimokawa 	crom_add_entry(unit, CSRKEY_UNIT_CH, (10<<8) | 8);
341e9e688e2SHidetoshi Shimokawa 
342e9e688e2SHidetoshi Shimokawa 	for (i = 0; i < MAX_LUN; i ++) {
343e9e688e2SHidetoshi Shimokawa 		lstate = sc->lstate[i];
344e9e688e2SHidetoshi Shimokawa 		if (lstate == NULL)
345e9e688e2SHidetoshi Shimokawa 			continue;
346e9e688e2SHidetoshi Shimokawa 		crom_add_entry(unit, CSRKEY_FIRM_VER, 1);
347e9e688e2SHidetoshi Shimokawa 		crom_add_entry(unit, CROM_LUN, i);
348e9e688e2SHidetoshi Shimokawa 		crom_add_entry(unit, CSRKEY_MODEL, 1);
349e9e688e2SHidetoshi Shimokawa 		crom_add_simple_text(src, unit, &lstate->model, "TargetMode");
350e9e688e2SHidetoshi Shimokawa 	}
351a73ff510SHidetoshi Shimokawa 
352a73ff510SHidetoshi Shimokawa 	/* Process for reconnection hold time */
353a73ff510SHidetoshi Shimokawa 	for (i = 0; i < MAX_LOGINS; i ++) {
354a73ff510SHidetoshi Shimokawa 		login = sc->logins[i];
355a73ff510SHidetoshi Shimokawa 		if (login == NULL)
356a73ff510SHidetoshi Shimokawa 			continue;
3579950b741SHidetoshi Shimokawa 		sbp_targ_abort(sc, STAILQ_FIRST(&login->orbs));
358a73ff510SHidetoshi Shimokawa 		if (login->flags & F_LOGIN) {
359a73ff510SHidetoshi Shimokawa 			login->flags |= F_HOLD;
360a73ff510SHidetoshi Shimokawa 			callout_reset(&login->hold_callout,
361a73ff510SHidetoshi Shimokawa 			    hz * login->hold_sec,
362a73ff510SHidetoshi Shimokawa 			    sbp_targ_hold_expire, (void *)login);
363a73ff510SHidetoshi Shimokawa 		}
364a73ff510SHidetoshi Shimokawa 	}
365a73ff510SHidetoshi Shimokawa }
366a73ff510SHidetoshi Shimokawa 
367a73ff510SHidetoshi Shimokawa static void
368a73ff510SHidetoshi Shimokawa sbp_targ_post_explore(void *arg)
369a73ff510SHidetoshi Shimokawa {
370a73ff510SHidetoshi Shimokawa 	struct sbp_targ_softc *sc;
371a73ff510SHidetoshi Shimokawa 
372a73ff510SHidetoshi Shimokawa 	sc = (struct sbp_targ_softc *)arg;
3739950b741SHidetoshi Shimokawa 	SBP_LOCK(sc);
374a73ff510SHidetoshi Shimokawa 	sc->flags &= ~F_FREEZED;
375a73ff510SHidetoshi Shimokawa 	xpt_release_simq(sc->sim, /*run queue*/TRUE);
3769950b741SHidetoshi Shimokawa 	SBP_UNLOCK(sc);
377a73ff510SHidetoshi Shimokawa 	return;
378e9e688e2SHidetoshi Shimokawa }
379e9e688e2SHidetoshi Shimokawa 
380e9e688e2SHidetoshi Shimokawa static cam_status
381e9e688e2SHidetoshi Shimokawa sbp_targ_find_devs(struct sbp_targ_softc *sc, union ccb *ccb,
382e9e688e2SHidetoshi Shimokawa     struct sbp_targ_lstate **lstate, int notfound_failure)
383e9e688e2SHidetoshi Shimokawa {
384e9e688e2SHidetoshi Shimokawa 	u_int lun;
385e9e688e2SHidetoshi Shimokawa 
386e9e688e2SHidetoshi Shimokawa 	/* XXX 0 is the only vaild target_id */
387e9e688e2SHidetoshi Shimokawa 	if (ccb->ccb_h.target_id == CAM_TARGET_WILDCARD &&
388e9e688e2SHidetoshi Shimokawa 	    ccb->ccb_h.target_lun == CAM_LUN_WILDCARD) {
389e9e688e2SHidetoshi Shimokawa 		*lstate = sc->black_hole;
3904636d244SSean Bruno 		if (debug)
3914636d244SSean Bruno 			printf("setting black hole for this target id(%d)\n", ccb->ccb_h.target_id);
392e9e688e2SHidetoshi Shimokawa 		return (CAM_REQ_CMP);
393e9e688e2SHidetoshi Shimokawa 	}
394e9e688e2SHidetoshi Shimokawa 
395e9e688e2SHidetoshi Shimokawa 	lun = ccb->ccb_h.target_lun;
396e9e688e2SHidetoshi Shimokawa 	if (lun >= MAX_LUN)
397e9e688e2SHidetoshi Shimokawa 		return (CAM_LUN_INVALID);
398e9e688e2SHidetoshi Shimokawa 
399e9e688e2SHidetoshi Shimokawa 	*lstate = sc->lstate[lun];
400e9e688e2SHidetoshi Shimokawa 
4014636d244SSean Bruno 	if (notfound_failure != 0 && *lstate == NULL) {
4024636d244SSean Bruno 		if (debug)
4034636d244SSean Bruno 			printf("%s: lstate for lun is invalid, target(%d), lun(%d)\n",
4044636d244SSean Bruno 				__func__, ccb->ccb_h.target_id, lun);
405e9e688e2SHidetoshi Shimokawa 		return (CAM_PATH_INVALID);
4064636d244SSean Bruno 	} else
4074636d244SSean Bruno 		if (debug)
4084636d244SSean Bruno 			printf("%s: setting lstate for tgt(%d) lun(%d)\n",
4094636d244SSean Bruno 				__func__,ccb->ccb_h.target_id, lun);
410e9e688e2SHidetoshi Shimokawa 
411e9e688e2SHidetoshi Shimokawa 	return (CAM_REQ_CMP);
412e9e688e2SHidetoshi Shimokawa }
413e9e688e2SHidetoshi Shimokawa 
414e9e688e2SHidetoshi Shimokawa static void
415e9e688e2SHidetoshi Shimokawa sbp_targ_en_lun(struct sbp_targ_softc *sc, union ccb *ccb)
416e9e688e2SHidetoshi Shimokawa {
417e9e688e2SHidetoshi Shimokawa 	struct ccb_en_lun *cel = &ccb->cel;
418e9e688e2SHidetoshi Shimokawa 	struct sbp_targ_lstate *lstate;
419e9e688e2SHidetoshi Shimokawa 	cam_status status;
420e9e688e2SHidetoshi Shimokawa 
421e9e688e2SHidetoshi Shimokawa 	status = sbp_targ_find_devs(sc, ccb, &lstate, 0);
422e9e688e2SHidetoshi Shimokawa 	if (status != CAM_REQ_CMP) {
423e9e688e2SHidetoshi Shimokawa 		ccb->ccb_h.status = status;
424e9e688e2SHidetoshi Shimokawa 		return;
425e9e688e2SHidetoshi Shimokawa 	}
426e9e688e2SHidetoshi Shimokawa 
427e9e688e2SHidetoshi Shimokawa 	if (cel->enable != 0) {
428e9e688e2SHidetoshi Shimokawa 		if (lstate != NULL) {
429e9e688e2SHidetoshi Shimokawa 			xpt_print_path(ccb->ccb_h.path);
430e9e688e2SHidetoshi Shimokawa 			printf("Lun already enabled\n");
431e9e688e2SHidetoshi Shimokawa 			ccb->ccb_h.status = CAM_LUN_ALRDY_ENA;
432e9e688e2SHidetoshi Shimokawa 			return;
433e9e688e2SHidetoshi Shimokawa 		}
434e9e688e2SHidetoshi Shimokawa 		if (cel->grp6_len != 0 || cel->grp7_len != 0) {
435e9e688e2SHidetoshi Shimokawa 			ccb->ccb_h.status = CAM_REQ_INVALID;
436e9e688e2SHidetoshi Shimokawa 			printf("Non-zero Group Codes\n");
437e9e688e2SHidetoshi Shimokawa 			return;
438e9e688e2SHidetoshi Shimokawa 		}
439e9e688e2SHidetoshi Shimokawa 		lstate = (struct sbp_targ_lstate *)
440e9e688e2SHidetoshi Shimokawa 		    malloc(sizeof(*lstate), M_SBP_TARG, M_NOWAIT | M_ZERO);
441e9e688e2SHidetoshi Shimokawa 		if (lstate == NULL) {
442e9e688e2SHidetoshi Shimokawa 			xpt_print_path(ccb->ccb_h.path);
443e9e688e2SHidetoshi Shimokawa 			printf("Couldn't allocate lstate\n");
444e9e688e2SHidetoshi Shimokawa 			ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
445e9e688e2SHidetoshi Shimokawa 			return;
4464636d244SSean Bruno 		} else {
4474636d244SSean Bruno 			if (debug)
4484636d244SSean Bruno 				printf("%s: malloc'd lstate %p\n",__func__, lstate);
449e9e688e2SHidetoshi Shimokawa 		}
4504636d244SSean Bruno 		if (ccb->ccb_h.target_id == CAM_TARGET_WILDCARD) {
451e9e688e2SHidetoshi Shimokawa 			sc->black_hole = lstate;
4524636d244SSean Bruno 			if (debug)
4534636d244SSean Bruno 				printf("Blackhole set due to target id == %d\n",
4544636d244SSean Bruno 					ccb->ccb_h.target_id);
4554636d244SSean Bruno 		} else
456e9e688e2SHidetoshi Shimokawa 			sc->lstate[ccb->ccb_h.target_lun] = lstate;
4574636d244SSean Bruno 
458e9e688e2SHidetoshi Shimokawa 		memset(lstate, 0, sizeof(*lstate));
459e9e688e2SHidetoshi Shimokawa 		lstate->sc = sc;
460e9e688e2SHidetoshi Shimokawa 		status = xpt_create_path(&lstate->path, /*periph*/NULL,
461e9e688e2SHidetoshi Shimokawa 					 xpt_path_path_id(ccb->ccb_h.path),
462e9e688e2SHidetoshi Shimokawa 					 xpt_path_target_id(ccb->ccb_h.path),
463e9e688e2SHidetoshi Shimokawa 					 xpt_path_lun_id(ccb->ccb_h.path));
464e9e688e2SHidetoshi Shimokawa 		if (status != CAM_REQ_CMP) {
465e9e688e2SHidetoshi Shimokawa 			free(lstate, M_SBP_TARG);
4664636d244SSean Bruno 			lstate = NULL;
467e9e688e2SHidetoshi Shimokawa 			xpt_print_path(ccb->ccb_h.path);
468e9e688e2SHidetoshi Shimokawa 			printf("Couldn't allocate path\n");
469e9e688e2SHidetoshi Shimokawa 			ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
470e9e688e2SHidetoshi Shimokawa 			return;
471e9e688e2SHidetoshi Shimokawa 		}
472e9e688e2SHidetoshi Shimokawa 		SLIST_INIT(&lstate->accept_tios);
473e9e688e2SHidetoshi Shimokawa 		SLIST_INIT(&lstate->immed_notifies);
474a73ff510SHidetoshi Shimokawa 		STAILQ_INIT(&lstate->logins);
475e9e688e2SHidetoshi Shimokawa 
476e9e688e2SHidetoshi Shimokawa 		ccb->ccb_h.status = CAM_REQ_CMP;
477e9e688e2SHidetoshi Shimokawa 		xpt_print_path(ccb->ccb_h.path);
478e9e688e2SHidetoshi Shimokawa 		printf("Lun now enabled for target mode\n");
479e9e688e2SHidetoshi Shimokawa 		/* bus reset */
480e9e688e2SHidetoshi Shimokawa 		sc->fd.fc->ibr(sc->fd.fc);
481e9e688e2SHidetoshi Shimokawa 	} else {
482a73ff510SHidetoshi Shimokawa 		struct sbp_targ_login *login, *next;
483a73ff510SHidetoshi Shimokawa 
484e9e688e2SHidetoshi Shimokawa 		if (lstate == NULL) {
485e9e688e2SHidetoshi Shimokawa 			ccb->ccb_h.status = CAM_LUN_INVALID;
4864636d244SSean Bruno 			printf("Invalid lstate for this target\n");
487e9e688e2SHidetoshi Shimokawa 			return;
488e9e688e2SHidetoshi Shimokawa 		}
489e9e688e2SHidetoshi Shimokawa 		ccb->ccb_h.status = CAM_REQ_CMP;
490e9e688e2SHidetoshi Shimokawa 
491e9e688e2SHidetoshi Shimokawa 		if (SLIST_FIRST(&lstate->accept_tios) != NULL) {
492e9e688e2SHidetoshi Shimokawa 			printf("ATIOs pending\n");
493e9e688e2SHidetoshi Shimokawa 			ccb->ccb_h.status = CAM_REQ_INVALID;
494e9e688e2SHidetoshi Shimokawa 		}
495e9e688e2SHidetoshi Shimokawa 
496e9e688e2SHidetoshi Shimokawa 		if (SLIST_FIRST(&lstate->immed_notifies) != NULL) {
497e9e688e2SHidetoshi Shimokawa 			printf("INOTs pending\n");
498e9e688e2SHidetoshi Shimokawa 			ccb->ccb_h.status = CAM_REQ_INVALID;
499e9e688e2SHidetoshi Shimokawa 		}
500e9e688e2SHidetoshi Shimokawa 
501e9e688e2SHidetoshi Shimokawa 		if (ccb->ccb_h.status != CAM_REQ_CMP) {
5024636d244SSean Bruno 			printf("status != CAM_REQ_CMP\n");
503e9e688e2SHidetoshi Shimokawa 			return;
504e9e688e2SHidetoshi Shimokawa 		}
505e9e688e2SHidetoshi Shimokawa 
506e9e688e2SHidetoshi Shimokawa 		xpt_print_path(ccb->ccb_h.path);
507e9e688e2SHidetoshi Shimokawa 		printf("Target mode disabled\n");
508e9e688e2SHidetoshi Shimokawa 		xpt_free_path(lstate->path);
509e9e688e2SHidetoshi Shimokawa 
510a73ff510SHidetoshi Shimokawa 		for (login = STAILQ_FIRST(&lstate->logins); login != NULL;
511a73ff510SHidetoshi Shimokawa 		    login = next) {
512a73ff510SHidetoshi Shimokawa 			next = STAILQ_NEXT(login, link);
513a73ff510SHidetoshi Shimokawa 			sbp_targ_dealloc_login(login);
514e9e688e2SHidetoshi Shimokawa 		}
515e9e688e2SHidetoshi Shimokawa 
516e9e688e2SHidetoshi Shimokawa 		if (ccb->ccb_h.target_id == CAM_TARGET_WILDCARD)
517e9e688e2SHidetoshi Shimokawa 			sc->black_hole = NULL;
518e9e688e2SHidetoshi Shimokawa 		else
519e9e688e2SHidetoshi Shimokawa 			sc->lstate[ccb->ccb_h.target_lun] = NULL;
5204636d244SSean Bruno 		if (debug)
5214636d244SSean Bruno 			printf("%s: free lstate %p\n", __func__, lstate);
522e9e688e2SHidetoshi Shimokawa 		free(lstate, M_SBP_TARG);
5234636d244SSean Bruno 		lstate = NULL;
524e9e688e2SHidetoshi Shimokawa 
525e9e688e2SHidetoshi Shimokawa 		/* bus reset */
526e9e688e2SHidetoshi Shimokawa 		sc->fd.fc->ibr(sc->fd.fc);
527e9e688e2SHidetoshi Shimokawa 	}
528e9e688e2SHidetoshi Shimokawa }
529e9e688e2SHidetoshi Shimokawa 
530e9e688e2SHidetoshi Shimokawa static void
531e9e688e2SHidetoshi Shimokawa sbp_targ_send_lstate_events(struct sbp_targ_softc *sc,
532e9e688e2SHidetoshi Shimokawa     struct sbp_targ_lstate *lstate)
533e9e688e2SHidetoshi Shimokawa {
534e9e688e2SHidetoshi Shimokawa #if 0
535e9e688e2SHidetoshi Shimokawa 	struct ccb_hdr *ccbh;
536b79dc8a8SKenneth D. Merry 	struct ccb_immediate_notify *inot;
537e9e688e2SHidetoshi Shimokawa 
53810d3ed64SHidetoshi Shimokawa 	printf("%s: not implemented yet\n", __func__);
539e9e688e2SHidetoshi Shimokawa #endif
540e9e688e2SHidetoshi Shimokawa }
541e9e688e2SHidetoshi Shimokawa 
5429950b741SHidetoshi Shimokawa 
5439950b741SHidetoshi Shimokawa static __inline void
5449950b741SHidetoshi Shimokawa sbp_targ_remove_orb_info_locked(struct sbp_targ_login *login, struct orb_info *orbi)
5459950b741SHidetoshi Shimokawa {
5469950b741SHidetoshi Shimokawa 	STAILQ_REMOVE(&login->orbs, orbi, orb_info, link);
5479950b741SHidetoshi Shimokawa }
5489950b741SHidetoshi Shimokawa 
549e9e688e2SHidetoshi Shimokawa static __inline void
550a73ff510SHidetoshi Shimokawa sbp_targ_remove_orb_info(struct sbp_targ_login *login, struct orb_info *orbi)
551e9e688e2SHidetoshi Shimokawa {
5529950b741SHidetoshi Shimokawa 	SBP_LOCK(orbi->sc);
553a73ff510SHidetoshi Shimokawa 	STAILQ_REMOVE(&login->orbs, orbi, orb_info, link);
5549950b741SHidetoshi Shimokawa 	SBP_UNLOCK(orbi->sc);
555e9e688e2SHidetoshi Shimokawa }
556e9e688e2SHidetoshi Shimokawa 
557e9e688e2SHidetoshi Shimokawa /*
558e9e688e2SHidetoshi Shimokawa  * tag_id/init_id encoding
559e9e688e2SHidetoshi Shimokawa  *
560e9e688e2SHidetoshi Shimokawa  * tag_id and init_id has only 32bit for each.
561e9e688e2SHidetoshi Shimokawa  * scsi_target can handle very limited number(up to 15) of init_id.
562e9e688e2SHidetoshi Shimokawa  * we have to encode 48bit orb and 64bit EUI64 into these
563e9e688e2SHidetoshi Shimokawa  * variables.
564e9e688e2SHidetoshi Shimokawa  *
565e9e688e2SHidetoshi Shimokawa  * tag_id represents lower 32bit of ORB address.
566a73ff510SHidetoshi Shimokawa  * init_id represents login_id.
567e9e688e2SHidetoshi Shimokawa  *
568e9e688e2SHidetoshi Shimokawa  */
569e9e688e2SHidetoshi Shimokawa 
570e9e688e2SHidetoshi Shimokawa static struct orb_info *
571e9e688e2SHidetoshi Shimokawa sbp_targ_get_orb_info(struct sbp_targ_lstate *lstate,
572e9e688e2SHidetoshi Shimokawa     u_int tag_id, u_int init_id)
573e9e688e2SHidetoshi Shimokawa {
574a73ff510SHidetoshi Shimokawa 	struct sbp_targ_login *login;
575e9e688e2SHidetoshi Shimokawa 	struct orb_info *orbi;
576e9e688e2SHidetoshi Shimokawa 
577a73ff510SHidetoshi Shimokawa 	login = lstate->sc->logins[init_id];
578a73ff510SHidetoshi Shimokawa 	if (login == NULL) {
57910d3ed64SHidetoshi Shimokawa 		printf("%s: no such login\n", __func__);
580a73ff510SHidetoshi Shimokawa 		return (NULL);
581a73ff510SHidetoshi Shimokawa 	}
582a73ff510SHidetoshi Shimokawa 	STAILQ_FOREACH(orbi, &login->orbs, link)
583a73ff510SHidetoshi Shimokawa 		if (orbi->orb_lo == tag_id)
584e9e688e2SHidetoshi Shimokawa 			goto found;
5859950b741SHidetoshi Shimokawa 	printf("%s: orb not found tag_id=0x%08x init_id=%d\n",
5869950b741SHidetoshi Shimokawa 			 __func__, tag_id, init_id);
587e9e688e2SHidetoshi Shimokawa 	return (NULL);
588e9e688e2SHidetoshi Shimokawa found:
589e9e688e2SHidetoshi Shimokawa 	return (orbi);
590e9e688e2SHidetoshi Shimokawa }
591e9e688e2SHidetoshi Shimokawa 
592e9e688e2SHidetoshi Shimokawa static void
5939950b741SHidetoshi Shimokawa sbp_targ_abort(struct sbp_targ_softc *sc, struct orb_info *orbi)
594e9e688e2SHidetoshi Shimokawa {
595e9e688e2SHidetoshi Shimokawa 	struct orb_info *norbi;
596e9e688e2SHidetoshi Shimokawa 
5979950b741SHidetoshi Shimokawa 	SBP_LOCK(sc);
598e9e688e2SHidetoshi Shimokawa 	for (; orbi != NULL; orbi = norbi) {
5999950b741SHidetoshi Shimokawa 		printf("%s: status=%d ccb=%p\n", __func__, orbi->state, orbi->ccb);
600e9e688e2SHidetoshi Shimokawa 		norbi = STAILQ_NEXT(orbi, link);
601e9e688e2SHidetoshi Shimokawa 		if (orbi->state != ORBI_STATUS_ABORTED) {
602e9e688e2SHidetoshi Shimokawa 			if (orbi->ccb != NULL) {
603e9e688e2SHidetoshi Shimokawa 				orbi->ccb->ccb_h.status = CAM_REQ_ABORTED;
604e9e688e2SHidetoshi Shimokawa 				xpt_done(orbi->ccb);
605e9e688e2SHidetoshi Shimokawa 				orbi->ccb = NULL;
606e9e688e2SHidetoshi Shimokawa 			}
607e9e688e2SHidetoshi Shimokawa 			if (orbi->state <= ORBI_STATUS_ATIO) {
6089950b741SHidetoshi Shimokawa 				sbp_targ_remove_orb_info_locked(orbi->login, orbi);
6094636d244SSean Bruno 				if (debug)
6104636d244SSean Bruno 					printf("%s: free orbi %p\n", __func__, orbi);
611e9e688e2SHidetoshi Shimokawa 				free(orbi, M_SBP_TARG);
6124636d244SSean Bruno 				orbi = NULL;
613e9e688e2SHidetoshi Shimokawa 			} else
614e9e688e2SHidetoshi Shimokawa 				orbi->state = ORBI_STATUS_ABORTED;
615e9e688e2SHidetoshi Shimokawa 		}
616e9e688e2SHidetoshi Shimokawa 	}
6179950b741SHidetoshi Shimokawa 	SBP_UNLOCK(sc);
618e9e688e2SHidetoshi Shimokawa }
619e9e688e2SHidetoshi Shimokawa 
620e9e688e2SHidetoshi Shimokawa static void
621e9e688e2SHidetoshi Shimokawa sbp_targ_free_orbi(struct fw_xfer *xfer)
622e9e688e2SHidetoshi Shimokawa {
623e9e688e2SHidetoshi Shimokawa 	struct orb_info *orbi;
624e9e688e2SHidetoshi Shimokawa 
625e9e688e2SHidetoshi Shimokawa 	if (xfer->resp != 0) {
626e9e688e2SHidetoshi Shimokawa 		/* XXX */
62710d3ed64SHidetoshi Shimokawa 		printf("%s: xfer->resp = %d\n", __func__, xfer->resp);
628e9e688e2SHidetoshi Shimokawa 	}
6294636d244SSean Bruno 	orbi = (struct orb_info *)xfer->sc;
6304636d244SSean Bruno 	if ( orbi->page_table != NULL ) {
6314636d244SSean Bruno 		if (debug)
6324636d244SSean Bruno 			printf("%s:  free orbi->page_table %p\n", __func__, orbi->page_table);
6334636d244SSean Bruno 		free(orbi->page_table, M_SBP_TARG);
6344636d244SSean Bruno 		orbi->page_table = NULL;
6354636d244SSean Bruno 	}
6364636d244SSean Bruno 	if (debug)
6374636d244SSean Bruno 		printf("%s: free orbi %p\n", __func__, orbi);
638e9e688e2SHidetoshi Shimokawa 	free(orbi, M_SBP_TARG);
6394636d244SSean Bruno 	orbi = NULL;
640e9e688e2SHidetoshi Shimokawa 	fw_xfer_free(xfer);
641e9e688e2SHidetoshi Shimokawa }
642e9e688e2SHidetoshi Shimokawa 
643e9e688e2SHidetoshi Shimokawa static void
644e9e688e2SHidetoshi Shimokawa sbp_targ_status_FIFO(struct orb_info *orbi,
64503161bbcSDoug Rabson     uint32_t fifo_hi, uint32_t fifo_lo, int dequeue)
646e9e688e2SHidetoshi Shimokawa {
647e9e688e2SHidetoshi Shimokawa 	struct fw_xfer *xfer;
648e9e688e2SHidetoshi Shimokawa 
649e9e688e2SHidetoshi Shimokawa 	if (dequeue)
650a73ff510SHidetoshi Shimokawa 		sbp_targ_remove_orb_info(orbi->login, orbi);
651e9e688e2SHidetoshi Shimokawa 
652e9e688e2SHidetoshi Shimokawa 	xfer = fwmem_write_block(orbi->fwdev, (void *)orbi,
6534636d244SSean Bruno 	    /*spd*/FWSPD_S400, fifo_hi, fifo_lo,
65403161bbcSDoug Rabson 	    sizeof(uint32_t) * (orbi->status.len + 1), (char *)&orbi->status,
655e9e688e2SHidetoshi Shimokawa 	    sbp_targ_free_orbi);
656e9e688e2SHidetoshi Shimokawa 
657e9e688e2SHidetoshi Shimokawa 	if (xfer == NULL) {
658e9e688e2SHidetoshi Shimokawa 		/* XXX */
65910d3ed64SHidetoshi Shimokawa 		printf("%s: xfer == NULL\n", __func__);
660e9e688e2SHidetoshi Shimokawa 	}
661e9e688e2SHidetoshi Shimokawa }
662e9e688e2SHidetoshi Shimokawa 
6634636d244SSean Bruno /*
6644636d244SSean Bruno  * Generate the appropriate CAM status for the
6654636d244SSean Bruno  * target.
6664636d244SSean Bruno  */
667e9e688e2SHidetoshi Shimokawa static void
668e9e688e2SHidetoshi Shimokawa sbp_targ_send_status(struct orb_info *orbi, union ccb *ccb)
669e9e688e2SHidetoshi Shimokawa {
670e9e688e2SHidetoshi Shimokawa 	struct sbp_status *sbp_status;
671ea47b6c8SMatt Jacob #if	0
6729950b741SHidetoshi Shimokawa 	struct orb_info *norbi;
673ea47b6c8SMatt Jacob #endif
674e9e688e2SHidetoshi Shimokawa 
675e9e688e2SHidetoshi Shimokawa 	sbp_status = &orbi->status;
676e9e688e2SHidetoshi Shimokawa 
677e9e688e2SHidetoshi Shimokawa 	orbi->state = ORBI_STATUS_STATUS;
678e9e688e2SHidetoshi Shimokawa 
679e9e688e2SHidetoshi Shimokawa 	sbp_status->resp = 0; /* XXX */
680e9e688e2SHidetoshi Shimokawa 	sbp_status->status = 0; /* XXX */
681e9e688e2SHidetoshi Shimokawa 	sbp_status->dead = 0; /* XXX */
682e9e688e2SHidetoshi Shimokawa 
6834636d244SSean Bruno 	ccb->ccb_h.status= CAM_REQ_CMP;
6844636d244SSean Bruno 
685e9e688e2SHidetoshi Shimokawa 	switch (ccb->csio.scsi_status) {
686e9e688e2SHidetoshi Shimokawa 	case SCSI_STATUS_OK:
687e9e688e2SHidetoshi Shimokawa 		if (debug)
68810d3ed64SHidetoshi Shimokawa 			printf("%s: STATUS_OK\n", __func__);
689e9e688e2SHidetoshi Shimokawa 		sbp_status->len = 1;
690e9e688e2SHidetoshi Shimokawa 		break;
691e9e688e2SHidetoshi Shimokawa 	case SCSI_STATUS_CHECK_COND:
6924636d244SSean Bruno 		if (debug)
6934636d244SSean Bruno 			printf("%s: STATUS SCSI_STATUS_CHECK_COND\n", __func__);
6944636d244SSean Bruno 		goto process_scsi_status;
695e9e688e2SHidetoshi Shimokawa 	case SCSI_STATUS_BUSY:
6964636d244SSean Bruno 		if (debug)
6974636d244SSean Bruno 			printf("%s: STATUS SCSI_STATUS_BUSY\n", __func__);
6984636d244SSean Bruno 		goto process_scsi_status;
699e9e688e2SHidetoshi Shimokawa 	case SCSI_STATUS_CMD_TERMINATED:
7004636d244SSean Bruno process_scsi_status:
701e9e688e2SHidetoshi Shimokawa 	{
702e9e688e2SHidetoshi Shimokawa 		struct sbp_cmd_status *sbp_cmd_status;
703e9e688e2SHidetoshi Shimokawa 		struct scsi_sense_data *sense;
7041cc052e8SKenneth D. Merry 		int error_code, sense_key, asc, ascq;
7051cc052e8SKenneth D. Merry 		uint8_t stream_bits;
7061cc052e8SKenneth D. Merry 		uint8_t sks[3];
7071cc052e8SKenneth D. Merry 		uint64_t info;
7081cc052e8SKenneth D. Merry 		int64_t sinfo;
7091cc052e8SKenneth D. Merry 		int sense_len;
710e9e688e2SHidetoshi Shimokawa 
711e9e688e2SHidetoshi Shimokawa 		sbp_cmd_status = (struct sbp_cmd_status *)&sbp_status->data[0];
712e9e688e2SHidetoshi Shimokawa 		sbp_cmd_status->status = ccb->csio.scsi_status;
713e9e688e2SHidetoshi Shimokawa 		sense = &ccb->csio.sense_data;
714e9e688e2SHidetoshi Shimokawa 
7159950b741SHidetoshi Shimokawa #if 0		/* XXX What we should do? */
7169950b741SHidetoshi Shimokawa #if 0
7179950b741SHidetoshi Shimokawa 		sbp_targ_abort(orbi->sc, STAILQ_NEXT(orbi, link));
7189950b741SHidetoshi Shimokawa #else
7199950b741SHidetoshi Shimokawa 		norbi = STAILQ_NEXT(orbi, link);
7209950b741SHidetoshi Shimokawa 		while (norbi) {
7219950b741SHidetoshi Shimokawa 			printf("%s: status=%d\n", __func__, norbi->state);
7229950b741SHidetoshi Shimokawa 			if (norbi->ccb != NULL) {
7239950b741SHidetoshi Shimokawa 				norbi->ccb->ccb_h.status = CAM_REQ_ABORTED;
7249950b741SHidetoshi Shimokawa 				xpt_done(norbi->ccb);
7259950b741SHidetoshi Shimokawa 				norbi->ccb = NULL;
7269950b741SHidetoshi Shimokawa 			}
7279950b741SHidetoshi Shimokawa 			sbp_targ_remove_orb_info_locked(orbi->login, norbi);
7289950b741SHidetoshi Shimokawa 			norbi = STAILQ_NEXT(norbi, link);
7299950b741SHidetoshi Shimokawa 			free(norbi, M_SBP_TARG);
7309950b741SHidetoshi Shimokawa 		}
7319950b741SHidetoshi Shimokawa #endif
7329950b741SHidetoshi Shimokawa #endif
733e9e688e2SHidetoshi Shimokawa 
7341cc052e8SKenneth D. Merry 		sense_len = ccb->csio.sense_len - ccb->csio.sense_resid;
7351cc052e8SKenneth D. Merry 		scsi_extract_sense_len(sense, sense_len, &error_code,
7361cc052e8SKenneth D. Merry 		    &sense_key, &asc, &ascq, /*show_errors*/ 0);
7371cc052e8SKenneth D. Merry 
7381cc052e8SKenneth D. Merry 		switch (error_code) {
7391cc052e8SKenneth D. Merry 		case SSD_CURRENT_ERROR:
7401cc052e8SKenneth D. Merry 		case SSD_DESC_CURRENT_ERROR:
741e9e688e2SHidetoshi Shimokawa 			sbp_cmd_status->sfmt = SBP_SFMT_CURR;
7421cc052e8SKenneth D. Merry 			break;
7431cc052e8SKenneth D. Merry 		default:
744e9e688e2SHidetoshi Shimokawa 			sbp_cmd_status->sfmt = SBP_SFMT_DEFER;
7451cc052e8SKenneth D. Merry 			break;
7461cc052e8SKenneth D. Merry 		}
747e9e688e2SHidetoshi Shimokawa 
7481cc052e8SKenneth D. Merry 		if (scsi_get_sense_info(sense, sense_len, SSD_DESC_INFO, &info,
7491cc052e8SKenneth D. Merry 					&sinfo) == 0) {
7501cc052e8SKenneth D. Merry 			uint32_t info_trunc;
7511cc052e8SKenneth D. Merry 			sbp_cmd_status->valid = 1;
7521cc052e8SKenneth D. Merry 			info_trunc = info;
753e9e688e2SHidetoshi Shimokawa 
7541cc052e8SKenneth D. Merry 			sbp_cmd_status->info = htobe32(info_trunc);
7551cc052e8SKenneth D. Merry 		} else {
7561cc052e8SKenneth D. Merry 			sbp_cmd_status->valid = 0;
7571cc052e8SKenneth D. Merry 		}
758e9e688e2SHidetoshi Shimokawa 
7591cc052e8SKenneth D. Merry 		sbp_cmd_status->s_key = sense_key;
7601cc052e8SKenneth D. Merry 
7611cc052e8SKenneth D. Merry 		if (scsi_get_stream_info(sense, sense_len, NULL,
7621cc052e8SKenneth D. Merry 					 &stream_bits) == 0) {
7631cc052e8SKenneth D. Merry 			sbp_cmd_status->mark =
7641cc052e8SKenneth D. Merry 			    (stream_bits & SSD_FILEMARK) ? 1 : 0;
7651cc052e8SKenneth D. Merry 			sbp_cmd_status->eom =
7661cc052e8SKenneth D. Merry 			    (stream_bits & SSD_EOM) ? 1 : 0;
7671cc052e8SKenneth D. Merry 			sbp_cmd_status->ill_len =
7681cc052e8SKenneth D. Merry 			    (stream_bits & SSD_ILI) ? 1 : 0;
7691cc052e8SKenneth D. Merry 		} else {
7701cc052e8SKenneth D. Merry 			sbp_cmd_status->mark = 0;
7711cc052e8SKenneth D. Merry 			sbp_cmd_status->eom = 0;
7721cc052e8SKenneth D. Merry 			sbp_cmd_status->ill_len = 0;
7731cc052e8SKenneth D. Merry 		}
7741cc052e8SKenneth D. Merry 
7751cc052e8SKenneth D. Merry 
776e9e688e2SHidetoshi Shimokawa 		/* add_sense_code(_qual), info, cmd_spec_info */
777e9e688e2SHidetoshi Shimokawa 		sbp_status->len = 4;
7781cc052e8SKenneth D. Merry 
7791cc052e8SKenneth D. Merry 		if (scsi_get_sense_info(sense, sense_len, SSD_DESC_COMMAND,
7801cc052e8SKenneth D. Merry 					&info, &sinfo) == 0) {
7811cc052e8SKenneth D. Merry 			uint32_t cmdspec_trunc;
7821cc052e8SKenneth D. Merry 
7831cc052e8SKenneth D. Merry 			cmdspec_trunc = info;
7841cc052e8SKenneth D. Merry 
7851cc052e8SKenneth D. Merry 			sbp_cmd_status->cdb = htobe32(cmdspec_trunc);
7861cc052e8SKenneth D. Merry 		}
7871cc052e8SKenneth D. Merry 
7881cc052e8SKenneth D. Merry 		sbp_cmd_status->s_code = asc;
7891cc052e8SKenneth D. Merry 		sbp_cmd_status->s_qlfr = ascq;
7901cc052e8SKenneth D. Merry 
7911cc052e8SKenneth D. Merry 		if (scsi_get_sense_info(sense, sense_len, SSD_DESC_FRU, &info,
7921cc052e8SKenneth D. Merry 					&sinfo) == 0) {
7931cc052e8SKenneth D. Merry 			sbp_cmd_status->fru = (uint8_t)info;
794e9e688e2SHidetoshi Shimokawa 			sbp_status->len = 5;
7951cc052e8SKenneth D. Merry 		} else {
7961cc052e8SKenneth D. Merry 			sbp_cmd_status->fru = 0;
7971cc052e8SKenneth D. Merry 		}
798e9e688e2SHidetoshi Shimokawa 
7991cc052e8SKenneth D. Merry 		if (scsi_get_sks(sense, sense_len, sks) == 0) {
8001cc052e8SKenneth D. Merry 			bcopy(sks, &sbp_cmd_status->s_keydep[0], sizeof(sks));
8011cc052e8SKenneth D. Merry 			sbp_status->len = 5;
8024636d244SSean Bruno 			ccb->ccb_h.status |= CAM_SENT_SENSE;
8031cc052e8SKenneth D. Merry 		}
804e9e688e2SHidetoshi Shimokawa 
805e9e688e2SHidetoshi Shimokawa 		break;
806e9e688e2SHidetoshi Shimokawa 	}
807e9e688e2SHidetoshi Shimokawa 	default:
80810d3ed64SHidetoshi Shimokawa 		printf("%s: unknown scsi status 0x%x\n", __func__,
809e9e688e2SHidetoshi Shimokawa 		    sbp_status->status);
810e9e688e2SHidetoshi Shimokawa 	}
811e9e688e2SHidetoshi Shimokawa 
8129950b741SHidetoshi Shimokawa 
8139950b741SHidetoshi Shimokawa 	sbp_targ_status_FIFO(orbi,
8149950b741SHidetoshi Shimokawa 	    orbi->login->fifo_hi, orbi->login->fifo_lo, /*dequeue*/1);
815e9e688e2SHidetoshi Shimokawa }
816e9e688e2SHidetoshi Shimokawa 
8174636d244SSean Bruno /*
8184636d244SSean Bruno  * Invoked as a callback handler from fwmem_read/write_block
8194636d244SSean Bruno  *
8204636d244SSean Bruno  * Process read/write of initiator address space
8214636d244SSean Bruno  * completion and pass status onto the backend target.
8224636d244SSean Bruno  * If this is a partial read/write for a CCB then
8234636d244SSean Bruno  * we decrement the orbi's refcount to indicate
8244636d244SSean Bruno  * the status of the read/write is complete
8254636d244SSean Bruno  */
826e9e688e2SHidetoshi Shimokawa static void
827e9e688e2SHidetoshi Shimokawa sbp_targ_cam_done(struct fw_xfer *xfer)
828e9e688e2SHidetoshi Shimokawa {
829e9e688e2SHidetoshi Shimokawa 	struct orb_info *orbi;
830e9e688e2SHidetoshi Shimokawa 	union ccb *ccb;
831e9e688e2SHidetoshi Shimokawa 
832e9e688e2SHidetoshi Shimokawa 	orbi = (struct orb_info *)xfer->sc;
833e9e688e2SHidetoshi Shimokawa 
8344636d244SSean Bruno 	if (debug)
83510d3ed64SHidetoshi Shimokawa 		printf("%s: resp=%d refcount=%d\n", __func__,
836e9e688e2SHidetoshi Shimokawa 			xfer->resp, orbi->refcount);
837e9e688e2SHidetoshi Shimokawa 
838e9e688e2SHidetoshi Shimokawa 	if (xfer->resp != 0) {
83910d3ed64SHidetoshi Shimokawa 		printf("%s: xfer->resp = %d\n", __func__, xfer->resp);
840e9e688e2SHidetoshi Shimokawa 		orbi->status.resp = SBP_TRANS_FAIL;
8411398a889SHidetoshi Shimokawa 		orbi->status.status = OBJ_DATA | SBE_TIMEOUT/*XXX*/;
842e9e688e2SHidetoshi Shimokawa 		orbi->status.dead = 1;
8439950b741SHidetoshi Shimokawa 		sbp_targ_abort(orbi->sc, STAILQ_NEXT(orbi, link));
844e9e688e2SHidetoshi Shimokawa 	}
845e9e688e2SHidetoshi Shimokawa 
846e9e688e2SHidetoshi Shimokawa 	orbi->refcount --;
847e9e688e2SHidetoshi Shimokawa 
848e9e688e2SHidetoshi Shimokawa 	ccb = orbi->ccb;
849e9e688e2SHidetoshi Shimokawa 	if (orbi->refcount == 0) {
8509950b741SHidetoshi Shimokawa 		orbi->ccb = NULL;
851e9e688e2SHidetoshi Shimokawa 		if (orbi->state == ORBI_STATUS_ABORTED) {
852e9e688e2SHidetoshi Shimokawa 			if (debug)
85310d3ed64SHidetoshi Shimokawa 				printf("%s: orbi aborted\n", __func__);
854a73ff510SHidetoshi Shimokawa 			sbp_targ_remove_orb_info(orbi->login, orbi);
8554636d244SSean Bruno 			if (orbi->page_table != NULL) {
8564636d244SSean Bruno 				if (debug)
8574636d244SSean Bruno 					printf("%s: free orbi->page_table %p\n",
8584636d244SSean Bruno 						__func__, orbi->page_table);
859e9e688e2SHidetoshi Shimokawa 				free(orbi->page_table, M_SBP_TARG);
8604636d244SSean Bruno 			}
8614636d244SSean Bruno 			if (debug)
8624636d244SSean Bruno 				printf("%s: free orbi %p\n", __func__, orbi);
863e9e688e2SHidetoshi Shimokawa 			free(orbi, M_SBP_TARG);
8644636d244SSean Bruno 			orbi = NULL;
8654636d244SSean Bruno 		} else if (orbi->status.resp == ORBI_STATUS_NONE) {
8664636d244SSean Bruno 			if ((ccb->ccb_h.flags & CAM_SEND_STATUS) != 0) {
8674636d244SSean Bruno 				if (debug)
8684636d244SSean Bruno 					printf("%s: CAM_SEND_STATUS set %0x\n", __func__, ccb->ccb_h.flags);
869e9e688e2SHidetoshi Shimokawa 				sbp_targ_send_status(orbi, ccb);
8704636d244SSean Bruno 			} else {
8714636d244SSean Bruno 				if (debug)
8724636d244SSean Bruno 					printf("%s: CAM_SEND_STATUS not set %0x\n", __func__, ccb->ccb_h.flags);
873e9e688e2SHidetoshi Shimokawa 				ccb->ccb_h.status = CAM_REQ_CMP;
8744636d244SSean Bruno 			}
8759950b741SHidetoshi Shimokawa 			SBP_LOCK(orbi->sc);
876e9e688e2SHidetoshi Shimokawa 			xpt_done(ccb);
8779950b741SHidetoshi Shimokawa 			SBP_UNLOCK(orbi->sc);
878e9e688e2SHidetoshi Shimokawa 		} else {
879e9e688e2SHidetoshi Shimokawa 			orbi->status.len = 1;
880e9e688e2SHidetoshi Shimokawa 			sbp_targ_status_FIFO(orbi,
881a73ff510SHidetoshi Shimokawa 		    	    orbi->login->fifo_hi, orbi->login->fifo_lo,
882e9e688e2SHidetoshi Shimokawa 			    /*dequeue*/1);
883e9e688e2SHidetoshi Shimokawa 			ccb->ccb_h.status = CAM_REQ_ABORTED;
8849950b741SHidetoshi Shimokawa 			SBP_LOCK(orbi->sc);
885e9e688e2SHidetoshi Shimokawa 			xpt_done(ccb);
8869950b741SHidetoshi Shimokawa 			SBP_UNLOCK(orbi->sc);
887e9e688e2SHidetoshi Shimokawa 		}
888e9e688e2SHidetoshi Shimokawa 	}
889e9e688e2SHidetoshi Shimokawa 
890e9e688e2SHidetoshi Shimokawa 	fw_xfer_free(xfer);
891e9e688e2SHidetoshi Shimokawa }
892e9e688e2SHidetoshi Shimokawa 
893e9e688e2SHidetoshi Shimokawa static cam_status
894e9e688e2SHidetoshi Shimokawa sbp_targ_abort_ccb(struct sbp_targ_softc *sc, union ccb *ccb)
895e9e688e2SHidetoshi Shimokawa {
896e9e688e2SHidetoshi Shimokawa 	union ccb *accb;
897e9e688e2SHidetoshi Shimokawa 	struct sbp_targ_lstate *lstate;
898e9e688e2SHidetoshi Shimokawa 	struct ccb_hdr_slist *list;
899e9e688e2SHidetoshi Shimokawa 	struct ccb_hdr *curelm;
900e9e688e2SHidetoshi Shimokawa 	int found;
901e9e688e2SHidetoshi Shimokawa 	cam_status status;
902e9e688e2SHidetoshi Shimokawa 
903e9e688e2SHidetoshi Shimokawa 	status = sbp_targ_find_devs(sc, ccb, &lstate, 0);
904e9e688e2SHidetoshi Shimokawa 	if (status != CAM_REQ_CMP)
905e9e688e2SHidetoshi Shimokawa 		return (status);
906e9e688e2SHidetoshi Shimokawa 
907e9e688e2SHidetoshi Shimokawa 	accb = ccb->cab.abort_ccb;
908e9e688e2SHidetoshi Shimokawa 
909e9e688e2SHidetoshi Shimokawa 	if (accb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO)
910e9e688e2SHidetoshi Shimokawa 		list = &lstate->accept_tios;
911b79dc8a8SKenneth D. Merry 	else if (accb->ccb_h.func_code == XPT_IMMEDIATE_NOTIFY)
912e9e688e2SHidetoshi Shimokawa 		list = &lstate->immed_notifies;
913e9e688e2SHidetoshi Shimokawa 	else
914e9e688e2SHidetoshi Shimokawa 		return (CAM_UA_ABORT);
915e9e688e2SHidetoshi Shimokawa 
916e9e688e2SHidetoshi Shimokawa 	curelm = SLIST_FIRST(list);
917e9e688e2SHidetoshi Shimokawa 	found = 0;
918e9e688e2SHidetoshi Shimokawa 	if (curelm == &accb->ccb_h) {
919e9e688e2SHidetoshi Shimokawa 		found = 1;
920e9e688e2SHidetoshi Shimokawa 		SLIST_REMOVE_HEAD(list, sim_links.sle);
921e9e688e2SHidetoshi Shimokawa 	} else {
922e9e688e2SHidetoshi Shimokawa 		while(curelm != NULL) {
923e9e688e2SHidetoshi Shimokawa 			struct ccb_hdr *nextelm;
924e9e688e2SHidetoshi Shimokawa 
925e9e688e2SHidetoshi Shimokawa 			nextelm = SLIST_NEXT(curelm, sim_links.sle);
926e9e688e2SHidetoshi Shimokawa 			if (nextelm == &accb->ccb_h) {
927e9e688e2SHidetoshi Shimokawa 				found = 1;
928e9e688e2SHidetoshi Shimokawa 				SLIST_NEXT(curelm, sim_links.sle) =
929e9e688e2SHidetoshi Shimokawa 				    SLIST_NEXT(nextelm, sim_links.sle);
930e9e688e2SHidetoshi Shimokawa 				break;
931e9e688e2SHidetoshi Shimokawa 			}
932e9e688e2SHidetoshi Shimokawa 			curelm = nextelm;
933e9e688e2SHidetoshi Shimokawa 		}
934e9e688e2SHidetoshi Shimokawa 	}
935e9e688e2SHidetoshi Shimokawa 	if (found) {
936e9e688e2SHidetoshi Shimokawa 		accb->ccb_h.status = CAM_REQ_ABORTED;
937e9e688e2SHidetoshi Shimokawa 		xpt_done(accb);
938e9e688e2SHidetoshi Shimokawa 		return (CAM_REQ_CMP);
939e9e688e2SHidetoshi Shimokawa 	}
94010d3ed64SHidetoshi Shimokawa 	printf("%s: not found\n", __func__);
941e9e688e2SHidetoshi Shimokawa 	return (CAM_PATH_INVALID);
942e9e688e2SHidetoshi Shimokawa }
943e9e688e2SHidetoshi Shimokawa 
9444636d244SSean Bruno /*
9454636d244SSean Bruno  * directly execute a read or write to the initiator
9464636d244SSean Bruno  * address space and set hand(sbp_targ_cam_done) to
9474636d244SSean Bruno  * process the completion from the SIM to the target.
9484636d244SSean Bruno  * set orbi->refcount to inidicate that a read/write
9494636d244SSean Bruno  * is inflight to/from the initiator.
9504636d244SSean Bruno  */
951e9e688e2SHidetoshi Shimokawa static void
952e9e688e2SHidetoshi Shimokawa sbp_targ_xfer_buf(struct orb_info *orbi, u_int offset,
95303161bbcSDoug Rabson     uint16_t dst_hi, uint32_t dst_lo, u_int size,
954e9e688e2SHidetoshi Shimokawa     void (*hand)(struct fw_xfer *))
955e9e688e2SHidetoshi Shimokawa {
956e9e688e2SHidetoshi Shimokawa 	struct fw_xfer *xfer;
957e9e688e2SHidetoshi Shimokawa 	u_int len, ccb_dir, off = 0;
958e9e688e2SHidetoshi Shimokawa 	char *ptr;
959e9e688e2SHidetoshi Shimokawa 
960a73ff510SHidetoshi Shimokawa 	if (debug > 1)
96110d3ed64SHidetoshi Shimokawa 		printf("%s: offset=%d size=%d\n", __func__, offset, size);
962e9e688e2SHidetoshi Shimokawa 	ccb_dir = orbi->ccb->ccb_h.flags & CAM_DIR_MASK;
963e9e688e2SHidetoshi Shimokawa 	ptr = (char *)orbi->ccb->csio.data_ptr + offset;
964e9e688e2SHidetoshi Shimokawa 
965e9e688e2SHidetoshi Shimokawa 	while (size > 0) {
966e9e688e2SHidetoshi Shimokawa 		/* XXX assume dst_lo + off doesn't overflow */
967e9e688e2SHidetoshi Shimokawa 		len = MIN(size, 2048 /* XXX */);
968e9e688e2SHidetoshi Shimokawa 		size -= len;
969e9e688e2SHidetoshi Shimokawa 		orbi->refcount ++;
9704636d244SSean Bruno 		if (ccb_dir == CAM_DIR_OUT) {
9714636d244SSean Bruno 			if (debug)
9724636d244SSean Bruno 				printf("%s: CAM_DIR_OUT --> read block in?\n",__func__);
973e9e688e2SHidetoshi Shimokawa 			xfer = fwmem_read_block(orbi->fwdev,
9744636d244SSean Bruno 			   (void *)orbi, /*spd*/FWSPD_S400,
975e9e688e2SHidetoshi Shimokawa 			    dst_hi, dst_lo + off, len,
976e9e688e2SHidetoshi Shimokawa 			    ptr + off, hand);
9774636d244SSean Bruno 		} else {
9784636d244SSean Bruno 			if (debug)
9794636d244SSean Bruno 				printf("%s: CAM_DIR_IN --> write block out?\n",__func__);
980e9e688e2SHidetoshi Shimokawa 			xfer = fwmem_write_block(orbi->fwdev,
9814636d244SSean Bruno 			   (void *)orbi, /*spd*/FWSPD_S400,
982e9e688e2SHidetoshi Shimokawa 			    dst_hi, dst_lo + off, len,
983e9e688e2SHidetoshi Shimokawa 			    ptr + off, hand);
9844636d244SSean Bruno 		}
985e9e688e2SHidetoshi Shimokawa 		if (xfer == NULL) {
98610d3ed64SHidetoshi Shimokawa 			printf("%s: xfer == NULL", __func__);
987e9e688e2SHidetoshi Shimokawa 			/* XXX what should we do?? */
988e9e688e2SHidetoshi Shimokawa 			orbi->refcount --;
989e9e688e2SHidetoshi Shimokawa 		}
990e9e688e2SHidetoshi Shimokawa 		off += len;
991e9e688e2SHidetoshi Shimokawa 	}
992e9e688e2SHidetoshi Shimokawa }
993e9e688e2SHidetoshi Shimokawa 
994e9e688e2SHidetoshi Shimokawa static void
995e9e688e2SHidetoshi Shimokawa sbp_targ_pt_done(struct fw_xfer *xfer)
996e9e688e2SHidetoshi Shimokawa {
997e9e688e2SHidetoshi Shimokawa 	struct orb_info *orbi;
9984636d244SSean Bruno 	struct unrestricted_page_table_fmt *pt;
9994636d244SSean Bruno 	uint32_t i;
1000e9e688e2SHidetoshi Shimokawa 
1001e9e688e2SHidetoshi Shimokawa 	orbi = (struct orb_info *)xfer->sc;
10024636d244SSean Bruno 
1003e9e688e2SHidetoshi Shimokawa 	if (orbi->state == ORBI_STATUS_ABORTED) {
1004e9e688e2SHidetoshi Shimokawa 		if (debug)
100510d3ed64SHidetoshi Shimokawa 			printf("%s: orbi aborted\n", __func__);
1006a73ff510SHidetoshi Shimokawa 		sbp_targ_remove_orb_info(orbi->login, orbi);
10074636d244SSean Bruno 		if (debug) {
10084636d244SSean Bruno 			printf("%s: free orbi->page_table %p\n", __func__, orbi->page_table);
10094636d244SSean Bruno 			printf("%s: free orbi %p\n", __func__, orbi);
10104636d244SSean Bruno 		}
1011e9e688e2SHidetoshi Shimokawa 		free(orbi->page_table, M_SBP_TARG);
1012e9e688e2SHidetoshi Shimokawa 		free(orbi, M_SBP_TARG);
10134636d244SSean Bruno 		orbi = NULL;
1014e9e688e2SHidetoshi Shimokawa 		fw_xfer_free(xfer);
1015e9e688e2SHidetoshi Shimokawa 		return;
1016e9e688e2SHidetoshi Shimokawa 	}
1017e9e688e2SHidetoshi Shimokawa 	if (xfer->resp != 0) {
101810d3ed64SHidetoshi Shimokawa 		printf("%s: xfer->resp = %d\n", __func__, xfer->resp);
1019e9e688e2SHidetoshi Shimokawa 		orbi->status.resp = SBP_TRANS_FAIL;
10201398a889SHidetoshi Shimokawa 		orbi->status.status = OBJ_PT | SBE_TIMEOUT/*XXX*/;
1021e9e688e2SHidetoshi Shimokawa 		orbi->status.dead = 1;
1022e9e688e2SHidetoshi Shimokawa 		orbi->status.len = 1;
10239950b741SHidetoshi Shimokawa 		sbp_targ_abort(orbi->sc, STAILQ_NEXT(orbi, link));
1024e9e688e2SHidetoshi Shimokawa 
10254636d244SSean Bruno 		if (debug)
10264636d244SSean Bruno 			printf("%s: free orbi->page_table %p\n", __func__, orbi->page_table);
10274636d244SSean Bruno 
1028e9e688e2SHidetoshi Shimokawa 		sbp_targ_status_FIFO(orbi,
1029a73ff510SHidetoshi Shimokawa 		    orbi->login->fifo_hi, orbi->login->fifo_lo, /*dequeue*/1);
1030e9e688e2SHidetoshi Shimokawa 		free(orbi->page_table, M_SBP_TARG);
10314636d244SSean Bruno 		orbi->page_table = NULL;
1032e9e688e2SHidetoshi Shimokawa 		fw_xfer_free(xfer);
1033e9e688e2SHidetoshi Shimokawa 		return;
1034e9e688e2SHidetoshi Shimokawa 	}
1035e9e688e2SHidetoshi Shimokawa 	orbi->refcount++;
10364636d244SSean Bruno /*
10374636d244SSean Bruno  * Set endianess here so we don't have
10384636d244SSean Bruno  * to deal with is later
10394636d244SSean Bruno  */
10404636d244SSean Bruno 	for (i = 0, pt = orbi->page_table; i < orbi->orb4.data_size; i++, pt++) {
10414636d244SSean Bruno 		pt->segment_len = ntohs(pt->segment_len);
10424636d244SSean Bruno 		if (debug)
10434636d244SSean Bruno 			printf("%s:segment_len = %u\n", __func__,pt->segment_len);
10444636d244SSean Bruno 		pt->segment_base_high = ntohs(pt->segment_base_high);
10454636d244SSean Bruno 		pt->segment_base_low = ntohl(pt->segment_base_low);
1046e9e688e2SHidetoshi Shimokawa 	}
10474636d244SSean Bruno 
10484636d244SSean Bruno 	sbp_targ_xfer_pt(orbi);
10494636d244SSean Bruno 
1050e9e688e2SHidetoshi Shimokawa 	orbi->refcount--;
1051e9e688e2SHidetoshi Shimokawa 	if (orbi->refcount == 0)
105210d3ed64SHidetoshi Shimokawa 		printf("%s: refcount == 0\n", __func__);
1053e9e688e2SHidetoshi Shimokawa 
1054e9e688e2SHidetoshi Shimokawa 	fw_xfer_free(xfer);
1055e9e688e2SHidetoshi Shimokawa 	return;
1056e9e688e2SHidetoshi Shimokawa }
1057e9e688e2SHidetoshi Shimokawa 
10584636d244SSean Bruno static void sbp_targ_xfer_pt(struct orb_info *orbi)
10594636d244SSean Bruno {
10604636d244SSean Bruno 	union ccb *ccb;
10614636d244SSean Bruno 	uint32_t res, offset, len;
10624636d244SSean Bruno 
10634636d244SSean Bruno 	ccb = orbi->ccb;
10644636d244SSean Bruno 	if (debug)
10654636d244SSean Bruno 		printf("%s: dxfer_len=%d\n", __func__, ccb->csio.dxfer_len);
10664636d244SSean Bruno 	res = ccb->csio.dxfer_len;
10674636d244SSean Bruno 	/*
10684636d244SSean Bruno 	 * If the page table required multiple CTIO's to
10694636d244SSean Bruno 	 * complete, then cur_pte is non NULL
10704636d244SSean Bruno 	 * and we need to start from the last position
10714636d244SSean Bruno 	 * If this is the first pass over a page table
10724636d244SSean Bruno 	 * then we just start at the beginning of the page
10734636d244SSean Bruno 	 * table.
10744636d244SSean Bruno 	 *
10754636d244SSean Bruno 	 * Parse the unrestricted page table and figure out where we need
10764636d244SSean Bruno 	 * to shove the data from this read request.
10774636d244SSean Bruno 	 */
10784636d244SSean Bruno 	for (offset = 0, len = 0; (res != 0) && (orbi->cur_pte < orbi->last_pte); offset += len) {
10794636d244SSean Bruno 		len = MIN(orbi->cur_pte->segment_len, res);
10804636d244SSean Bruno 		res -= len;
10814636d244SSean Bruno 		if (debug)
10824636d244SSean Bruno 			printf("%s:page_table: %04x:%08x segment_len(%u) res(%u) len(%u)\n",
10834636d244SSean Bruno 				__func__, orbi->cur_pte->segment_base_high,
10844636d244SSean Bruno 				orbi->cur_pte->segment_base_low,
10854636d244SSean Bruno 				orbi->cur_pte->segment_len,
10864636d244SSean Bruno 				res, len);
10874636d244SSean Bruno 		sbp_targ_xfer_buf(orbi, offset,
10884636d244SSean Bruno 				orbi->cur_pte->segment_base_high,
10894636d244SSean Bruno 				orbi->cur_pte->segment_base_low,
10904636d244SSean Bruno 				len, sbp_targ_cam_done);
10914636d244SSean Bruno 		/*
10924636d244SSean Bruno 		 * If we have only written partially to
10934636d244SSean Bruno 		 * this page table, then we need to save
10944636d244SSean Bruno 		 * our position for the next CTIO.  If we
10954636d244SSean Bruno 		 * have completed the page table, then we
10964636d244SSean Bruno 		 * are safe to move on to the next entry.
10974636d244SSean Bruno 		 */
10984636d244SSean Bruno 		if (len == orbi->cur_pte->segment_len) {
10994636d244SSean Bruno 			orbi->cur_pte++;
11004636d244SSean Bruno 		} else {
11014636d244SSean Bruno 			uint32_t saved_base_low;
11024636d244SSean Bruno 
11034636d244SSean Bruno 			/* Handle transfers that cross a 4GB boundary. */
11044636d244SSean Bruno 			saved_base_low = orbi->cur_pte->segment_base_low;
11054636d244SSean Bruno 			orbi->cur_pte->segment_base_low += len;
11064636d244SSean Bruno 			if (orbi->cur_pte->segment_base_low < saved_base_low)
11074636d244SSean Bruno 				orbi->cur_pte->segment_base_high++;
11084636d244SSean Bruno 
11094636d244SSean Bruno 			orbi->cur_pte->segment_len -= len;
11104636d244SSean Bruno 		}
11114636d244SSean Bruno 	}
11124636d244SSean Bruno 	if (debug) {
11134636d244SSean Bruno 		printf("%s: base_low(%08x) page_table_off(%p) last_block(%u)\n",
11144636d244SSean Bruno 			__func__, orbi->cur_pte->segment_base_low,
11154636d244SSean Bruno 			orbi->cur_pte, orbi->last_block_read);
11164636d244SSean Bruno 	}
11174636d244SSean Bruno 	if (res != 0)
11184636d244SSean Bruno 		printf("Warning - short pt encountered.  "
11194636d244SSean Bruno 			"Could not transfer all data.\n");
11204636d244SSean Bruno 	return;
11214636d244SSean Bruno }
11224636d244SSean Bruno 
11234636d244SSean Bruno /*
11244636d244SSean Bruno  * Create page table in local memory
11254636d244SSean Bruno  * and transfer it from the initiator
11264636d244SSean Bruno  * in order to know where we are supposed
11274636d244SSean Bruno  * to put the data.
11284636d244SSean Bruno  */
11294636d244SSean Bruno 
1130e9e688e2SHidetoshi Shimokawa static void
1131e9e688e2SHidetoshi Shimokawa sbp_targ_fetch_pt(struct orb_info *orbi)
1132e9e688e2SHidetoshi Shimokawa {
1133e9e688e2SHidetoshi Shimokawa 	struct fw_xfer *xfer;
1134e9e688e2SHidetoshi Shimokawa 
11354636d244SSean Bruno 	/*
11364636d244SSean Bruno 	 * Pull in page table from initiator
11374636d244SSean Bruno 	 * and setup for data from our
11384636d244SSean Bruno 	 * backend device.
11394636d244SSean Bruno 	 */
11404636d244SSean Bruno 	if (orbi->page_table == NULL) {
11414636d244SSean Bruno 		orbi->page_table = malloc(orbi->orb4.data_size*
11424636d244SSean Bruno 					  sizeof(struct unrestricted_page_table_fmt),
11434636d244SSean Bruno 					  M_SBP_TARG, M_NOWAIT|M_ZERO);
1144e9e688e2SHidetoshi Shimokawa 		if (orbi->page_table == NULL)
1145e9e688e2SHidetoshi Shimokawa 			goto error;
11464636d244SSean Bruno 		orbi->cur_pte = orbi->page_table;
11474636d244SSean Bruno 		orbi->last_pte = orbi->page_table + orbi->orb4.data_size;
11484636d244SSean Bruno 		orbi->last_block_read = orbi->orb4.data_size;
11494636d244SSean Bruno 		if (debug && orbi->page_table != NULL)
11504636d244SSean Bruno 			printf("%s: malloc'd orbi->page_table(%p), orb4.data_size(%u)\n",
11514636d244SSean Bruno  				__func__, orbi->page_table, orbi->orb4.data_size);
11524636d244SSean Bruno 
11534636d244SSean Bruno 		xfer = fwmem_read_block(orbi->fwdev, (void *)orbi, /*spd*/FWSPD_S400,
11544636d244SSean Bruno 					orbi->data_hi, orbi->data_lo, orbi->orb4.data_size*
11554636d244SSean Bruno 					sizeof(struct unrestricted_page_table_fmt),
1156e9e688e2SHidetoshi Shimokawa 					(void *)orbi->page_table, sbp_targ_pt_done);
11574636d244SSean Bruno 
1158e9e688e2SHidetoshi Shimokawa 		if (xfer != NULL)
1159e9e688e2SHidetoshi Shimokawa 			return;
11604636d244SSean Bruno 	} else {
11614636d244SSean Bruno 		/*
11624636d244SSean Bruno 		 * This is a CTIO for a page table we have
11634636d244SSean Bruno 		 * already malloc'd, so just directly invoke
11644636d244SSean Bruno 		 * the xfer function on the orbi.
11654636d244SSean Bruno 		 */
11664636d244SSean Bruno 		sbp_targ_xfer_pt(orbi);
11674636d244SSean Bruno 		return;
11684636d244SSean Bruno 	}
1169e9e688e2SHidetoshi Shimokawa error:
1170e9e688e2SHidetoshi Shimokawa 	orbi->ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
11714636d244SSean Bruno 	if (debug)
11724636d244SSean Bruno 		printf("%s: free orbi->page_table %p due to xfer == NULL\n", __func__, orbi->page_table);
11734636d244SSean Bruno 	if (orbi->page_table != NULL) {
11744636d244SSean Bruno 		free(orbi->page_table, M_SBP_TARG);
11754636d244SSean Bruno 		orbi->page_table = NULL;
11764636d244SSean Bruno 	}
1177e9e688e2SHidetoshi Shimokawa 	xpt_done(orbi->ccb);
1178e9e688e2SHidetoshi Shimokawa 	return;
1179e9e688e2SHidetoshi Shimokawa }
1180e9e688e2SHidetoshi Shimokawa 
1181e9e688e2SHidetoshi Shimokawa static void
1182e9e688e2SHidetoshi Shimokawa sbp_targ_action1(struct cam_sim *sim, union ccb *ccb)
1183e9e688e2SHidetoshi Shimokawa {
1184e9e688e2SHidetoshi Shimokawa 	struct sbp_targ_softc *sc;
1185e9e688e2SHidetoshi Shimokawa 	struct sbp_targ_lstate *lstate;
1186e9e688e2SHidetoshi Shimokawa 	cam_status status;
1187e9e688e2SHidetoshi Shimokawa 	u_int ccb_dir;
1188e9e688e2SHidetoshi Shimokawa 
1189e9e688e2SHidetoshi Shimokawa 	sc =  (struct sbp_targ_softc *)cam_sim_softc(sim);
1190e9e688e2SHidetoshi Shimokawa 
1191e9e688e2SHidetoshi Shimokawa 	status = sbp_targ_find_devs(sc, ccb, &lstate, TRUE);
1192e9e688e2SHidetoshi Shimokawa 
1193e9e688e2SHidetoshi Shimokawa 	switch (ccb->ccb_h.func_code) {
1194e9e688e2SHidetoshi Shimokawa 	case XPT_CONT_TARGET_IO:
1195e9e688e2SHidetoshi Shimokawa 	{
1196e9e688e2SHidetoshi Shimokawa 		struct orb_info *orbi;
1197e9e688e2SHidetoshi Shimokawa 
1198e9e688e2SHidetoshi Shimokawa 		if (debug)
11999950b741SHidetoshi Shimokawa 			printf("%s: XPT_CONT_TARGET_IO (0x%08x)\n",
12009950b741SHidetoshi Shimokawa 					 __func__, ccb->csio.tag_id);
1201e9e688e2SHidetoshi Shimokawa 
1202e9e688e2SHidetoshi Shimokawa 		if (status != CAM_REQ_CMP) {
1203e9e688e2SHidetoshi Shimokawa 			ccb->ccb_h.status = status;
1204e9e688e2SHidetoshi Shimokawa 			xpt_done(ccb);
1205e9e688e2SHidetoshi Shimokawa 			break;
1206e9e688e2SHidetoshi Shimokawa 		}
1207e9e688e2SHidetoshi Shimokawa 		/* XXX transfer from/to initiator */
1208e9e688e2SHidetoshi Shimokawa 		orbi = sbp_targ_get_orb_info(lstate,
1209e9e688e2SHidetoshi Shimokawa 		    ccb->csio.tag_id, ccb->csio.init_id);
1210e9e688e2SHidetoshi Shimokawa 		if (orbi == NULL) {
1211e9e688e2SHidetoshi Shimokawa 			ccb->ccb_h.status = CAM_REQ_ABORTED; /* XXX */
1212e9e688e2SHidetoshi Shimokawa 			xpt_done(ccb);
1213e9e688e2SHidetoshi Shimokawa 			break;
1214e9e688e2SHidetoshi Shimokawa 		}
1215e9e688e2SHidetoshi Shimokawa 		if (orbi->state == ORBI_STATUS_ABORTED) {
1216e9e688e2SHidetoshi Shimokawa 			if (debug)
121710d3ed64SHidetoshi Shimokawa 				printf("%s: ctio aborted\n", __func__);
12189950b741SHidetoshi Shimokawa 			sbp_targ_remove_orb_info_locked(orbi->login, orbi);
12194636d244SSean Bruno 			if (debug)
12204636d244SSean Bruno 				printf("%s: free orbi %p\n", __func__, orbi);
1221e9e688e2SHidetoshi Shimokawa 			free(orbi, M_SBP_TARG);
12229950b741SHidetoshi Shimokawa 			ccb->ccb_h.status = CAM_REQ_ABORTED;
12239950b741SHidetoshi Shimokawa 			xpt_done(ccb);
1224e9e688e2SHidetoshi Shimokawa 			break;
1225e9e688e2SHidetoshi Shimokawa 		}
1226e9e688e2SHidetoshi Shimokawa 		orbi->state = ORBI_STATUS_CTIO;
1227e9e688e2SHidetoshi Shimokawa 
1228e9e688e2SHidetoshi Shimokawa 		orbi->ccb = ccb;
1229e9e688e2SHidetoshi Shimokawa 		ccb_dir = ccb->ccb_h.flags & CAM_DIR_MASK;
1230e9e688e2SHidetoshi Shimokawa 
1231e9e688e2SHidetoshi Shimokawa 		/* XXX */
1232e9e688e2SHidetoshi Shimokawa 		if (ccb->csio.dxfer_len == 0)
1233e9e688e2SHidetoshi Shimokawa 			ccb_dir = CAM_DIR_NONE;
1234e9e688e2SHidetoshi Shimokawa 
1235e9e688e2SHidetoshi Shimokawa 		/* Sanity check */
1236e9e688e2SHidetoshi Shimokawa 		if (ccb_dir == CAM_DIR_IN && orbi->orb4.dir == 0)
123710d3ed64SHidetoshi Shimokawa 			printf("%s: direction mismatch\n", __func__);
1238e9e688e2SHidetoshi Shimokawa 
1239e9e688e2SHidetoshi Shimokawa 		/* check page table */
1240e9e688e2SHidetoshi Shimokawa 		if (ccb_dir != CAM_DIR_NONE && orbi->orb4.page_table_present) {
1241e9e688e2SHidetoshi Shimokawa 			if (debug)
1242e9e688e2SHidetoshi Shimokawa 				printf("%s: page_table_present\n",
124310d3ed64SHidetoshi Shimokawa 				    __func__);
1244e9e688e2SHidetoshi Shimokawa 			if (orbi->orb4.page_size != 0) {
1245e9e688e2SHidetoshi Shimokawa 				printf("%s: unsupported pagesize %d != 0\n",
124610d3ed64SHidetoshi Shimokawa 			 	    __func__, orbi->orb4.page_size);
1247e9e688e2SHidetoshi Shimokawa 				ccb->ccb_h.status = CAM_REQ_INVALID;
1248e9e688e2SHidetoshi Shimokawa 				xpt_done(ccb);
1249e9e688e2SHidetoshi Shimokawa 				break;
1250e9e688e2SHidetoshi Shimokawa 			}
1251e9e688e2SHidetoshi Shimokawa 			sbp_targ_fetch_pt(orbi);
1252e9e688e2SHidetoshi Shimokawa 			break;
1253e9e688e2SHidetoshi Shimokawa 		}
1254e9e688e2SHidetoshi Shimokawa 
1255e9e688e2SHidetoshi Shimokawa 		/* Sanity check */
12564636d244SSean Bruno 		if (ccb_dir != CAM_DIR_NONE) {
1257e9e688e2SHidetoshi Shimokawa 			sbp_targ_xfer_buf(orbi, 0, orbi->data_hi,
1258e9e688e2SHidetoshi Shimokawa 			    orbi->data_lo,
1259e9e688e2SHidetoshi Shimokawa 			    MIN(orbi->orb4.data_size, ccb->csio.dxfer_len),
1260e9e688e2SHidetoshi Shimokawa 			    sbp_targ_cam_done);
12614636d244SSean Bruno 			if ( orbi->orb4.data_size > ccb->csio.dxfer_len ) {
12624636d244SSean Bruno 				orbi->data_lo += ccb->csio.dxfer_len;
12634636d244SSean Bruno 				orbi->orb4.data_size -= ccb->csio.dxfer_len;
12644636d244SSean Bruno 			}
12654636d244SSean Bruno 		}
1266e9e688e2SHidetoshi Shimokawa 
1267e9e688e2SHidetoshi Shimokawa 		if (ccb_dir == CAM_DIR_NONE) {
12689950b741SHidetoshi Shimokawa 			if ((ccb->ccb_h.flags & CAM_SEND_STATUS) != 0) {
12699950b741SHidetoshi Shimokawa 				/* XXX */
12709950b741SHidetoshi Shimokawa 				SBP_UNLOCK(sc);
1271e9e688e2SHidetoshi Shimokawa 				sbp_targ_send_status(orbi, ccb);
12729950b741SHidetoshi Shimokawa 				SBP_LOCK(sc);
12739950b741SHidetoshi Shimokawa 			}
1274e9e688e2SHidetoshi Shimokawa 			ccb->ccb_h.status = CAM_REQ_CMP;
1275e9e688e2SHidetoshi Shimokawa 			xpt_done(ccb);
1276e9e688e2SHidetoshi Shimokawa 		}
1277e9e688e2SHidetoshi Shimokawa 		break;
1278e9e688e2SHidetoshi Shimokawa 	}
1279e9e688e2SHidetoshi Shimokawa 	case XPT_ACCEPT_TARGET_IO:	/* Add Accept Target IO Resource */
1280e9e688e2SHidetoshi Shimokawa 		if (status != CAM_REQ_CMP) {
1281e9e688e2SHidetoshi Shimokawa 			ccb->ccb_h.status = status;
1282e9e688e2SHidetoshi Shimokawa 			xpt_done(ccb);
1283e9e688e2SHidetoshi Shimokawa 			break;
1284e9e688e2SHidetoshi Shimokawa 		}
1285e9e688e2SHidetoshi Shimokawa 		SLIST_INSERT_HEAD(&lstate->accept_tios, &ccb->ccb_h,
1286e9e688e2SHidetoshi Shimokawa 		    sim_links.sle);
1287e9e688e2SHidetoshi Shimokawa 		ccb->ccb_h.status = CAM_REQ_INPROG;
1288a73ff510SHidetoshi Shimokawa 		if ((lstate->flags & F_ATIO_STARVED) != 0) {
1289a73ff510SHidetoshi Shimokawa 			struct sbp_targ_login *login;
1290a73ff510SHidetoshi Shimokawa 
1291e9e688e2SHidetoshi Shimokawa 			if (debug)
129210d3ed64SHidetoshi Shimokawa 				printf("%s: new atio arrived\n", __func__);
1293a73ff510SHidetoshi Shimokawa 			lstate->flags &= ~F_ATIO_STARVED;
1294a73ff510SHidetoshi Shimokawa 			STAILQ_FOREACH(login, &lstate->logins, link)
1295a73ff510SHidetoshi Shimokawa 				if ((login->flags & F_ATIO_STARVED) != 0) {
1296a73ff510SHidetoshi Shimokawa 					login->flags &= ~F_ATIO_STARVED;
1297a73ff510SHidetoshi Shimokawa 					sbp_targ_fetch_orb(lstate->sc,
1298a73ff510SHidetoshi Shimokawa 					    login->fwdev,
1299a73ff510SHidetoshi Shimokawa 					    login->last_hi, login->last_lo,
1300a73ff510SHidetoshi Shimokawa 					    login, FETCH_CMD);
1301a73ff510SHidetoshi Shimokawa 				}
1302e9e688e2SHidetoshi Shimokawa 		}
1303e9e688e2SHidetoshi Shimokawa 		break;
1304b79dc8a8SKenneth D. Merry 	case XPT_NOTIFY_ACKNOWLEDGE:	/* recycle notify ack */
1305b79dc8a8SKenneth D. Merry 	case XPT_IMMEDIATE_NOTIFY:	/* Add Immediate Notify Resource */
1306e9e688e2SHidetoshi Shimokawa 		if (status != CAM_REQ_CMP) {
1307e9e688e2SHidetoshi Shimokawa 			ccb->ccb_h.status = status;
1308e9e688e2SHidetoshi Shimokawa 			xpt_done(ccb);
1309e9e688e2SHidetoshi Shimokawa 			break;
1310e9e688e2SHidetoshi Shimokawa 		}
1311e9e688e2SHidetoshi Shimokawa 		SLIST_INSERT_HEAD(&lstate->immed_notifies, &ccb->ccb_h,
1312e9e688e2SHidetoshi Shimokawa 		    sim_links.sle);
1313e9e688e2SHidetoshi Shimokawa 		ccb->ccb_h.status = CAM_REQ_INPROG;
1314e9e688e2SHidetoshi Shimokawa 		sbp_targ_send_lstate_events(sc, lstate);
1315e9e688e2SHidetoshi Shimokawa 		break;
1316e9e688e2SHidetoshi Shimokawa 	case XPT_EN_LUN:
1317e9e688e2SHidetoshi Shimokawa 		sbp_targ_en_lun(sc, ccb);
1318e9e688e2SHidetoshi Shimokawa 		xpt_done(ccb);
1319e9e688e2SHidetoshi Shimokawa 		break;
1320e9e688e2SHidetoshi Shimokawa 	case XPT_PATH_INQ:
1321e9e688e2SHidetoshi Shimokawa 	{
1322e9e688e2SHidetoshi Shimokawa 		struct ccb_pathinq *cpi = &ccb->cpi;
1323e9e688e2SHidetoshi Shimokawa 
1324e9e688e2SHidetoshi Shimokawa 		cpi->version_num = 1; /* XXX??? */
1325e9e688e2SHidetoshi Shimokawa 		cpi->hba_inquiry = PI_TAG_ABLE;
1326e9e688e2SHidetoshi Shimokawa 		cpi->target_sprt = PIT_PROCESSOR
1327e9e688e2SHidetoshi Shimokawa 				 | PIT_DISCONNECT
1328e9e688e2SHidetoshi Shimokawa 				 | PIT_TERM_IO;
13294636d244SSean Bruno 		cpi->transport = XPORT_SPI; /* FIXME add XPORT_FW type to cam */
13304636d244SSean Bruno 		cpi->hba_misc = PIM_NOBUSRESET | PIM_NOBUSRESET;
1331e9e688e2SHidetoshi Shimokawa 		cpi->hba_eng_cnt = 0;
1332e9e688e2SHidetoshi Shimokawa 		cpi->max_target = 7; /* XXX */
1333e9e688e2SHidetoshi Shimokawa 		cpi->max_lun = MAX_LUN - 1;
1334e9e688e2SHidetoshi Shimokawa 		cpi->initiator_id = 7; /* XXX */
1335e9e688e2SHidetoshi Shimokawa 		cpi->bus_id = sim->bus_id;
1336e9e688e2SHidetoshi Shimokawa 		cpi->base_transfer_speed = 400 * 1000 / 8;
1337e9e688e2SHidetoshi Shimokawa 		strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
1338e9e688e2SHidetoshi Shimokawa 		strncpy(cpi->hba_vid, "SBP_TARG", HBA_IDLEN);
1339e9e688e2SHidetoshi Shimokawa 		strncpy(cpi->dev_name, sim->sim_name, DEV_IDLEN);
1340e9e688e2SHidetoshi Shimokawa 		cpi->unit_number = sim->unit_number;
1341e9e688e2SHidetoshi Shimokawa 
1342e9e688e2SHidetoshi Shimokawa 		cpi->ccb_h.status = CAM_REQ_CMP;
1343e9e688e2SHidetoshi Shimokawa 		xpt_done(ccb);
1344e9e688e2SHidetoshi Shimokawa 		break;
1345e9e688e2SHidetoshi Shimokawa 	}
1346e9e688e2SHidetoshi Shimokawa 	case XPT_ABORT:
1347e9e688e2SHidetoshi Shimokawa 	{
1348e9e688e2SHidetoshi Shimokawa 		union ccb *accb = ccb->cab.abort_ccb;
1349e9e688e2SHidetoshi Shimokawa 
1350e9e688e2SHidetoshi Shimokawa 		switch (accb->ccb_h.func_code) {
1351e9e688e2SHidetoshi Shimokawa 		case XPT_ACCEPT_TARGET_IO:
1352b79dc8a8SKenneth D. Merry 		case XPT_IMMEDIATE_NOTIFY:
1353e9e688e2SHidetoshi Shimokawa 			ccb->ccb_h.status = sbp_targ_abort_ccb(sc, ccb);
1354e9e688e2SHidetoshi Shimokawa 			break;
1355e9e688e2SHidetoshi Shimokawa 		case XPT_CONT_TARGET_IO:
1356e9e688e2SHidetoshi Shimokawa 			/* XXX */
1357e9e688e2SHidetoshi Shimokawa 			ccb->ccb_h.status = CAM_UA_ABORT;
1358e9e688e2SHidetoshi Shimokawa 			break;
1359e9e688e2SHidetoshi Shimokawa 		default:
1360e9e688e2SHidetoshi Shimokawa 			printf("%s: aborting unknown function %d\n",
136110d3ed64SHidetoshi Shimokawa 				__func__, accb->ccb_h.func_code);
1362e9e688e2SHidetoshi Shimokawa 			ccb->ccb_h.status = CAM_REQ_INVALID;
1363e9e688e2SHidetoshi Shimokawa 			break;
1364e9e688e2SHidetoshi Shimokawa 		}
1365e9e688e2SHidetoshi Shimokawa 		xpt_done(ccb);
1366e9e688e2SHidetoshi Shimokawa 		break;
1367e9e688e2SHidetoshi Shimokawa 	}
13684636d244SSean Bruno #ifdef CAM_NEW_TRAN_CODE
13694636d244SSean Bruno 	case XPT_SET_TRAN_SETTINGS:
1370e9e688e2SHidetoshi Shimokawa 		ccb->ccb_h.status = CAM_REQ_INVALID;
1371e9e688e2SHidetoshi Shimokawa 		xpt_done(ccb);
1372e9e688e2SHidetoshi Shimokawa 		break;
13734636d244SSean Bruno 	case XPT_GET_TRAN_SETTINGS:
13744636d244SSean Bruno 	{
13754636d244SSean Bruno 		struct ccb_trans_settings *cts = &ccb->cts;
13764636d244SSean Bruno 		struct ccb_trans_settings_scsi *scsi =
13774636d244SSean Bruno 			&cts->proto_specific.scsi;
13784636d244SSean Bruno 		struct ccb_trans_settings_spi *spi =
13794636d244SSean Bruno 			&cts->xport_specific.spi;
13804636d244SSean Bruno 
13814636d244SSean Bruno 		cts->protocol = PROTO_SCSI;
13824636d244SSean Bruno 		cts->protocol_version = SCSI_REV_2;
13834636d244SSean Bruno 		cts->transport = XPORT_FW;     /* should have a FireWire */
13844636d244SSean Bruno 		cts->transport_version = 2;
13854636d244SSean Bruno 		spi->valid = CTS_SPI_VALID_DISC;
13864636d244SSean Bruno 		spi->flags = CTS_SPI_FLAGS_DISC_ENB;
13874636d244SSean Bruno 		scsi->valid = CTS_SCSI_VALID_TQ;
13884636d244SSean Bruno 		scsi->flags = CTS_SCSI_FLAGS_TAG_ENB;
13894636d244SSean Bruno #if 0
13904636d244SSean Bruno 		printf("%s:%d:%d XPT_GET_TRAN_SETTINGS:\n",
13914636d244SSean Bruno 			device_get_nameunit(sc->fd.dev),
13924636d244SSean Bruno 			ccb->ccb_h.target_id, ccb->ccb_h.target_lun);
13934636d244SSean Bruno #endif
13944636d244SSean Bruno 		cts->ccb_h.status = CAM_REQ_CMP;
13954636d244SSean Bruno 		xpt_done(ccb);
13964636d244SSean Bruno 		break;
13974636d244SSean Bruno 	}
13984636d244SSean Bruno #endif
13994636d244SSean Bruno 
14004636d244SSean Bruno 	default:
14014636d244SSean Bruno 		printf("%s: unknown function 0x%x\n",
14024636d244SSean Bruno 		    __func__, ccb->ccb_h.func_code);
14034636d244SSean Bruno 		ccb->ccb_h.status = CAM_PROVIDE_FAIL;
14044636d244SSean Bruno 		xpt_done(ccb);
14054636d244SSean Bruno 		break;
1406e9e688e2SHidetoshi Shimokawa 	}
1407e9e688e2SHidetoshi Shimokawa 	return;
1408e9e688e2SHidetoshi Shimokawa }
1409e9e688e2SHidetoshi Shimokawa 
1410e9e688e2SHidetoshi Shimokawa static void
1411e9e688e2SHidetoshi Shimokawa sbp_targ_action(struct cam_sim *sim, union ccb *ccb)
1412e9e688e2SHidetoshi Shimokawa {
1413e9e688e2SHidetoshi Shimokawa 	int s;
1414e9e688e2SHidetoshi Shimokawa 
1415e9e688e2SHidetoshi Shimokawa 	s = splfw();
1416e9e688e2SHidetoshi Shimokawa 	sbp_targ_action1(sim, ccb);
1417e9e688e2SHidetoshi Shimokawa 	splx(s);
1418e9e688e2SHidetoshi Shimokawa }
1419e9e688e2SHidetoshi Shimokawa 
1420e9e688e2SHidetoshi Shimokawa static void
1421e9e688e2SHidetoshi Shimokawa sbp_targ_poll(struct cam_sim *sim)
1422e9e688e2SHidetoshi Shimokawa {
1423e9e688e2SHidetoshi Shimokawa 	/* XXX */
1424e9e688e2SHidetoshi Shimokawa 	return;
1425e9e688e2SHidetoshi Shimokawa }
1426e9e688e2SHidetoshi Shimokawa 
1427e9e688e2SHidetoshi Shimokawa static void
1428e9e688e2SHidetoshi Shimokawa sbp_targ_cmd_handler(struct fw_xfer *xfer)
1429e9e688e2SHidetoshi Shimokawa {
1430e9e688e2SHidetoshi Shimokawa 	struct fw_pkt *fp;
143103161bbcSDoug Rabson 	uint32_t *orb;
1432e9e688e2SHidetoshi Shimokawa 	struct corb4 *orb4;
1433e9e688e2SHidetoshi Shimokawa 	struct orb_info *orbi;
1434e9e688e2SHidetoshi Shimokawa 	struct ccb_accept_tio *atio;
1435e9e688e2SHidetoshi Shimokawa 	u_char *bytes;
1436e9e688e2SHidetoshi Shimokawa 	int i;
1437e9e688e2SHidetoshi Shimokawa 
1438e9e688e2SHidetoshi Shimokawa 	orbi = (struct orb_info *)xfer->sc;
1439e9e688e2SHidetoshi Shimokawa 	if (xfer->resp != 0) {
144010d3ed64SHidetoshi Shimokawa 		printf("%s: xfer->resp = %d\n", __func__, xfer->resp);
1441e9e688e2SHidetoshi Shimokawa 		orbi->status.resp = SBP_TRANS_FAIL;
14421398a889SHidetoshi Shimokawa 		orbi->status.status = OBJ_ORB | SBE_TIMEOUT/*XXX*/;
1443e9e688e2SHidetoshi Shimokawa 		orbi->status.dead = 1;
1444e9e688e2SHidetoshi Shimokawa 		orbi->status.len = 1;
14459950b741SHidetoshi Shimokawa 		sbp_targ_abort(orbi->sc, STAILQ_NEXT(orbi, link));
1446e9e688e2SHidetoshi Shimokawa 
1447e9e688e2SHidetoshi Shimokawa 		sbp_targ_status_FIFO(orbi,
1448a73ff510SHidetoshi Shimokawa 		    orbi->login->fifo_hi, orbi->login->fifo_lo, /*dequeue*/1);
1449e9e688e2SHidetoshi Shimokawa 		fw_xfer_free(xfer);
1450e9e688e2SHidetoshi Shimokawa 		return;
1451e9e688e2SHidetoshi Shimokawa 	}
1452e9e688e2SHidetoshi Shimokawa 	fp = &xfer->recv.hdr;
1453e9e688e2SHidetoshi Shimokawa 
14549950b741SHidetoshi Shimokawa 	atio = orbi->atio;
14559950b741SHidetoshi Shimokawa 
1456e9e688e2SHidetoshi Shimokawa 	if (orbi->state == ORBI_STATUS_ABORTED) {
145710d3ed64SHidetoshi Shimokawa 		printf("%s: aborted\n", __func__);
1458a73ff510SHidetoshi Shimokawa 		sbp_targ_remove_orb_info(orbi->login, orbi);
1459e9e688e2SHidetoshi Shimokawa 		free(orbi, M_SBP_TARG);
14609950b741SHidetoshi Shimokawa 		atio->ccb_h.status = CAM_REQ_ABORTED;
14619950b741SHidetoshi Shimokawa 		SBP_LOCK(orbi->sc);
14629950b741SHidetoshi Shimokawa 		xpt_done((union ccb*)atio);
14639950b741SHidetoshi Shimokawa 		SBP_UNLOCK(orbi->sc);
1464e9e688e2SHidetoshi Shimokawa 		goto done0;
1465e9e688e2SHidetoshi Shimokawa 	}
1466e9e688e2SHidetoshi Shimokawa 	orbi->state = ORBI_STATUS_ATIO;
1467e9e688e2SHidetoshi Shimokawa 
1468e9e688e2SHidetoshi Shimokawa 	orb = orbi->orb;
1469e9e688e2SHidetoshi Shimokawa 	/* swap payload except SCSI command */
1470e9e688e2SHidetoshi Shimokawa 	for (i = 0; i < 5; i ++)
1471e9e688e2SHidetoshi Shimokawa 		orb[i] = ntohl(orb[i]);
1472e9e688e2SHidetoshi Shimokawa 
1473e9e688e2SHidetoshi Shimokawa 	orb4 = (struct corb4 *)&orb[4];
1474e9e688e2SHidetoshi Shimokawa 	if (orb4->rq_fmt != 0) {
1475e9e688e2SHidetoshi Shimokawa 		/* XXX */
147610d3ed64SHidetoshi Shimokawa 		printf("%s: rq_fmt(%d) != 0\n", __func__, orb4->rq_fmt);
1477e9e688e2SHidetoshi Shimokawa 	}
1478e9e688e2SHidetoshi Shimokawa 
1479e9e688e2SHidetoshi Shimokawa 	atio->ccb_h.target_id = 0; /* XXX */
1480a73ff510SHidetoshi Shimokawa 	atio->ccb_h.target_lun = orbi->login->lstate->lun;
1481e9e688e2SHidetoshi Shimokawa 	atio->sense_len = 0;
14824636d244SSean Bruno 	atio->tag_action = MSG_SIMPLE_TASK;
1483e9e688e2SHidetoshi Shimokawa 	atio->tag_id = orbi->orb_lo;
1484a73ff510SHidetoshi Shimokawa 	atio->init_id = orbi->login->id;
1485a73ff510SHidetoshi Shimokawa 
14865e63cdb4SAlexander Motin 	atio->ccb_h.flags |= CAM_TAG_ACTION_VALID;
14879950b741SHidetoshi Shimokawa 	bytes = (u_char *)&orb[5];
1488e9e688e2SHidetoshi Shimokawa 	if (debug)
14899950b741SHidetoshi Shimokawa 		printf("%s: %p %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
14909950b741SHidetoshi Shimokawa 		    __func__, (void *)atio,
1491e9e688e2SHidetoshi Shimokawa 		    bytes[0], bytes[1], bytes[2], bytes[3], bytes[4],
1492e9e688e2SHidetoshi Shimokawa 		    bytes[5], bytes[6], bytes[7], bytes[8], bytes[9]);
1493e9e688e2SHidetoshi Shimokawa 	switch (bytes[0] >> 5) {
1494e9e688e2SHidetoshi Shimokawa 	case 0:
1495e9e688e2SHidetoshi Shimokawa 		atio->cdb_len = 6;
1496e9e688e2SHidetoshi Shimokawa 		break;
1497e9e688e2SHidetoshi Shimokawa 	case 1:
1498e9e688e2SHidetoshi Shimokawa 	case 2:
1499e9e688e2SHidetoshi Shimokawa 		atio->cdb_len = 10;
1500e9e688e2SHidetoshi Shimokawa 		break;
1501e9e688e2SHidetoshi Shimokawa 	case 4:
1502e9e688e2SHidetoshi Shimokawa 		atio->cdb_len = 16;
1503e9e688e2SHidetoshi Shimokawa 		break;
1504e9e688e2SHidetoshi Shimokawa 	case 5:
1505e9e688e2SHidetoshi Shimokawa 		atio->cdb_len = 12;
1506e9e688e2SHidetoshi Shimokawa 		break;
1507e9e688e2SHidetoshi Shimokawa 	case 3:
1508e9e688e2SHidetoshi Shimokawa 	default:
1509e9e688e2SHidetoshi Shimokawa 		/* Only copy the opcode. */
1510e9e688e2SHidetoshi Shimokawa 		atio->cdb_len = 1;
1511e9e688e2SHidetoshi Shimokawa 		printf("Reserved or VU command code type encountered\n");
1512e9e688e2SHidetoshi Shimokawa 		break;
1513e9e688e2SHidetoshi Shimokawa 	}
1514e9e688e2SHidetoshi Shimokawa 
1515e9e688e2SHidetoshi Shimokawa 	memcpy(atio->cdb_io.cdb_bytes, bytes, atio->cdb_len);
1516e9e688e2SHidetoshi Shimokawa 
1517e9e688e2SHidetoshi Shimokawa 	atio->ccb_h.status |= CAM_CDB_RECVD;
1518e9e688e2SHidetoshi Shimokawa 
1519e9e688e2SHidetoshi Shimokawa 	/* next ORB */
1520e9e688e2SHidetoshi Shimokawa 	if ((orb[0] & (1<<31)) == 0) {
1521e9e688e2SHidetoshi Shimokawa 		if (debug)
152210d3ed64SHidetoshi Shimokawa 			printf("%s: fetch next orb\n", __func__);
1523e9e688e2SHidetoshi Shimokawa 		orbi->status.src = SRC_NEXT_EXISTS;
1524e9e688e2SHidetoshi Shimokawa 		sbp_targ_fetch_orb(orbi->sc, orbi->fwdev,
1525a73ff510SHidetoshi Shimokawa 		    orb[0], orb[1], orbi->login, FETCH_CMD);
1526e9e688e2SHidetoshi Shimokawa 	} else {
1527e9e688e2SHidetoshi Shimokawa 		orbi->status.src = SRC_NO_NEXT;
1528a73ff510SHidetoshi Shimokawa 		orbi->login->flags &= ~F_LINK_ACTIVE;
1529e9e688e2SHidetoshi Shimokawa 	}
1530e9e688e2SHidetoshi Shimokawa 
1531e9e688e2SHidetoshi Shimokawa 	orbi->data_hi = orb[2];
1532e9e688e2SHidetoshi Shimokawa 	orbi->data_lo = orb[3];
1533e9e688e2SHidetoshi Shimokawa 	orbi->orb4 = *orb4;
1534e9e688e2SHidetoshi Shimokawa 
15359950b741SHidetoshi Shimokawa 	SBP_LOCK(orbi->sc);
1536e9e688e2SHidetoshi Shimokawa 	xpt_done((union ccb*)atio);
15379950b741SHidetoshi Shimokawa 	SBP_UNLOCK(orbi->sc);
1538e9e688e2SHidetoshi Shimokawa done0:
1539e9e688e2SHidetoshi Shimokawa 	fw_xfer_free(xfer);
1540e9e688e2SHidetoshi Shimokawa 	return;
1541e9e688e2SHidetoshi Shimokawa }
1542e9e688e2SHidetoshi Shimokawa 
1543a73ff510SHidetoshi Shimokawa static struct sbp_targ_login *
1544a73ff510SHidetoshi Shimokawa sbp_targ_get_login(struct sbp_targ_softc *sc, struct fw_device *fwdev, int lun)
1545a73ff510SHidetoshi Shimokawa {
1546a73ff510SHidetoshi Shimokawa 	struct sbp_targ_lstate *lstate;
1547a73ff510SHidetoshi Shimokawa 	struct sbp_targ_login *login;
1548a73ff510SHidetoshi Shimokawa 	int i;
1549a73ff510SHidetoshi Shimokawa 
1550a73ff510SHidetoshi Shimokawa 	lstate = sc->lstate[lun];
1551a73ff510SHidetoshi Shimokawa 
1552a73ff510SHidetoshi Shimokawa 	STAILQ_FOREACH(login, &lstate->logins, link)
1553a73ff510SHidetoshi Shimokawa 		if (login->fwdev == fwdev)
1554a73ff510SHidetoshi Shimokawa 			return (login);
1555a73ff510SHidetoshi Shimokawa 
1556a73ff510SHidetoshi Shimokawa 	for (i = 0; i < MAX_LOGINS; i ++)
1557a73ff510SHidetoshi Shimokawa 		if (sc->logins[i] == NULL)
1558a73ff510SHidetoshi Shimokawa 			goto found;
1559a73ff510SHidetoshi Shimokawa 
156010d3ed64SHidetoshi Shimokawa 	printf("%s: increase MAX_LOGIN\n", __func__);
1561a73ff510SHidetoshi Shimokawa 	return (NULL);
1562a73ff510SHidetoshi Shimokawa 
1563a73ff510SHidetoshi Shimokawa found:
1564a73ff510SHidetoshi Shimokawa 	login = (struct sbp_targ_login *)malloc(
1565a73ff510SHidetoshi Shimokawa 	    sizeof(struct sbp_targ_login), M_SBP_TARG, M_NOWAIT | M_ZERO);
1566a73ff510SHidetoshi Shimokawa 
1567a73ff510SHidetoshi Shimokawa 	if (login == NULL) {
156810d3ed64SHidetoshi Shimokawa 		printf("%s: malloc failed\n", __func__);
1569a73ff510SHidetoshi Shimokawa 		return (NULL);
1570a73ff510SHidetoshi Shimokawa 	}
1571a73ff510SHidetoshi Shimokawa 
1572c6cf3e20SHidetoshi Shimokawa 	login->id = i;
1573a73ff510SHidetoshi Shimokawa 	login->fwdev = fwdev;
1574a73ff510SHidetoshi Shimokawa 	login->lstate = lstate;
1575a73ff510SHidetoshi Shimokawa 	login->last_hi = 0xffff;
1576a73ff510SHidetoshi Shimokawa 	login->last_lo = 0xffffffff;
1577a73ff510SHidetoshi Shimokawa 	login->hold_sec = 1;
1578a73ff510SHidetoshi Shimokawa 	STAILQ_INIT(&login->orbs);
1579a73ff510SHidetoshi Shimokawa 	CALLOUT_INIT(&login->hold_callout);
1580a73ff510SHidetoshi Shimokawa 	sc->logins[i] = login;
1581a73ff510SHidetoshi Shimokawa 	return (login);
1582a73ff510SHidetoshi Shimokawa }
1583a73ff510SHidetoshi Shimokawa 
1584e9e688e2SHidetoshi Shimokawa static void
1585e9e688e2SHidetoshi Shimokawa sbp_targ_mgm_handler(struct fw_xfer *xfer)
1586e9e688e2SHidetoshi Shimokawa {
1587e9e688e2SHidetoshi Shimokawa 	struct sbp_targ_lstate *lstate;
1588a73ff510SHidetoshi Shimokawa 	struct sbp_targ_login *login;
1589e9e688e2SHidetoshi Shimokawa 	struct fw_pkt *fp;
159003161bbcSDoug Rabson 	uint32_t *orb;
1591e9e688e2SHidetoshi Shimokawa 	struct morb4 *orb4;
1592e9e688e2SHidetoshi Shimokawa 	struct orb_info *orbi;
1593e9e688e2SHidetoshi Shimokawa 	int i;
1594e9e688e2SHidetoshi Shimokawa 
1595e9e688e2SHidetoshi Shimokawa 	orbi = (struct orb_info *)xfer->sc;
1596e9e688e2SHidetoshi Shimokawa 	if (xfer->resp != 0) {
159710d3ed64SHidetoshi Shimokawa 		printf("%s: xfer->resp = %d\n", __func__, xfer->resp);
1598e9e688e2SHidetoshi Shimokawa 		orbi->status.resp = SBP_TRANS_FAIL;
15991398a889SHidetoshi Shimokawa 		orbi->status.status = OBJ_ORB | SBE_TIMEOUT/*XXX*/;
1600e9e688e2SHidetoshi Shimokawa 		orbi->status.dead = 1;
1601e9e688e2SHidetoshi Shimokawa 		orbi->status.len = 1;
16029950b741SHidetoshi Shimokawa 		sbp_targ_abort(orbi->sc, STAILQ_NEXT(orbi, link));
1603e9e688e2SHidetoshi Shimokawa 
1604e9e688e2SHidetoshi Shimokawa 		sbp_targ_status_FIFO(orbi,
1605a73ff510SHidetoshi Shimokawa 		    orbi->login->fifo_hi, orbi->login->fifo_lo, /*dequeue*/0);
1606e9e688e2SHidetoshi Shimokawa 		fw_xfer_free(xfer);
1607e9e688e2SHidetoshi Shimokawa 		return;
1608e9e688e2SHidetoshi Shimokawa 	}
1609e9e688e2SHidetoshi Shimokawa 	fp = &xfer->recv.hdr;
1610e9e688e2SHidetoshi Shimokawa 
1611e9e688e2SHidetoshi Shimokawa 	orb = orbi->orb;
1612e9e688e2SHidetoshi Shimokawa 	/* swap payload */
1613e9e688e2SHidetoshi Shimokawa 	for (i = 0; i < 8; i ++) {
1614e9e688e2SHidetoshi Shimokawa 		orb[i] = ntohl(orb[i]);
1615e9e688e2SHidetoshi Shimokawa 	}
1616e9e688e2SHidetoshi Shimokawa 	orb4 = (struct morb4 *)&orb[4];
1617e9e688e2SHidetoshi Shimokawa 	if (debug)
161810d3ed64SHidetoshi Shimokawa 		printf("%s: %s\n", __func__, orb_fun_name[orb4->fun]);
1619e9e688e2SHidetoshi Shimokawa 
1620e9e688e2SHidetoshi Shimokawa 	orbi->status.src = SRC_NO_NEXT;
1621e9e688e2SHidetoshi Shimokawa 
1622e9e688e2SHidetoshi Shimokawa 	switch (orb4->fun << 16) {
1623e9e688e2SHidetoshi Shimokawa 	case ORB_FUN_LGI:
1624e9e688e2SHidetoshi Shimokawa 	{
1625a73ff510SHidetoshi Shimokawa 		int exclusive = 0, lun;
1626e9e688e2SHidetoshi Shimokawa 
1627a73ff510SHidetoshi Shimokawa 		if (orb[4] & ORB_EXV)
1628a73ff510SHidetoshi Shimokawa 			exclusive = 1;
1629a73ff510SHidetoshi Shimokawa 
1630a73ff510SHidetoshi Shimokawa 		lun = orb4->id;
1631a73ff510SHidetoshi Shimokawa 		lstate = orbi->sc->lstate[lun];
1632a73ff510SHidetoshi Shimokawa 
1633a73ff510SHidetoshi Shimokawa 		if (lun >= MAX_LUN || lstate == NULL ||
1634a73ff510SHidetoshi Shimokawa 		    (exclusive &&
1635a73ff510SHidetoshi Shimokawa 		    STAILQ_FIRST(&lstate->logins) != NULL &&
1636a73ff510SHidetoshi Shimokawa 		    STAILQ_FIRST(&lstate->logins)->fwdev != orbi->fwdev)
1637a73ff510SHidetoshi Shimokawa 		    ) {
1638e9e688e2SHidetoshi Shimokawa 			/* error */
1639e9e688e2SHidetoshi Shimokawa 			orbi->status.dead = 1;
1640e9e688e2SHidetoshi Shimokawa 			orbi->status.status = STATUS_ACCESS_DENY;
1641e9e688e2SHidetoshi Shimokawa 			orbi->status.len = 1;
1642e9e688e2SHidetoshi Shimokawa 			break;
1643e9e688e2SHidetoshi Shimokawa 		}
1644a73ff510SHidetoshi Shimokawa 
1645a73ff510SHidetoshi Shimokawa 		/* allocate login */
1646a73ff510SHidetoshi Shimokawa 		login = sbp_targ_get_login(orbi->sc, orbi->fwdev, lun);
1647a73ff510SHidetoshi Shimokawa 		if (login == NULL) {
1648a73ff510SHidetoshi Shimokawa 			printf("%s: sbp_targ_get_login failed\n",
164910d3ed64SHidetoshi Shimokawa 			    __func__);
1650a73ff510SHidetoshi Shimokawa 			orbi->status.dead = 1;
1651a73ff510SHidetoshi Shimokawa 			orbi->status.status = STATUS_RES_UNAVAIL;
1652a73ff510SHidetoshi Shimokawa 			orbi->status.len = 1;
1653a73ff510SHidetoshi Shimokawa 			break;
1654a73ff510SHidetoshi Shimokawa 		}
16559950b741SHidetoshi Shimokawa 		printf("%s: login id=%d\n", __func__, login->id);
1656a73ff510SHidetoshi Shimokawa 
1657a73ff510SHidetoshi Shimokawa 		login->fifo_hi = orb[6];
1658a73ff510SHidetoshi Shimokawa 		login->fifo_lo = orb[7];
165903161bbcSDoug Rabson 		login->loginres.len = htons(sizeof(uint32_t) * 4);
1660a73ff510SHidetoshi Shimokawa 		login->loginres.id = htons(login->id);
1661a73ff510SHidetoshi Shimokawa 		login->loginres.cmd_hi = htons(SBP_TARG_BIND_HI);
1662a73ff510SHidetoshi Shimokawa 		login->loginres.cmd_lo = htonl(SBP_TARG_BIND_LO(login->id));
1663a73ff510SHidetoshi Shimokawa 		login->loginres.recon_hold = htons(login->hold_sec);
1664a73ff510SHidetoshi Shimokawa 
16659950b741SHidetoshi Shimokawa 		STAILQ_INSERT_TAIL(&lstate->logins, login, link);
16664636d244SSean Bruno 		fwmem_write_block(orbi->fwdev, NULL, /*spd*/FWSPD_S400, orb[2], orb[3],
1667a73ff510SHidetoshi Shimokawa 		    sizeof(struct sbp_login_res), (void *)&login->loginres,
1668e9e688e2SHidetoshi Shimokawa 		    fw_asy_callback_free);
1669c54d1fe2SHidetoshi Shimokawa 		/* XXX return status after loginres is successfully written */
1670e9e688e2SHidetoshi Shimokawa 		break;
1671e9e688e2SHidetoshi Shimokawa 	}
1672e9e688e2SHidetoshi Shimokawa 	case ORB_FUN_RCN:
1673a73ff510SHidetoshi Shimokawa 		login = orbi->sc->logins[orb4->id];
1674a73ff510SHidetoshi Shimokawa 		if (login != NULL && login->fwdev == orbi->fwdev) {
1675a73ff510SHidetoshi Shimokawa 			login->flags &= ~F_HOLD;
1676a73ff510SHidetoshi Shimokawa 			callout_stop(&login->hold_callout);
1677a73ff510SHidetoshi Shimokawa 			printf("%s: reconnected id=%d\n",
167810d3ed64SHidetoshi Shimokawa 			    __func__, login->id);
1679a73ff510SHidetoshi Shimokawa 		} else {
1680e9e688e2SHidetoshi Shimokawa 			orbi->status.dead = 1;
1681e9e688e2SHidetoshi Shimokawa 			orbi->status.status = STATUS_ACCESS_DENY;
1682a73ff510SHidetoshi Shimokawa 			printf("%s: reconnection faild id=%d\n",
168310d3ed64SHidetoshi Shimokawa 			    __func__, orb4->id);
1684a73ff510SHidetoshi Shimokawa 		}
1685a73ff510SHidetoshi Shimokawa 		break;
1686a73ff510SHidetoshi Shimokawa 	case ORB_FUN_LGO:
1687a73ff510SHidetoshi Shimokawa 		login = orbi->sc->logins[orb4->id];
1688a73ff510SHidetoshi Shimokawa 		if (login->fwdev != orbi->fwdev) {
168910d3ed64SHidetoshi Shimokawa 			printf("%s: wrong initiator\n", __func__);
1690a73ff510SHidetoshi Shimokawa 			break;
1691a73ff510SHidetoshi Shimokawa 		}
1692a73ff510SHidetoshi Shimokawa 		sbp_targ_dealloc_login(login);
1693e9e688e2SHidetoshi Shimokawa 		break;
1694e9e688e2SHidetoshi Shimokawa 	default:
1695e9e688e2SHidetoshi Shimokawa 		printf("%s: %s not implemented yet\n",
169610d3ed64SHidetoshi Shimokawa 		    __func__, orb_fun_name[orb4->fun]);
1697e9e688e2SHidetoshi Shimokawa 		break;
1698e9e688e2SHidetoshi Shimokawa 	}
1699e9e688e2SHidetoshi Shimokawa 	orbi->status.len = 1;
1700e9e688e2SHidetoshi Shimokawa 	sbp_targ_status_FIFO(orbi, orb[6], orb[7], /*dequeue*/0);
1701e9e688e2SHidetoshi Shimokawa 	fw_xfer_free(xfer);
1702e9e688e2SHidetoshi Shimokawa 	return;
1703e9e688e2SHidetoshi Shimokawa }
1704e9e688e2SHidetoshi Shimokawa 
1705e9e688e2SHidetoshi Shimokawa static void
1706e9e688e2SHidetoshi Shimokawa sbp_targ_pointer_handler(struct fw_xfer *xfer)
1707e9e688e2SHidetoshi Shimokawa {
1708e9e688e2SHidetoshi Shimokawa 	struct orb_info *orbi;
170903161bbcSDoug Rabson 	uint32_t orb0, orb1;
1710e9e688e2SHidetoshi Shimokawa 
1711e9e688e2SHidetoshi Shimokawa 	orbi = (struct orb_info *)xfer->sc;
1712e9e688e2SHidetoshi Shimokawa 	if (xfer->resp != 0) {
171310d3ed64SHidetoshi Shimokawa 		printf("%s: xfer->resp = %d\n", __func__, xfer->resp);
1714e9e688e2SHidetoshi Shimokawa 		goto done;
1715e9e688e2SHidetoshi Shimokawa 	}
1716e9e688e2SHidetoshi Shimokawa 
1717e9e688e2SHidetoshi Shimokawa 	orb0 = ntohl(orbi->orb[0]);
1718e9e688e2SHidetoshi Shimokawa 	orb1 = ntohl(orbi->orb[1]);
1719*7a22215cSEitan Adler 	if ((orb0 & (1U << 31)) != 0) {
172010d3ed64SHidetoshi Shimokawa 		printf("%s: invalid pointer\n", __func__);
1721e9e688e2SHidetoshi Shimokawa 		goto done;
1722e9e688e2SHidetoshi Shimokawa 	}
1723a73ff510SHidetoshi Shimokawa 	sbp_targ_fetch_orb(orbi->login->lstate->sc, orbi->fwdev,
172403161bbcSDoug Rabson 	    (uint16_t)orb0, orb1, orbi->login, FETCH_CMD);
1725e9e688e2SHidetoshi Shimokawa done:
1726e9e688e2SHidetoshi Shimokawa 	free(orbi, M_SBP_TARG);
1727e9e688e2SHidetoshi Shimokawa 	fw_xfer_free(xfer);
1728e9e688e2SHidetoshi Shimokawa 	return;
1729e9e688e2SHidetoshi Shimokawa }
1730e9e688e2SHidetoshi Shimokawa 
1731e9e688e2SHidetoshi Shimokawa static void
1732e9e688e2SHidetoshi Shimokawa sbp_targ_fetch_orb(struct sbp_targ_softc *sc, struct fw_device *fwdev,
173303161bbcSDoug Rabson     uint16_t orb_hi, uint32_t orb_lo, struct sbp_targ_login *login,
1734e9e688e2SHidetoshi Shimokawa     int mode)
1735e9e688e2SHidetoshi Shimokawa {
1736e9e688e2SHidetoshi Shimokawa 	struct orb_info *orbi;
1737e9e688e2SHidetoshi Shimokawa 
1738e9e688e2SHidetoshi Shimokawa 	if (debug)
173910d3ed64SHidetoshi Shimokawa 		printf("%s: fetch orb %04x:%08x\n", __func__, orb_hi, orb_lo);
1740e9e688e2SHidetoshi Shimokawa 	orbi = malloc(sizeof(struct orb_info), M_SBP_TARG, M_NOWAIT | M_ZERO);
1741e9e688e2SHidetoshi Shimokawa 	if (orbi == NULL) {
174210d3ed64SHidetoshi Shimokawa 		printf("%s: malloc failed\n", __func__);
1743e9e688e2SHidetoshi Shimokawa 		return;
1744e9e688e2SHidetoshi Shimokawa 	}
1745e9e688e2SHidetoshi Shimokawa 	orbi->sc = sc;
1746e9e688e2SHidetoshi Shimokawa 	orbi->fwdev = fwdev;
1747a73ff510SHidetoshi Shimokawa 	orbi->login = login;
1748e9e688e2SHidetoshi Shimokawa 	orbi->orb_hi = orb_hi;
1749e9e688e2SHidetoshi Shimokawa 	orbi->orb_lo = orb_lo;
1750e9e688e2SHidetoshi Shimokawa 	orbi->status.orb_hi = htons(orb_hi);
1751e9e688e2SHidetoshi Shimokawa 	orbi->status.orb_lo = htonl(orb_lo);
17524636d244SSean Bruno 	orbi->page_table = NULL;
1753e9e688e2SHidetoshi Shimokawa 
1754e9e688e2SHidetoshi Shimokawa 	switch (mode) {
1755e9e688e2SHidetoshi Shimokawa 	case FETCH_MGM:
17564636d244SSean Bruno 		fwmem_read_block(fwdev, (void *)orbi, /*spd*/FWSPD_S400, orb_hi, orb_lo,
175703161bbcSDoug Rabson 		    sizeof(uint32_t) * 8, &orbi->orb[0],
1758e9e688e2SHidetoshi Shimokawa 		    sbp_targ_mgm_handler);
1759e9e688e2SHidetoshi Shimokawa 		break;
1760e9e688e2SHidetoshi Shimokawa 	case FETCH_CMD:
1761e9e688e2SHidetoshi Shimokawa 		orbi->state = ORBI_STATUS_FETCH;
1762a73ff510SHidetoshi Shimokawa 		login->last_hi = orb_hi;
1763a73ff510SHidetoshi Shimokawa 		login->last_lo = orb_lo;
1764a73ff510SHidetoshi Shimokawa 		login->flags |= F_LINK_ACTIVE;
1765e9e688e2SHidetoshi Shimokawa 		/* dequeue */
17669950b741SHidetoshi Shimokawa 		SBP_LOCK(sc);
1767e9e688e2SHidetoshi Shimokawa 		orbi->atio = (struct ccb_accept_tio *)
1768a73ff510SHidetoshi Shimokawa 		    SLIST_FIRST(&login->lstate->accept_tios);
1769e9e688e2SHidetoshi Shimokawa 		if (orbi->atio == NULL) {
17709950b741SHidetoshi Shimokawa 			SBP_UNLOCK(sc);
177110d3ed64SHidetoshi Shimokawa 			printf("%s: no free atio\n", __func__);
1772a73ff510SHidetoshi Shimokawa 			login->lstate->flags |= F_ATIO_STARVED;
1773a73ff510SHidetoshi Shimokawa 			login->flags |= F_ATIO_STARVED;
1774a73ff510SHidetoshi Shimokawa #if 0
1775a73ff510SHidetoshi Shimokawa 			/* XXX ?? */
1776a73ff510SHidetoshi Shimokawa 			login->fwdev = fwdev;
1777a73ff510SHidetoshi Shimokawa #endif
1778e9e688e2SHidetoshi Shimokawa 			break;
1779e9e688e2SHidetoshi Shimokawa 		}
1780a73ff510SHidetoshi Shimokawa 		SLIST_REMOVE_HEAD(&login->lstate->accept_tios, sim_links.sle);
17819950b741SHidetoshi Shimokawa 		STAILQ_INSERT_TAIL(&login->orbs, orbi, link);
17829950b741SHidetoshi Shimokawa 		SBP_UNLOCK(sc);
17834636d244SSean Bruno 		fwmem_read_block(fwdev, (void *)orbi, /*spd*/FWSPD_S400, orb_hi, orb_lo,
178403161bbcSDoug Rabson 		    sizeof(uint32_t) * 8, &orbi->orb[0],
1785e9e688e2SHidetoshi Shimokawa 		    sbp_targ_cmd_handler);
1786e9e688e2SHidetoshi Shimokawa 		break;
1787e9e688e2SHidetoshi Shimokawa 	case FETCH_POINTER:
1788e9e688e2SHidetoshi Shimokawa 		orbi->state = ORBI_STATUS_POINTER;
1789a73ff510SHidetoshi Shimokawa 		login->flags |= F_LINK_ACTIVE;
17904636d244SSean Bruno 		fwmem_read_block(fwdev, (void *)orbi, /*spd*/FWSPD_S400, orb_hi, orb_lo,
179103161bbcSDoug Rabson 		    sizeof(uint32_t) * 2, &orbi->orb[0],
1792e9e688e2SHidetoshi Shimokawa 		    sbp_targ_pointer_handler);
1793e9e688e2SHidetoshi Shimokawa 		break;
1794e9e688e2SHidetoshi Shimokawa 	default:
179510d3ed64SHidetoshi Shimokawa 		printf("%s: invalid mode %d\n", __func__, mode);
1796e9e688e2SHidetoshi Shimokawa 	}
1797e9e688e2SHidetoshi Shimokawa }
1798e9e688e2SHidetoshi Shimokawa 
1799e9e688e2SHidetoshi Shimokawa static void
1800e9e688e2SHidetoshi Shimokawa sbp_targ_resp_callback(struct fw_xfer *xfer)
1801e9e688e2SHidetoshi Shimokawa {
1802e9e688e2SHidetoshi Shimokawa 	struct sbp_targ_softc *sc;
1803e9e688e2SHidetoshi Shimokawa 	int s;
1804e9e688e2SHidetoshi Shimokawa 
1805e9e688e2SHidetoshi Shimokawa 	if (debug)
180610d3ed64SHidetoshi Shimokawa 		printf("%s: xfer=%p\n", __func__, xfer);
1807e9e688e2SHidetoshi Shimokawa 	sc = (struct sbp_targ_softc *)xfer->sc;
1808e9e688e2SHidetoshi Shimokawa 	fw_xfer_unload(xfer);
1809e9e688e2SHidetoshi Shimokawa 	xfer->recv.pay_len = SBP_TARG_RECV_LEN;
1810801167a8SHidetoshi Shimokawa 	xfer->hand = sbp_targ_recv;
1811e9e688e2SHidetoshi Shimokawa 	s = splfw();
1812e9e688e2SHidetoshi Shimokawa 	STAILQ_INSERT_TAIL(&sc->fwb.xferlist, xfer, link);
1813e9e688e2SHidetoshi Shimokawa 	splx(s);
1814e9e688e2SHidetoshi Shimokawa }
1815e9e688e2SHidetoshi Shimokawa 
1816e9e688e2SHidetoshi Shimokawa static int
1817a73ff510SHidetoshi Shimokawa sbp_targ_cmd(struct fw_xfer *xfer, struct fw_device *fwdev, int login_id,
1818a73ff510SHidetoshi Shimokawa     int reg)
1819e9e688e2SHidetoshi Shimokawa {
1820a73ff510SHidetoshi Shimokawa 	struct sbp_targ_login *login;
1821e9e688e2SHidetoshi Shimokawa 	struct sbp_targ_softc *sc;
1822e9e688e2SHidetoshi Shimokawa 	int rtcode = 0;
1823e9e688e2SHidetoshi Shimokawa 
1824a73ff510SHidetoshi Shimokawa 	if (login_id < 0 || login_id >= MAX_LOGINS)
1825e9e688e2SHidetoshi Shimokawa 		return(RESP_ADDRESS_ERROR);
1826e9e688e2SHidetoshi Shimokawa 
1827e9e688e2SHidetoshi Shimokawa 	sc = (struct sbp_targ_softc *)xfer->sc;
1828a73ff510SHidetoshi Shimokawa 	login = sc->logins[login_id];
1829a73ff510SHidetoshi Shimokawa 	if (login == NULL)
1830e9e688e2SHidetoshi Shimokawa 		return(RESP_ADDRESS_ERROR);
1831e9e688e2SHidetoshi Shimokawa 
1832a73ff510SHidetoshi Shimokawa 	if (login->fwdev != fwdev) {
1833a73ff510SHidetoshi Shimokawa 		/* XXX */
1834a73ff510SHidetoshi Shimokawa 		return(RESP_ADDRESS_ERROR);
1835a73ff510SHidetoshi Shimokawa 	}
1836a73ff510SHidetoshi Shimokawa 
1837e9e688e2SHidetoshi Shimokawa 	switch (reg) {
1838e9e688e2SHidetoshi Shimokawa 	case 0x08:	/* ORB_POINTER */
1839e9e688e2SHidetoshi Shimokawa 		if (debug)
18409950b741SHidetoshi Shimokawa 			printf("%s: ORB_POINTER(%d)\n", __func__, login_id);
1841a73ff510SHidetoshi Shimokawa 		if ((login->flags & F_LINK_ACTIVE) != 0) {
1842a73ff510SHidetoshi Shimokawa 			if (debug)
1843a73ff510SHidetoshi Shimokawa 				printf("link active (ORB_POINTER)\n");
1844a73ff510SHidetoshi Shimokawa 			break;
1845a73ff510SHidetoshi Shimokawa 		}
1846a73ff510SHidetoshi Shimokawa 		sbp_targ_fetch_orb(sc, fwdev,
1847e9e688e2SHidetoshi Shimokawa 		    ntohl(xfer->recv.payload[0]),
1848e9e688e2SHidetoshi Shimokawa 		    ntohl(xfer->recv.payload[1]),
1849a73ff510SHidetoshi Shimokawa 		    login, FETCH_CMD);
1850e9e688e2SHidetoshi Shimokawa 		break;
1851e9e688e2SHidetoshi Shimokawa 	case 0x04:	/* AGENT_RESET */
1852e9e688e2SHidetoshi Shimokawa 		if (debug)
18539950b741SHidetoshi Shimokawa 			printf("%s: AGENT RESET(%d)\n", __func__, login_id);
1854a73ff510SHidetoshi Shimokawa 		login->last_hi = 0xffff;
1855a73ff510SHidetoshi Shimokawa 		login->last_lo = 0xffffffff;
18569950b741SHidetoshi Shimokawa 		sbp_targ_abort(sc, STAILQ_FIRST(&login->orbs));
1857e9e688e2SHidetoshi Shimokawa 		break;
1858e9e688e2SHidetoshi Shimokawa 	case 0x10:	/* DOORBELL */
1859e9e688e2SHidetoshi Shimokawa 		if (debug)
18609950b741SHidetoshi Shimokawa 			printf("%s: DOORBELL(%d)\n", __func__, login_id);
1861a73ff510SHidetoshi Shimokawa 		if (login->last_hi == 0xffff &&
1862a73ff510SHidetoshi Shimokawa 		    login->last_lo == 0xffffffff) {
1863e9e688e2SHidetoshi Shimokawa 			printf("%s: no previous pointer(DOORBELL)\n",
186410d3ed64SHidetoshi Shimokawa 			    __func__);
1865e9e688e2SHidetoshi Shimokawa 			break;
1866e9e688e2SHidetoshi Shimokawa 		}
1867a73ff510SHidetoshi Shimokawa 		if ((login->flags & F_LINK_ACTIVE) != 0) {
1868e9e688e2SHidetoshi Shimokawa 			if (debug)
1869e9e688e2SHidetoshi Shimokawa 				printf("link active (DOORBELL)\n");
1870e9e688e2SHidetoshi Shimokawa 			break;
1871e9e688e2SHidetoshi Shimokawa 		}
1872a73ff510SHidetoshi Shimokawa 		sbp_targ_fetch_orb(sc, fwdev,
1873a73ff510SHidetoshi Shimokawa 		    login->last_hi, login->last_lo,
1874a73ff510SHidetoshi Shimokawa 		    login, FETCH_POINTER);
1875e9e688e2SHidetoshi Shimokawa 		break;
1876e9e688e2SHidetoshi Shimokawa 	case 0x00:	/* AGENT_STATE */
18779950b741SHidetoshi Shimokawa 		printf("%s: AGENT_STATE (%d:ignore)\n", __func__, login_id);
1878e9e688e2SHidetoshi Shimokawa 		break;
1879e9e688e2SHidetoshi Shimokawa 	case 0x14:	/* UNSOLICITED_STATE_ENABLE */
18809950b741SHidetoshi Shimokawa 		printf("%s: UNSOLICITED_STATE_ENABLE (%d:ignore)\n",
18819950b741SHidetoshi Shimokawa 							 __func__, login_id);
1882e9e688e2SHidetoshi Shimokawa 		break;
1883e9e688e2SHidetoshi Shimokawa 	default:
18849950b741SHidetoshi Shimokawa 		printf("%s: invalid register %d(%d)\n",
18859950b741SHidetoshi Shimokawa 						 __func__, reg, login_id);
1886e9e688e2SHidetoshi Shimokawa 		rtcode = RESP_ADDRESS_ERROR;
1887e9e688e2SHidetoshi Shimokawa 	}
1888e9e688e2SHidetoshi Shimokawa 
1889e9e688e2SHidetoshi Shimokawa 	return (rtcode);
1890e9e688e2SHidetoshi Shimokawa }
1891e9e688e2SHidetoshi Shimokawa 
1892e9e688e2SHidetoshi Shimokawa static int
1893e9e688e2SHidetoshi Shimokawa sbp_targ_mgm(struct fw_xfer *xfer, struct fw_device *fwdev)
1894e9e688e2SHidetoshi Shimokawa {
1895e9e688e2SHidetoshi Shimokawa 	struct sbp_targ_softc *sc;
1896e9e688e2SHidetoshi Shimokawa 	struct fw_pkt *fp;
1897e9e688e2SHidetoshi Shimokawa 
1898e9e688e2SHidetoshi Shimokawa 	sc = (struct sbp_targ_softc *)xfer->sc;
1899e9e688e2SHidetoshi Shimokawa 
1900e9e688e2SHidetoshi Shimokawa 	fp = &xfer->recv.hdr;
1901e9e688e2SHidetoshi Shimokawa 	if (fp->mode.wreqb.tcode != FWTCODE_WREQB){
190210d3ed64SHidetoshi Shimokawa 		printf("%s: tcode = %d\n", __func__, fp->mode.wreqb.tcode);
1903e9e688e2SHidetoshi Shimokawa 		return(RESP_TYPE_ERROR);
1904e9e688e2SHidetoshi Shimokawa         }
1905e9e688e2SHidetoshi Shimokawa 
1906e9e688e2SHidetoshi Shimokawa 	sbp_targ_fetch_orb(sc, fwdev,
1907e9e688e2SHidetoshi Shimokawa 	    ntohl(xfer->recv.payload[0]),
1908e9e688e2SHidetoshi Shimokawa 	    ntohl(xfer->recv.payload[1]),
1909e9e688e2SHidetoshi Shimokawa 	    NULL, FETCH_MGM);
1910e9e688e2SHidetoshi Shimokawa 
1911e9e688e2SHidetoshi Shimokawa 	return(0);
1912e9e688e2SHidetoshi Shimokawa }
1913e9e688e2SHidetoshi Shimokawa 
1914e9e688e2SHidetoshi Shimokawa static void
1915e9e688e2SHidetoshi Shimokawa sbp_targ_recv(struct fw_xfer *xfer)
1916e9e688e2SHidetoshi Shimokawa {
1917e9e688e2SHidetoshi Shimokawa 	struct fw_pkt *fp, *sfp;
1918e9e688e2SHidetoshi Shimokawa 	struct fw_device *fwdev;
191903161bbcSDoug Rabson 	uint32_t lo;
1920e9e688e2SHidetoshi Shimokawa 	int s, rtcode;
1921e9e688e2SHidetoshi Shimokawa 	struct sbp_targ_softc *sc;
1922e9e688e2SHidetoshi Shimokawa 
1923e9e688e2SHidetoshi Shimokawa 	s = splfw();
1924e9e688e2SHidetoshi Shimokawa 	sc = (struct sbp_targ_softc *)xfer->sc;
1925e9e688e2SHidetoshi Shimokawa 	fp = &xfer->recv.hdr;
1926e9e688e2SHidetoshi Shimokawa 	fwdev = fw_noderesolve_nodeid(sc->fd.fc, fp->mode.wreqb.src & 0x3f);
1927e9e688e2SHidetoshi Shimokawa 	if (fwdev == NULL) {
1928e9e688e2SHidetoshi Shimokawa 		printf("%s: cannot resolve nodeid=%d\n",
192910d3ed64SHidetoshi Shimokawa 		    __func__, fp->mode.wreqb.src & 0x3f);
1930e9e688e2SHidetoshi Shimokawa 		rtcode = RESP_TYPE_ERROR; /* XXX */
1931e9e688e2SHidetoshi Shimokawa 		goto done;
1932e9e688e2SHidetoshi Shimokawa 	}
1933e9e688e2SHidetoshi Shimokawa 	lo = fp->mode.wreqb.dest_lo;
19349950b741SHidetoshi Shimokawa 
1935e9e688e2SHidetoshi Shimokawa 	if (lo == SBP_TARG_BIND_LO(-1))
1936e9e688e2SHidetoshi Shimokawa 		rtcode = sbp_targ_mgm(xfer, fwdev);
1937e9e688e2SHidetoshi Shimokawa 	else if (lo >= SBP_TARG_BIND_LO(0))
1938a73ff510SHidetoshi Shimokawa 		rtcode = sbp_targ_cmd(xfer, fwdev, SBP_TARG_LOGIN_ID(lo),
1939a73ff510SHidetoshi Shimokawa 		    lo % 0x20);
1940e9e688e2SHidetoshi Shimokawa 	else
1941e9e688e2SHidetoshi Shimokawa 		rtcode = RESP_ADDRESS_ERROR;
1942e9e688e2SHidetoshi Shimokawa 
1943e9e688e2SHidetoshi Shimokawa done:
1944e9e688e2SHidetoshi Shimokawa 	if (rtcode != 0)
194510d3ed64SHidetoshi Shimokawa 		printf("%s: rtcode = %d\n", __func__, rtcode);
1946e9e688e2SHidetoshi Shimokawa 	sfp = &xfer->send.hdr;
19474636d244SSean Bruno 	xfer->send.spd = FWSPD_S400;
1948801167a8SHidetoshi Shimokawa 	xfer->hand = sbp_targ_resp_callback;
1949e9e688e2SHidetoshi Shimokawa 	sfp->mode.wres.dst = fp->mode.wreqb.src;
1950e9e688e2SHidetoshi Shimokawa 	sfp->mode.wres.tlrt = fp->mode.wreqb.tlrt;
1951e9e688e2SHidetoshi Shimokawa 	sfp->mode.wres.tcode = FWTCODE_WRES;
1952e9e688e2SHidetoshi Shimokawa 	sfp->mode.wres.rtcode = rtcode;
1953e9e688e2SHidetoshi Shimokawa 	sfp->mode.wres.pri = 0;
1954e9e688e2SHidetoshi Shimokawa 
1955e9e688e2SHidetoshi Shimokawa 	fw_asyreq(xfer->fc, -1, xfer);
1956e9e688e2SHidetoshi Shimokawa 	splx(s);
1957e9e688e2SHidetoshi Shimokawa }
1958e9e688e2SHidetoshi Shimokawa 
1959e9e688e2SHidetoshi Shimokawa static int
1960e9e688e2SHidetoshi Shimokawa sbp_targ_attach(device_t dev)
1961e9e688e2SHidetoshi Shimokawa {
1962e9e688e2SHidetoshi Shimokawa 	struct sbp_targ_softc *sc;
1963e9e688e2SHidetoshi Shimokawa 	struct cam_devq *devq;
19649950b741SHidetoshi Shimokawa 	struct firewire_comm *fc;
1965e9e688e2SHidetoshi Shimokawa 
1966e9e688e2SHidetoshi Shimokawa         sc = (struct sbp_targ_softc *) device_get_softc(dev);
1967e9e688e2SHidetoshi Shimokawa 	bzero((void *)sc, sizeof(struct sbp_targ_softc));
1968e9e688e2SHidetoshi Shimokawa 
19699950b741SHidetoshi Shimokawa 	mtx_init(&sc->mtx, "sbp_targ", NULL, MTX_DEF);
19709950b741SHidetoshi Shimokawa 	sc->fd.fc = fc = device_get_ivars(dev);
1971e9e688e2SHidetoshi Shimokawa 	sc->fd.dev = dev;
1972a73ff510SHidetoshi Shimokawa 	sc->fd.post_explore = (void *) sbp_targ_post_explore;
1973e9e688e2SHidetoshi Shimokawa 	sc->fd.post_busreset = (void *) sbp_targ_post_busreset;
1974e9e688e2SHidetoshi Shimokawa 
1975c6cf3e20SHidetoshi Shimokawa         devq = cam_simq_alloc(/*maxopenings*/MAX_LUN*MAX_INITIATORS);
1976e9e688e2SHidetoshi Shimokawa 	if (devq == NULL)
1977e9e688e2SHidetoshi Shimokawa 		return (ENXIO);
1978e9e688e2SHidetoshi Shimokawa 
1979e9e688e2SHidetoshi Shimokawa 	sc->sim = cam_sim_alloc(sbp_targ_action, sbp_targ_poll,
19809950b741SHidetoshi Shimokawa 	    "sbp_targ", sc, device_get_unit(dev), &sc->mtx,
1981e9e688e2SHidetoshi Shimokawa 	    /*untagged*/ 1, /*tagged*/ 1, devq);
1982e9e688e2SHidetoshi Shimokawa 	if (sc->sim == NULL) {
1983e9e688e2SHidetoshi Shimokawa 		cam_simq_free(devq);
1984e9e688e2SHidetoshi Shimokawa 		return (ENXIO);
1985e9e688e2SHidetoshi Shimokawa 	}
1986e9e688e2SHidetoshi Shimokawa 
19879950b741SHidetoshi Shimokawa 	SBP_LOCK(sc);
1988b50569b7SScott Long 	if (xpt_bus_register(sc->sim, dev, /*bus*/0) != CAM_SUCCESS)
1989e9e688e2SHidetoshi Shimokawa 		goto fail;
1990e9e688e2SHidetoshi Shimokawa 
1991e9e688e2SHidetoshi Shimokawa 	if (xpt_create_path(&sc->path, /*periph*/ NULL, cam_sim_path(sc->sim),
1992e9e688e2SHidetoshi Shimokawa 	    CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
1993e9e688e2SHidetoshi Shimokawa 		xpt_bus_deregister(cam_sim_path(sc->sim));
1994e9e688e2SHidetoshi Shimokawa 		goto fail;
1995e9e688e2SHidetoshi Shimokawa 	}
19969950b741SHidetoshi Shimokawa 	SBP_UNLOCK(sc);
1997e9e688e2SHidetoshi Shimokawa 
1998e9e688e2SHidetoshi Shimokawa 	sc->fwb.start = SBP_TARG_BIND_START;
1999e9e688e2SHidetoshi Shimokawa 	sc->fwb.end = SBP_TARG_BIND_END;
2000e9e688e2SHidetoshi Shimokawa 
2001e9e688e2SHidetoshi Shimokawa 	/* pre-allocate xfer */
2002e9e688e2SHidetoshi Shimokawa 	STAILQ_INIT(&sc->fwb.xferlist);
20030892f4c5SHidetoshi Shimokawa 	fw_xferlist_add(&sc->fwb.xferlist, M_SBP_TARG,
20040892f4c5SHidetoshi Shimokawa 	    /*send*/ 0, /*recv*/ SBP_TARG_RECV_LEN, MAX_LUN /* XXX */,
20059950b741SHidetoshi Shimokawa 	    fc, (void *)sc, sbp_targ_recv);
20069950b741SHidetoshi Shimokawa 	fw_bindadd(fc, &sc->fwb);
2007e9e688e2SHidetoshi Shimokawa 	return 0;
2008e9e688e2SHidetoshi Shimokawa 
2009e9e688e2SHidetoshi Shimokawa fail:
20109950b741SHidetoshi Shimokawa 	SBP_UNLOCK(sc);
2011e9e688e2SHidetoshi Shimokawa 	cam_sim_free(sc->sim, /*free_devq*/TRUE);
2012e9e688e2SHidetoshi Shimokawa 	return (ENXIO);
2013e9e688e2SHidetoshi Shimokawa }
2014e9e688e2SHidetoshi Shimokawa 
2015e9e688e2SHidetoshi Shimokawa static int
2016e9e688e2SHidetoshi Shimokawa sbp_targ_detach(device_t dev)
2017e9e688e2SHidetoshi Shimokawa {
2018e9e688e2SHidetoshi Shimokawa 	struct sbp_targ_softc *sc;
2019e9e688e2SHidetoshi Shimokawa 	struct sbp_targ_lstate *lstate;
2020e9e688e2SHidetoshi Shimokawa 	int i;
2021e9e688e2SHidetoshi Shimokawa 
2022e9e688e2SHidetoshi Shimokawa 	sc = (struct sbp_targ_softc *)device_get_softc(dev);
2023e9e688e2SHidetoshi Shimokawa 	sc->fd.post_busreset = NULL;
2024e9e688e2SHidetoshi Shimokawa 
20259950b741SHidetoshi Shimokawa 	SBP_LOCK(sc);
2026e9e688e2SHidetoshi Shimokawa 	xpt_free_path(sc->path);
2027e9e688e2SHidetoshi Shimokawa 	xpt_bus_deregister(cam_sim_path(sc->sim));
20289950b741SHidetoshi Shimokawa 	SBP_UNLOCK(sc);
2029e9e688e2SHidetoshi Shimokawa 	cam_sim_free(sc->sim, /*free_devq*/TRUE);
2030e9e688e2SHidetoshi Shimokawa 
2031e9e688e2SHidetoshi Shimokawa 	for (i = 0; i < MAX_LUN; i ++) {
2032e9e688e2SHidetoshi Shimokawa 		lstate = sc->lstate[i];
2033e9e688e2SHidetoshi Shimokawa 		if (lstate != NULL) {
2034e9e688e2SHidetoshi Shimokawa 			xpt_free_path(lstate->path);
2035e9e688e2SHidetoshi Shimokawa 			free(lstate, M_SBP_TARG);
2036e9e688e2SHidetoshi Shimokawa 		}
2037e9e688e2SHidetoshi Shimokawa 	}
2038e9e688e2SHidetoshi Shimokawa 	if (sc->black_hole != NULL) {
2039e9e688e2SHidetoshi Shimokawa 		xpt_free_path(sc->black_hole->path);
2040e9e688e2SHidetoshi Shimokawa 		free(sc->black_hole, M_SBP_TARG);
2041e9e688e2SHidetoshi Shimokawa 	}
2042e9e688e2SHidetoshi Shimokawa 
2043e9e688e2SHidetoshi Shimokawa 	fw_bindremove(sc->fd.fc, &sc->fwb);
20440892f4c5SHidetoshi Shimokawa 	fw_xferlist_remove(&sc->fwb.xferlist);
2045e9e688e2SHidetoshi Shimokawa 
20469950b741SHidetoshi Shimokawa 	mtx_destroy(&sc->mtx);
20479950b741SHidetoshi Shimokawa 
2048e9e688e2SHidetoshi Shimokawa 	return 0;
2049e9e688e2SHidetoshi Shimokawa }
2050e9e688e2SHidetoshi Shimokawa 
2051e9e688e2SHidetoshi Shimokawa static devclass_t sbp_targ_devclass;
2052e9e688e2SHidetoshi Shimokawa 
2053e9e688e2SHidetoshi Shimokawa static device_method_t sbp_targ_methods[] = {
2054e9e688e2SHidetoshi Shimokawa 	/* device interface */
2055e9e688e2SHidetoshi Shimokawa 	DEVMETHOD(device_identify,	sbp_targ_identify),
2056e9e688e2SHidetoshi Shimokawa 	DEVMETHOD(device_probe,		sbp_targ_probe),
2057e9e688e2SHidetoshi Shimokawa 	DEVMETHOD(device_attach,	sbp_targ_attach),
2058e9e688e2SHidetoshi Shimokawa 	DEVMETHOD(device_detach,	sbp_targ_detach),
2059e9e688e2SHidetoshi Shimokawa 	{ 0, 0 }
2060e9e688e2SHidetoshi Shimokawa };
2061e9e688e2SHidetoshi Shimokawa 
2062e9e688e2SHidetoshi Shimokawa static driver_t sbp_targ_driver = {
2063e9e688e2SHidetoshi Shimokawa 	"sbp_targ",
2064e9e688e2SHidetoshi Shimokawa 	sbp_targ_methods,
2065e9e688e2SHidetoshi Shimokawa 	sizeof(struct sbp_targ_softc),
2066e9e688e2SHidetoshi Shimokawa };
2067e9e688e2SHidetoshi Shimokawa 
2068e9e688e2SHidetoshi Shimokawa DRIVER_MODULE(sbp_targ, firewire, sbp_targ_driver, sbp_targ_devclass, 0, 0);
2069e9e688e2SHidetoshi Shimokawa MODULE_VERSION(sbp_targ, 1);
2070e9e688e2SHidetoshi Shimokawa MODULE_DEPEND(sbp_targ, firewire, 1, 1, 1);
2071e9e688e2SHidetoshi Shimokawa MODULE_DEPEND(sbp_targ, cam, 1, 1, 1);
2072