1098ca2bdSWarner Losh /*-
2df57947fSPedro F. Giffuni * SPDX-License-Identifier: BSD-4-Clause
3df57947fSPedro F. Giffuni *
4e9e688e2SHidetoshi Shimokawa * Copyright (C) 2003
5e9e688e2SHidetoshi Shimokawa * Hidetoshi Shimokawa. All rights reserved.
6e9e688e2SHidetoshi Shimokawa *
7e9e688e2SHidetoshi Shimokawa * Redistribution and use in source and binary forms, with or without
8e9e688e2SHidetoshi Shimokawa * modification, are permitted provided that the following conditions
9e9e688e2SHidetoshi Shimokawa * are met:
10e9e688e2SHidetoshi Shimokawa * 1. Redistributions of source code must retain the above copyright
11e9e688e2SHidetoshi Shimokawa * notice, this list of conditions and the following disclaimer.
12e9e688e2SHidetoshi Shimokawa * 2. Redistributions in binary form must reproduce the above copyright
13e9e688e2SHidetoshi Shimokawa * notice, this list of conditions and the following disclaimer in the
14e9e688e2SHidetoshi Shimokawa * documentation and/or other materials provided with the distribution.
15e9e688e2SHidetoshi Shimokawa * 3. All advertising materials mentioning features or use of this software
16e9e688e2SHidetoshi Shimokawa * must display the following acknowledgement:
17e9e688e2SHidetoshi Shimokawa *
18e9e688e2SHidetoshi Shimokawa * This product includes software developed by Hidetoshi Shimokawa.
19e9e688e2SHidetoshi Shimokawa *
20e9e688e2SHidetoshi Shimokawa * 4. Neither the name of the author nor the names of its contributors
21e9e688e2SHidetoshi Shimokawa * may be used to endorse or promote products derived from this software
22e9e688e2SHidetoshi Shimokawa * without specific prior written permission.
23e9e688e2SHidetoshi Shimokawa *
24e9e688e2SHidetoshi Shimokawa * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25e9e688e2SHidetoshi Shimokawa * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26e9e688e2SHidetoshi Shimokawa * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27e9e688e2SHidetoshi Shimokawa * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28e9e688e2SHidetoshi Shimokawa * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29e9e688e2SHidetoshi Shimokawa * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30e9e688e2SHidetoshi Shimokawa * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31e9e688e2SHidetoshi Shimokawa * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32e9e688e2SHidetoshi Shimokawa * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33e9e688e2SHidetoshi Shimokawa * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34e9e688e2SHidetoshi Shimokawa * SUCH DAMAGE.
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
46e9e688e2SHidetoshi Shimokawa #include <sys/bus.h>
47e9e688e2SHidetoshi Shimokawa #include <machine/bus.h>
48e9e688e2SHidetoshi Shimokawa
49e9e688e2SHidetoshi Shimokawa #include <dev/firewire/firewire.h>
50e9e688e2SHidetoshi Shimokawa #include <dev/firewire/firewirereg.h>
51e9e688e2SHidetoshi Shimokawa #include <dev/firewire/iec13213.h>
52e9e688e2SHidetoshi Shimokawa #include <dev/firewire/sbp.h>
53e9e688e2SHidetoshi Shimokawa #include <dev/firewire/fwmem.h>
54e9e688e2SHidetoshi Shimokawa
55e9e688e2SHidetoshi Shimokawa #include <cam/cam.h>
56e9e688e2SHidetoshi Shimokawa #include <cam/cam_ccb.h>
57e9e688e2SHidetoshi Shimokawa #include <cam/cam_sim.h>
58e9e688e2SHidetoshi Shimokawa #include <cam/cam_xpt_sim.h>
59e9e688e2SHidetoshi Shimokawa #include <cam/cam_debug.h>
60e9e688e2SHidetoshi Shimokawa #include <cam/cam_periph.h>
61e9e688e2SHidetoshi Shimokawa #include <cam/scsi/scsi_all.h>
624636d244SSean Bruno #include <cam/scsi/scsi_message.h>
63e9e688e2SHidetoshi Shimokawa
64a73ff510SHidetoshi Shimokawa #define SBP_TARG_RECV_LEN 8
65a73ff510SHidetoshi Shimokawa #define MAX_INITIATORS 8
66e9e688e2SHidetoshi Shimokawa #define MAX_LUN 63
67a73ff510SHidetoshi Shimokawa #define MAX_LOGINS 63
68a73ff510SHidetoshi Shimokawa #define MAX_NODES 63
69e9e688e2SHidetoshi Shimokawa /*
70e9e688e2SHidetoshi Shimokawa * management/command block agent registers
71e9e688e2SHidetoshi Shimokawa *
72e9e688e2SHidetoshi Shimokawa * BASE 0xffff f001 0000 management port
73a73ff510SHidetoshi Shimokawa * BASE 0xffff f001 0020 command port for login id 0
74a73ff510SHidetoshi Shimokawa * BASE 0xffff f001 0040 command port for login id 1
75e9e688e2SHidetoshi Shimokawa *
76e9e688e2SHidetoshi Shimokawa */
77e9e688e2SHidetoshi Shimokawa #define SBP_TARG_MGM 0x10000 /* offset from 0xffff f000 000 */
78e9e688e2SHidetoshi Shimokawa #define SBP_TARG_BIND_HI 0xffff
79e9e688e2SHidetoshi Shimokawa #define SBP_TARG_BIND_LO(l) (0xf0000000 + SBP_TARG_MGM + 0x20 * ((l) + 1))
80e9e688e2SHidetoshi Shimokawa #define SBP_TARG_BIND_START (((u_int64_t)SBP_TARG_BIND_HI << 32) | \
81e9e688e2SHidetoshi Shimokawa SBP_TARG_BIND_LO(-1))
82e9e688e2SHidetoshi Shimokawa #define SBP_TARG_BIND_END (((u_int64_t)SBP_TARG_BIND_HI << 32) | \
83a73ff510SHidetoshi Shimokawa SBP_TARG_BIND_LO(MAX_LOGINS))
84a73ff510SHidetoshi Shimokawa #define SBP_TARG_LOGIN_ID(lo) (((lo) - SBP_TARG_BIND_LO(0))/0x20)
85e9e688e2SHidetoshi Shimokawa
86e9e688e2SHidetoshi Shimokawa #define FETCH_MGM 0
87e9e688e2SHidetoshi Shimokawa #define FETCH_CMD 1
88e9e688e2SHidetoshi Shimokawa #define FETCH_POINTER 2
89e9e688e2SHidetoshi Shimokawa
90a73ff510SHidetoshi Shimokawa #define F_LINK_ACTIVE (1 << 0)
91a73ff510SHidetoshi Shimokawa #define F_ATIO_STARVED (1 << 1)
92a73ff510SHidetoshi Shimokawa #define F_LOGIN (1 << 2)
93a73ff510SHidetoshi Shimokawa #define F_HOLD (1 << 3)
94a73ff510SHidetoshi Shimokawa #define F_FREEZED (1 << 4)
95a73ff510SHidetoshi Shimokawa
96d745c852SEd Schouten static MALLOC_DEFINE(M_SBP_TARG, "sbp_targ", "SBP-II/FireWire target mode");
97e9e688e2SHidetoshi Shimokawa
98e9e688e2SHidetoshi Shimokawa static int debug = 0;
99e9e688e2SHidetoshi Shimokawa
100e9e688e2SHidetoshi Shimokawa SYSCTL_INT(_debug, OID_AUTO, sbp_targ_debug, CTLFLAG_RW, &debug, 0,
101e9e688e2SHidetoshi Shimokawa "SBP target mode debug flag");
102e9e688e2SHidetoshi Shimokawa
103a73ff510SHidetoshi Shimokawa struct sbp_targ_login {
104a73ff510SHidetoshi Shimokawa struct sbp_targ_lstate *lstate;
105a73ff510SHidetoshi Shimokawa struct fw_device *fwdev;
106a73ff510SHidetoshi Shimokawa struct sbp_login_res loginres;
10703161bbcSDoug Rabson uint16_t fifo_hi;
10803161bbcSDoug Rabson uint16_t last_hi;
10903161bbcSDoug Rabson uint32_t fifo_lo;
11003161bbcSDoug Rabson uint32_t last_lo;
111a73ff510SHidetoshi Shimokawa STAILQ_HEAD(, orb_info) orbs;
112a73ff510SHidetoshi Shimokawa STAILQ_ENTRY(sbp_targ_login) link;
11303161bbcSDoug Rabson uint16_t hold_sec;
11403161bbcSDoug Rabson uint16_t id;
11503161bbcSDoug Rabson uint8_t flags;
11603161bbcSDoug Rabson uint8_t spd;
117a73ff510SHidetoshi Shimokawa struct callout hold_callout;
118a73ff510SHidetoshi Shimokawa };
119a73ff510SHidetoshi Shimokawa
120a73ff510SHidetoshi Shimokawa struct sbp_targ_lstate {
12103161bbcSDoug Rabson uint16_t lun;
122a73ff510SHidetoshi Shimokawa struct sbp_targ_softc *sc;
123a73ff510SHidetoshi Shimokawa struct cam_path *path;
124a73ff510SHidetoshi Shimokawa struct ccb_hdr_slist accept_tios;
125a73ff510SHidetoshi Shimokawa struct ccb_hdr_slist immed_notifies;
126a73ff510SHidetoshi Shimokawa struct crom_chunk model;
12703161bbcSDoug Rabson uint32_t flags;
128a73ff510SHidetoshi Shimokawa STAILQ_HEAD(, sbp_targ_login) logins;
129a73ff510SHidetoshi Shimokawa };
130a73ff510SHidetoshi Shimokawa
131e9e688e2SHidetoshi Shimokawa struct sbp_targ_softc {
132e9e688e2SHidetoshi Shimokawa struct firewire_dev_comm fd;
133e9e688e2SHidetoshi Shimokawa struct cam_sim *sim;
134e9e688e2SHidetoshi Shimokawa struct cam_path *path;
135e9e688e2SHidetoshi Shimokawa struct fw_bind fwb;
136e9e688e2SHidetoshi Shimokawa int ndevs;
137a73ff510SHidetoshi Shimokawa int flags;
138e9e688e2SHidetoshi Shimokawa struct crom_chunk unit;
139e9e688e2SHidetoshi Shimokawa struct sbp_targ_lstate *lstate[MAX_LUN];
140e9e688e2SHidetoshi Shimokawa struct sbp_targ_lstate *black_hole;
141a73ff510SHidetoshi Shimokawa struct sbp_targ_login *logins[MAX_LOGINS];
1429950b741SHidetoshi Shimokawa struct mtx mtx;
143e9e688e2SHidetoshi Shimokawa };
1449950b741SHidetoshi Shimokawa #define SBP_LOCK(sc) mtx_lock(&(sc)->mtx)
1459950b741SHidetoshi Shimokawa #define SBP_UNLOCK(sc) mtx_unlock(&(sc)->mtx)
146e9e688e2SHidetoshi Shimokawa
147e9e688e2SHidetoshi Shimokawa struct corb4 {
148e9e688e2SHidetoshi Shimokawa #if BYTE_ORDER == BIG_ENDIAN
14903161bbcSDoug Rabson uint32_t n:1,
150e9e688e2SHidetoshi Shimokawa rq_fmt:2,
151e9e688e2SHidetoshi Shimokawa :1,
152e9e688e2SHidetoshi Shimokawa dir:1,
153e9e688e2SHidetoshi Shimokawa spd:3,
154e9e688e2SHidetoshi Shimokawa max_payload:4,
155e9e688e2SHidetoshi Shimokawa page_table_present:1,
156e9e688e2SHidetoshi Shimokawa page_size:3,
157e9e688e2SHidetoshi Shimokawa data_size:16;
158e9e688e2SHidetoshi Shimokawa #else
15903161bbcSDoug Rabson uint32_t data_size:16,
160e9e688e2SHidetoshi Shimokawa page_size:3,
161e9e688e2SHidetoshi Shimokawa page_table_present:1,
162e9e688e2SHidetoshi Shimokawa max_payload:4,
163e9e688e2SHidetoshi Shimokawa spd:3,
164e9e688e2SHidetoshi Shimokawa dir:1,
165e9e688e2SHidetoshi Shimokawa :1,
166e9e688e2SHidetoshi Shimokawa rq_fmt:2,
167e9e688e2SHidetoshi Shimokawa n:1;
168e9e688e2SHidetoshi Shimokawa #endif
169e9e688e2SHidetoshi Shimokawa };
170e9e688e2SHidetoshi Shimokawa
171e9e688e2SHidetoshi Shimokawa struct morb4 {
172e9e688e2SHidetoshi Shimokawa #if BYTE_ORDER == BIG_ENDIAN
17303161bbcSDoug Rabson uint32_t n:1,
174e9e688e2SHidetoshi Shimokawa rq_fmt:2,
175e9e688e2SHidetoshi Shimokawa :9,
176e9e688e2SHidetoshi Shimokawa fun:4,
177e9e688e2SHidetoshi Shimokawa id:16;
178e9e688e2SHidetoshi Shimokawa #else
17903161bbcSDoug Rabson uint32_t id:16,
180e9e688e2SHidetoshi Shimokawa fun:4,
181e9e688e2SHidetoshi Shimokawa :9,
182e9e688e2SHidetoshi Shimokawa rq_fmt:2,
183e9e688e2SHidetoshi Shimokawa n:1;
184e9e688e2SHidetoshi Shimokawa #endif
185e9e688e2SHidetoshi Shimokawa };
186e9e688e2SHidetoshi Shimokawa
1874636d244SSean Bruno
1884636d244SSean Bruno /*
1894636d244SSean Bruno * Urestricted page table format
1904636d244SSean Bruno * states that the segment length
1914636d244SSean Bruno * and high base addr are in the first
1924636d244SSean Bruno * 32 bits and the base low is in
1934636d244SSean Bruno * the second
1944636d244SSean Bruno */
1954636d244SSean Bruno struct unrestricted_page_table_fmt {
1964636d244SSean Bruno uint16_t segment_len;
1974636d244SSean Bruno uint16_t segment_base_high;
1984636d244SSean Bruno uint32_t segment_base_low;
1994636d244SSean Bruno };
2004636d244SSean Bruno
2014636d244SSean Bruno
202e9e688e2SHidetoshi Shimokawa struct orb_info {
203e9e688e2SHidetoshi Shimokawa struct sbp_targ_softc *sc;
204e9e688e2SHidetoshi Shimokawa struct fw_device *fwdev;
205a73ff510SHidetoshi Shimokawa struct sbp_targ_login *login;
206e9e688e2SHidetoshi Shimokawa union ccb *ccb;
207e9e688e2SHidetoshi Shimokawa struct ccb_accept_tio *atio;
20803161bbcSDoug Rabson uint8_t state;
209e9e688e2SHidetoshi Shimokawa #define ORBI_STATUS_NONE 0
210e9e688e2SHidetoshi Shimokawa #define ORBI_STATUS_FETCH 1
211e9e688e2SHidetoshi Shimokawa #define ORBI_STATUS_ATIO 2
212e9e688e2SHidetoshi Shimokawa #define ORBI_STATUS_CTIO 3
213e9e688e2SHidetoshi Shimokawa #define ORBI_STATUS_STATUS 4
214e9e688e2SHidetoshi Shimokawa #define ORBI_STATUS_POINTER 5
215e9e688e2SHidetoshi Shimokawa #define ORBI_STATUS_ABORTED 7
21603161bbcSDoug Rabson uint8_t refcount;
21703161bbcSDoug Rabson uint16_t orb_hi;
21803161bbcSDoug Rabson uint32_t orb_lo;
21903161bbcSDoug Rabson uint32_t data_hi;
22003161bbcSDoug Rabson uint32_t data_lo;
221e9e688e2SHidetoshi Shimokawa struct corb4 orb4;
222e9e688e2SHidetoshi Shimokawa STAILQ_ENTRY(orb_info) link;
22303161bbcSDoug Rabson uint32_t orb[8];
2244636d244SSean Bruno struct unrestricted_page_table_fmt *page_table;
2254636d244SSean Bruno struct unrestricted_page_table_fmt *cur_pte;
2264636d244SSean Bruno struct unrestricted_page_table_fmt *last_pte;
2274636d244SSean Bruno uint32_t last_block_read;
228e9e688e2SHidetoshi Shimokawa struct sbp_status status;
229e9e688e2SHidetoshi Shimokawa };
230e9e688e2SHidetoshi Shimokawa
231e9e688e2SHidetoshi Shimokawa static char *orb_fun_name[] = {
232e9e688e2SHidetoshi Shimokawa ORB_FUN_NAMES
233e9e688e2SHidetoshi Shimokawa };
234e9e688e2SHidetoshi Shimokawa
235e9e688e2SHidetoshi Shimokawa static void sbp_targ_recv(struct fw_xfer *);
236e9e688e2SHidetoshi Shimokawa static void sbp_targ_fetch_orb(struct sbp_targ_softc *, struct fw_device *,
23703161bbcSDoug Rabson uint16_t, uint32_t, struct sbp_targ_login *, int);
2384636d244SSean Bruno static void sbp_targ_xfer_pt(struct orb_info *);
2399950b741SHidetoshi Shimokawa static void sbp_targ_abort(struct sbp_targ_softc *, struct orb_info *);
240e9e688e2SHidetoshi Shimokawa
241e9e688e2SHidetoshi Shimokawa static void
sbp_targ_identify(driver_t * driver,device_t parent)242e9e688e2SHidetoshi Shimokawa sbp_targ_identify(driver_t *driver, device_t parent)
243e9e688e2SHidetoshi Shimokawa {
244e9e688e2SHidetoshi Shimokawa BUS_ADD_CHILD(parent, 0, "sbp_targ", device_get_unit(parent));
245e9e688e2SHidetoshi Shimokawa }
246e9e688e2SHidetoshi Shimokawa
247e9e688e2SHidetoshi Shimokawa static int
sbp_targ_probe(device_t dev)248e9e688e2SHidetoshi Shimokawa sbp_targ_probe(device_t dev)
249e9e688e2SHidetoshi Shimokawa {
250e9e688e2SHidetoshi Shimokawa device_t pa;
251e9e688e2SHidetoshi Shimokawa
252e9e688e2SHidetoshi Shimokawa pa = device_get_parent(dev);
253e9e688e2SHidetoshi Shimokawa if (device_get_unit(dev) != device_get_unit(pa)) {
254e9e688e2SHidetoshi Shimokawa return (ENXIO);
255e9e688e2SHidetoshi Shimokawa }
256e9e688e2SHidetoshi Shimokawa
257e9e688e2SHidetoshi Shimokawa device_set_desc(dev, "SBP-2/SCSI over FireWire target mode");
258e9e688e2SHidetoshi Shimokawa return (0);
259e9e688e2SHidetoshi Shimokawa }
260e9e688e2SHidetoshi Shimokawa
261a73ff510SHidetoshi Shimokawa static void
sbp_targ_dealloc_login(struct sbp_targ_login * login)262a73ff510SHidetoshi Shimokawa sbp_targ_dealloc_login(struct sbp_targ_login *login)
263a73ff510SHidetoshi Shimokawa {
264a73ff510SHidetoshi Shimokawa struct orb_info *orbi, *next;
265a73ff510SHidetoshi Shimokawa
266a73ff510SHidetoshi Shimokawa if (login == NULL) {
26710d3ed64SHidetoshi Shimokawa printf("%s: login = NULL\n", __func__);
268a73ff510SHidetoshi Shimokawa return;
269a73ff510SHidetoshi Shimokawa }
270a73ff510SHidetoshi Shimokawa for (orbi = STAILQ_FIRST(&login->orbs); orbi != NULL; orbi = next) {
271a73ff510SHidetoshi Shimokawa next = STAILQ_NEXT(orbi, link);
2724636d244SSean Bruno if (debug)
2734636d244SSean Bruno printf("%s: free orbi %p\n", __func__, orbi);
274a73ff510SHidetoshi Shimokawa free(orbi, M_SBP_TARG);
2754636d244SSean Bruno orbi = NULL;
276a73ff510SHidetoshi Shimokawa }
277a73ff510SHidetoshi Shimokawa callout_stop(&login->hold_callout);
278a73ff510SHidetoshi Shimokawa
279a73ff510SHidetoshi Shimokawa STAILQ_REMOVE(&login->lstate->logins, login, sbp_targ_login, link);
280a73ff510SHidetoshi Shimokawa login->lstate->sc->logins[login->id] = NULL;
2814636d244SSean Bruno if (debug)
2824636d244SSean Bruno printf("%s: free login %p\n", __func__, login);
283a73ff510SHidetoshi Shimokawa free((void *)login, M_SBP_TARG);
2844636d244SSean Bruno login = NULL;
285a73ff510SHidetoshi Shimokawa }
286a73ff510SHidetoshi Shimokawa
287a73ff510SHidetoshi Shimokawa static void
sbp_targ_hold_expire(void * arg)288a73ff510SHidetoshi Shimokawa sbp_targ_hold_expire(void *arg)
289a73ff510SHidetoshi Shimokawa {
290a73ff510SHidetoshi Shimokawa struct sbp_targ_login *login;
291a73ff510SHidetoshi Shimokawa
292a73ff510SHidetoshi Shimokawa login = (struct sbp_targ_login *)arg;
293a73ff510SHidetoshi Shimokawa
294a73ff510SHidetoshi Shimokawa if (login->flags & F_HOLD) {
29510d3ed64SHidetoshi Shimokawa printf("%s: login_id=%d expired\n", __func__, login->id);
296a73ff510SHidetoshi Shimokawa sbp_targ_dealloc_login(login);
297a73ff510SHidetoshi Shimokawa } else {
29810d3ed64SHidetoshi Shimokawa printf("%s: login_id=%d not hold\n", __func__, login->id);
299a73ff510SHidetoshi Shimokawa }
300a73ff510SHidetoshi Shimokawa }
301a73ff510SHidetoshi Shimokawa
302e9e688e2SHidetoshi Shimokawa static void
sbp_targ_post_busreset(void * arg)303e9e688e2SHidetoshi Shimokawa sbp_targ_post_busreset(void *arg)
304e9e688e2SHidetoshi Shimokawa {
305e9e688e2SHidetoshi Shimokawa struct sbp_targ_softc *sc;
306e9e688e2SHidetoshi Shimokawa struct crom_src *src;
307e9e688e2SHidetoshi Shimokawa struct crom_chunk *root;
308e9e688e2SHidetoshi Shimokawa struct crom_chunk *unit;
309e9e688e2SHidetoshi Shimokawa struct sbp_targ_lstate *lstate;
310a73ff510SHidetoshi Shimokawa struct sbp_targ_login *login;
311e9e688e2SHidetoshi Shimokawa int i;
312e9e688e2SHidetoshi Shimokawa
313e9e688e2SHidetoshi Shimokawa sc = (struct sbp_targ_softc *)arg;
314e9e688e2SHidetoshi Shimokawa src = sc->fd.fc->crom_src;
315e9e688e2SHidetoshi Shimokawa root = sc->fd.fc->crom_root;
316e9e688e2SHidetoshi Shimokawa
317e9e688e2SHidetoshi Shimokawa unit = &sc->unit;
318e9e688e2SHidetoshi Shimokawa
319a73ff510SHidetoshi Shimokawa if ((sc->flags & F_FREEZED) == 0) {
320a73ff510SHidetoshi Shimokawa sc->flags |= F_FREEZED;
321a73ff510SHidetoshi Shimokawa xpt_freeze_simq(sc->sim, /*count*/1);
322a73ff510SHidetoshi Shimokawa } else {
32310d3ed64SHidetoshi Shimokawa printf("%s: already freezed\n", __func__);
324a73ff510SHidetoshi Shimokawa }
325a73ff510SHidetoshi Shimokawa
326e9e688e2SHidetoshi Shimokawa bzero(unit, sizeof(struct crom_chunk));
327e9e688e2SHidetoshi Shimokawa
328e9e688e2SHidetoshi Shimokawa crom_add_chunk(src, root, unit, CROM_UDIR);
329e9e688e2SHidetoshi Shimokawa crom_add_entry(unit, CSRKEY_SPEC, CSRVAL_ANSIT10);
330e9e688e2SHidetoshi Shimokawa crom_add_entry(unit, CSRKEY_VER, CSRVAL_T10SBP2);
331e9e688e2SHidetoshi Shimokawa crom_add_entry(unit, CSRKEY_COM_SPEC, CSRVAL_ANSIT10);
332e9e688e2SHidetoshi Shimokawa crom_add_entry(unit, CSRKEY_COM_SET, CSRVAL_SCSI);
333e9e688e2SHidetoshi Shimokawa
334e9e688e2SHidetoshi Shimokawa crom_add_entry(unit, CROM_MGM, SBP_TARG_MGM >> 2);
335e9e688e2SHidetoshi Shimokawa crom_add_entry(unit, CSRKEY_UNIT_CH, (10<<8) | 8);
336e9e688e2SHidetoshi Shimokawa
337e9e688e2SHidetoshi Shimokawa for (i = 0; i < MAX_LUN; i++) {
338e9e688e2SHidetoshi Shimokawa lstate = sc->lstate[i];
339e9e688e2SHidetoshi Shimokawa if (lstate == NULL)
340e9e688e2SHidetoshi Shimokawa continue;
341e9e688e2SHidetoshi Shimokawa crom_add_entry(unit, CSRKEY_FIRM_VER, 1);
342e9e688e2SHidetoshi Shimokawa crom_add_entry(unit, CROM_LUN, i);
343e9e688e2SHidetoshi Shimokawa crom_add_entry(unit, CSRKEY_MODEL, 1);
344e9e688e2SHidetoshi Shimokawa crom_add_simple_text(src, unit, &lstate->model, "TargetMode");
345e9e688e2SHidetoshi Shimokawa }
346a73ff510SHidetoshi Shimokawa
347a73ff510SHidetoshi Shimokawa /* Process for reconnection hold time */
348a73ff510SHidetoshi Shimokawa for (i = 0; i < MAX_LOGINS; i++) {
349a73ff510SHidetoshi Shimokawa login = sc->logins[i];
350a73ff510SHidetoshi Shimokawa if (login == NULL)
351a73ff510SHidetoshi Shimokawa continue;
3529950b741SHidetoshi Shimokawa sbp_targ_abort(sc, STAILQ_FIRST(&login->orbs));
353a73ff510SHidetoshi Shimokawa if (login->flags & F_LOGIN) {
354a73ff510SHidetoshi Shimokawa login->flags |= F_HOLD;
355a73ff510SHidetoshi Shimokawa callout_reset(&login->hold_callout,
356a73ff510SHidetoshi Shimokawa hz * login->hold_sec,
357a73ff510SHidetoshi Shimokawa sbp_targ_hold_expire, (void *)login);
358a73ff510SHidetoshi Shimokawa }
359a73ff510SHidetoshi Shimokawa }
360a73ff510SHidetoshi Shimokawa }
361a73ff510SHidetoshi Shimokawa
362a73ff510SHidetoshi Shimokawa static void
sbp_targ_post_explore(void * arg)363a73ff510SHidetoshi Shimokawa sbp_targ_post_explore(void *arg)
364a73ff510SHidetoshi Shimokawa {
365a73ff510SHidetoshi Shimokawa struct sbp_targ_softc *sc;
366a73ff510SHidetoshi Shimokawa
367a73ff510SHidetoshi Shimokawa sc = (struct sbp_targ_softc *)arg;
368a73ff510SHidetoshi Shimokawa sc->flags &= ~F_FREEZED;
369a73ff510SHidetoshi Shimokawa xpt_release_simq(sc->sim, /*run queue*/TRUE);
370a73ff510SHidetoshi Shimokawa return;
371e9e688e2SHidetoshi Shimokawa }
372e9e688e2SHidetoshi Shimokawa
373e9e688e2SHidetoshi Shimokawa static cam_status
sbp_targ_find_devs(struct sbp_targ_softc * sc,union ccb * ccb,struct sbp_targ_lstate ** lstate,int notfound_failure)374e9e688e2SHidetoshi Shimokawa sbp_targ_find_devs(struct sbp_targ_softc *sc, union ccb *ccb,
375e9e688e2SHidetoshi Shimokawa struct sbp_targ_lstate **lstate, int notfound_failure)
376e9e688e2SHidetoshi Shimokawa {
377e9e688e2SHidetoshi Shimokawa u_int lun;
378e9e688e2SHidetoshi Shimokawa
379e9e688e2SHidetoshi Shimokawa /* XXX 0 is the only vaild target_id */
380e9e688e2SHidetoshi Shimokawa if (ccb->ccb_h.target_id == CAM_TARGET_WILDCARD &&
381e9e688e2SHidetoshi Shimokawa ccb->ccb_h.target_lun == CAM_LUN_WILDCARD) {
382e9e688e2SHidetoshi Shimokawa *lstate = sc->black_hole;
3834636d244SSean Bruno if (debug)
3844636d244SSean Bruno printf("setting black hole for this target id(%d)\n", ccb->ccb_h.target_id);
385e9e688e2SHidetoshi Shimokawa return (CAM_REQ_CMP);
386e9e688e2SHidetoshi Shimokawa }
387e9e688e2SHidetoshi Shimokawa
388e9e688e2SHidetoshi Shimokawa lun = ccb->ccb_h.target_lun;
389e9e688e2SHidetoshi Shimokawa if (lun >= MAX_LUN)
390e9e688e2SHidetoshi Shimokawa return (CAM_LUN_INVALID);
391e9e688e2SHidetoshi Shimokawa
392e9e688e2SHidetoshi Shimokawa *lstate = sc->lstate[lun];
393e9e688e2SHidetoshi Shimokawa
3944636d244SSean Bruno if (notfound_failure != 0 && *lstate == NULL) {
3954636d244SSean Bruno if (debug)
3964636d244SSean Bruno printf("%s: lstate for lun is invalid, target(%d), lun(%d)\n",
3974636d244SSean Bruno __func__, ccb->ccb_h.target_id, lun);
398e9e688e2SHidetoshi Shimokawa return (CAM_PATH_INVALID);
3994636d244SSean Bruno } else
4004636d244SSean Bruno if (debug)
4014636d244SSean Bruno printf("%s: setting lstate for tgt(%d) lun(%d)\n",
4024636d244SSean Bruno __func__,ccb->ccb_h.target_id, lun);
403e9e688e2SHidetoshi Shimokawa
404e9e688e2SHidetoshi Shimokawa return (CAM_REQ_CMP);
405e9e688e2SHidetoshi Shimokawa }
406e9e688e2SHidetoshi Shimokawa
407e9e688e2SHidetoshi Shimokawa static void
sbp_targ_en_lun(struct sbp_targ_softc * sc,union ccb * ccb)408e9e688e2SHidetoshi Shimokawa sbp_targ_en_lun(struct sbp_targ_softc *sc, union ccb *ccb)
409e9e688e2SHidetoshi Shimokawa {
410e9e688e2SHidetoshi Shimokawa struct ccb_en_lun *cel = &ccb->cel;
411e9e688e2SHidetoshi Shimokawa struct sbp_targ_lstate *lstate;
412e9e688e2SHidetoshi Shimokawa cam_status status;
413e9e688e2SHidetoshi Shimokawa
414e9e688e2SHidetoshi Shimokawa status = sbp_targ_find_devs(sc, ccb, &lstate, 0);
415e9e688e2SHidetoshi Shimokawa if (status != CAM_REQ_CMP) {
416e9e688e2SHidetoshi Shimokawa ccb->ccb_h.status = status;
417e9e688e2SHidetoshi Shimokawa return;
418e9e688e2SHidetoshi Shimokawa }
419e9e688e2SHidetoshi Shimokawa
420e9e688e2SHidetoshi Shimokawa if (cel->enable != 0) {
421e9e688e2SHidetoshi Shimokawa if (lstate != NULL) {
422e9e688e2SHidetoshi Shimokawa xpt_print_path(ccb->ccb_h.path);
423e9e688e2SHidetoshi Shimokawa printf("Lun already enabled\n");
424e9e688e2SHidetoshi Shimokawa ccb->ccb_h.status = CAM_LUN_ALRDY_ENA;
425e9e688e2SHidetoshi Shimokawa return;
426e9e688e2SHidetoshi Shimokawa }
427e9e688e2SHidetoshi Shimokawa if (cel->grp6_len != 0 || cel->grp7_len != 0) {
428e9e688e2SHidetoshi Shimokawa ccb->ccb_h.status = CAM_REQ_INVALID;
429e9e688e2SHidetoshi Shimokawa printf("Non-zero Group Codes\n");
430e9e688e2SHidetoshi Shimokawa return;
431e9e688e2SHidetoshi Shimokawa }
432e9e688e2SHidetoshi Shimokawa lstate = (struct sbp_targ_lstate *)
433e9e688e2SHidetoshi Shimokawa malloc(sizeof(*lstate), M_SBP_TARG, M_NOWAIT | M_ZERO);
434e9e688e2SHidetoshi Shimokawa if (lstate == NULL) {
435e9e688e2SHidetoshi Shimokawa xpt_print_path(ccb->ccb_h.path);
436e9e688e2SHidetoshi Shimokawa printf("Couldn't allocate lstate\n");
437e9e688e2SHidetoshi Shimokawa ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
438e9e688e2SHidetoshi Shimokawa return;
4394636d244SSean Bruno } else {
4404636d244SSean Bruno if (debug)
4414636d244SSean Bruno printf("%s: malloc'd lstate %p\n",__func__, lstate);
442e9e688e2SHidetoshi Shimokawa }
4434636d244SSean Bruno if (ccb->ccb_h.target_id == CAM_TARGET_WILDCARD) {
444e9e688e2SHidetoshi Shimokawa sc->black_hole = lstate;
4454636d244SSean Bruno if (debug)
4464636d244SSean Bruno printf("Blackhole set due to target id == %d\n",
4474636d244SSean Bruno ccb->ccb_h.target_id);
4484636d244SSean Bruno } else
449e9e688e2SHidetoshi Shimokawa sc->lstate[ccb->ccb_h.target_lun] = lstate;
4504636d244SSean Bruno
451e9e688e2SHidetoshi Shimokawa memset(lstate, 0, sizeof(*lstate));
452e9e688e2SHidetoshi Shimokawa lstate->sc = sc;
453e9e688e2SHidetoshi Shimokawa status = xpt_create_path(&lstate->path, /*periph*/NULL,
454e9e688e2SHidetoshi Shimokawa xpt_path_path_id(ccb->ccb_h.path),
455e9e688e2SHidetoshi Shimokawa xpt_path_target_id(ccb->ccb_h.path),
456e9e688e2SHidetoshi Shimokawa xpt_path_lun_id(ccb->ccb_h.path));
457e9e688e2SHidetoshi Shimokawa if (status != CAM_REQ_CMP) {
458e9e688e2SHidetoshi Shimokawa free(lstate, M_SBP_TARG);
4594636d244SSean Bruno lstate = NULL;
460e9e688e2SHidetoshi Shimokawa xpt_print_path(ccb->ccb_h.path);
461e9e688e2SHidetoshi Shimokawa printf("Couldn't allocate path\n");
462e9e688e2SHidetoshi Shimokawa ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
463e9e688e2SHidetoshi Shimokawa return;
464e9e688e2SHidetoshi Shimokawa }
465e9e688e2SHidetoshi Shimokawa SLIST_INIT(&lstate->accept_tios);
466e9e688e2SHidetoshi Shimokawa SLIST_INIT(&lstate->immed_notifies);
467a73ff510SHidetoshi Shimokawa STAILQ_INIT(&lstate->logins);
468e9e688e2SHidetoshi Shimokawa
469e9e688e2SHidetoshi Shimokawa ccb->ccb_h.status = CAM_REQ_CMP;
470e9e688e2SHidetoshi Shimokawa xpt_print_path(ccb->ccb_h.path);
471e9e688e2SHidetoshi Shimokawa printf("Lun now enabled for target mode\n");
472e9e688e2SHidetoshi Shimokawa /* bus reset */
473e9e688e2SHidetoshi Shimokawa sc->fd.fc->ibr(sc->fd.fc);
474e9e688e2SHidetoshi Shimokawa } else {
475a73ff510SHidetoshi Shimokawa struct sbp_targ_login *login, *next;
476a73ff510SHidetoshi Shimokawa
477e9e688e2SHidetoshi Shimokawa if (lstate == NULL) {
478e9e688e2SHidetoshi Shimokawa ccb->ccb_h.status = CAM_LUN_INVALID;
4794636d244SSean Bruno printf("Invalid lstate for this target\n");
480e9e688e2SHidetoshi Shimokawa return;
481e9e688e2SHidetoshi Shimokawa }
482e9e688e2SHidetoshi Shimokawa ccb->ccb_h.status = CAM_REQ_CMP;
483e9e688e2SHidetoshi Shimokawa
484e9e688e2SHidetoshi Shimokawa if (SLIST_FIRST(&lstate->accept_tios) != NULL) {
485e9e688e2SHidetoshi Shimokawa printf("ATIOs pending\n");
486e9e688e2SHidetoshi Shimokawa ccb->ccb_h.status = CAM_REQ_INVALID;
487e9e688e2SHidetoshi Shimokawa }
488e9e688e2SHidetoshi Shimokawa
489e9e688e2SHidetoshi Shimokawa if (SLIST_FIRST(&lstate->immed_notifies) != NULL) {
490e9e688e2SHidetoshi Shimokawa printf("INOTs pending\n");
491e9e688e2SHidetoshi Shimokawa ccb->ccb_h.status = CAM_REQ_INVALID;
492e9e688e2SHidetoshi Shimokawa }
493e9e688e2SHidetoshi Shimokawa
494e9e688e2SHidetoshi Shimokawa if (ccb->ccb_h.status != CAM_REQ_CMP) {
4954636d244SSean Bruno printf("status != CAM_REQ_CMP\n");
496e9e688e2SHidetoshi Shimokawa return;
497e9e688e2SHidetoshi Shimokawa }
498e9e688e2SHidetoshi Shimokawa
499e9e688e2SHidetoshi Shimokawa xpt_print_path(ccb->ccb_h.path);
500e9e688e2SHidetoshi Shimokawa printf("Target mode disabled\n");
501e9e688e2SHidetoshi Shimokawa xpt_free_path(lstate->path);
502e9e688e2SHidetoshi Shimokawa
503a73ff510SHidetoshi Shimokawa for (login = STAILQ_FIRST(&lstate->logins); login != NULL;
504a73ff510SHidetoshi Shimokawa login = next) {
505a73ff510SHidetoshi Shimokawa next = STAILQ_NEXT(login, link);
506a73ff510SHidetoshi Shimokawa sbp_targ_dealloc_login(login);
507e9e688e2SHidetoshi Shimokawa }
508e9e688e2SHidetoshi Shimokawa
509e9e688e2SHidetoshi Shimokawa if (ccb->ccb_h.target_id == CAM_TARGET_WILDCARD)
510e9e688e2SHidetoshi Shimokawa sc->black_hole = NULL;
511e9e688e2SHidetoshi Shimokawa else
512e9e688e2SHidetoshi Shimokawa sc->lstate[ccb->ccb_h.target_lun] = NULL;
5134636d244SSean Bruno if (debug)
5144636d244SSean Bruno printf("%s: free lstate %p\n", __func__, lstate);
515e9e688e2SHidetoshi Shimokawa free(lstate, M_SBP_TARG);
5164636d244SSean Bruno lstate = NULL;
517e9e688e2SHidetoshi Shimokawa
518e9e688e2SHidetoshi Shimokawa /* bus reset */
519e9e688e2SHidetoshi Shimokawa sc->fd.fc->ibr(sc->fd.fc);
520e9e688e2SHidetoshi Shimokawa }
521e9e688e2SHidetoshi Shimokawa }
522e9e688e2SHidetoshi Shimokawa
523e9e688e2SHidetoshi Shimokawa static void
sbp_targ_send_lstate_events(struct sbp_targ_softc * sc,struct sbp_targ_lstate * lstate)524e9e688e2SHidetoshi Shimokawa sbp_targ_send_lstate_events(struct sbp_targ_softc *sc,
525e9e688e2SHidetoshi Shimokawa struct sbp_targ_lstate *lstate)
526e9e688e2SHidetoshi Shimokawa {
527e9e688e2SHidetoshi Shimokawa #if 0
528e9e688e2SHidetoshi Shimokawa struct ccb_hdr *ccbh;
529b79dc8a8SKenneth D. Merry struct ccb_immediate_notify *inot;
530e9e688e2SHidetoshi Shimokawa
53110d3ed64SHidetoshi Shimokawa printf("%s: not implemented yet\n", __func__);
532e9e688e2SHidetoshi Shimokawa #endif
533e9e688e2SHidetoshi Shimokawa }
534e9e688e2SHidetoshi Shimokawa
5359950b741SHidetoshi Shimokawa
5369950b741SHidetoshi Shimokawa static __inline void
sbp_targ_remove_orb_info_locked(struct sbp_targ_login * login,struct orb_info * orbi)5379950b741SHidetoshi Shimokawa sbp_targ_remove_orb_info_locked(struct sbp_targ_login *login, struct orb_info *orbi)
5389950b741SHidetoshi Shimokawa {
5399950b741SHidetoshi Shimokawa STAILQ_REMOVE(&login->orbs, orbi, orb_info, link);
5409950b741SHidetoshi Shimokawa }
5419950b741SHidetoshi Shimokawa
542e9e688e2SHidetoshi Shimokawa static __inline void
sbp_targ_remove_orb_info(struct sbp_targ_login * login,struct orb_info * orbi)543a73ff510SHidetoshi Shimokawa sbp_targ_remove_orb_info(struct sbp_targ_login *login, struct orb_info *orbi)
544e9e688e2SHidetoshi Shimokawa {
5459950b741SHidetoshi Shimokawa SBP_LOCK(orbi->sc);
546a73ff510SHidetoshi Shimokawa STAILQ_REMOVE(&login->orbs, orbi, orb_info, link);
5479950b741SHidetoshi Shimokawa SBP_UNLOCK(orbi->sc);
548e9e688e2SHidetoshi Shimokawa }
549e9e688e2SHidetoshi Shimokawa
550e9e688e2SHidetoshi Shimokawa /*
551e9e688e2SHidetoshi Shimokawa * tag_id/init_id encoding
552e9e688e2SHidetoshi Shimokawa *
553e9e688e2SHidetoshi Shimokawa * tag_id and init_id has only 32bit for each.
554e9e688e2SHidetoshi Shimokawa * scsi_target can handle very limited number(up to 15) of init_id.
555e9e688e2SHidetoshi Shimokawa * we have to encode 48bit orb and 64bit EUI64 into these
556e9e688e2SHidetoshi Shimokawa * variables.
557e9e688e2SHidetoshi Shimokawa *
558e9e688e2SHidetoshi Shimokawa * tag_id represents lower 32bit of ORB address.
559a73ff510SHidetoshi Shimokawa * init_id represents login_id.
560e9e688e2SHidetoshi Shimokawa *
561e9e688e2SHidetoshi Shimokawa */
562e9e688e2SHidetoshi Shimokawa
563e9e688e2SHidetoshi Shimokawa static struct orb_info *
sbp_targ_get_orb_info(struct sbp_targ_lstate * lstate,u_int tag_id,u_int init_id)564e9e688e2SHidetoshi Shimokawa sbp_targ_get_orb_info(struct sbp_targ_lstate *lstate,
565e9e688e2SHidetoshi Shimokawa u_int tag_id, u_int init_id)
566e9e688e2SHidetoshi Shimokawa {
567a73ff510SHidetoshi Shimokawa struct sbp_targ_login *login;
568e9e688e2SHidetoshi Shimokawa struct orb_info *orbi;
569e9e688e2SHidetoshi Shimokawa
570a73ff510SHidetoshi Shimokawa login = lstate->sc->logins[init_id];
571a73ff510SHidetoshi Shimokawa if (login == NULL) {
57210d3ed64SHidetoshi Shimokawa printf("%s: no such login\n", __func__);
573a73ff510SHidetoshi Shimokawa return (NULL);
574a73ff510SHidetoshi Shimokawa }
575a73ff510SHidetoshi Shimokawa STAILQ_FOREACH(orbi, &login->orbs, link)
576a73ff510SHidetoshi Shimokawa if (orbi->orb_lo == tag_id)
577e9e688e2SHidetoshi Shimokawa goto found;
5789950b741SHidetoshi Shimokawa printf("%s: orb not found tag_id=0x%08x init_id=%d\n",
5799950b741SHidetoshi Shimokawa __func__, tag_id, init_id);
580e9e688e2SHidetoshi Shimokawa return (NULL);
581e9e688e2SHidetoshi Shimokawa found:
582e9e688e2SHidetoshi Shimokawa return (orbi);
583e9e688e2SHidetoshi Shimokawa }
584e9e688e2SHidetoshi Shimokawa
585e9e688e2SHidetoshi Shimokawa static void
sbp_targ_abort(struct sbp_targ_softc * sc,struct orb_info * orbi)5869950b741SHidetoshi Shimokawa sbp_targ_abort(struct sbp_targ_softc *sc, struct orb_info *orbi)
587e9e688e2SHidetoshi Shimokawa {
588e9e688e2SHidetoshi Shimokawa struct orb_info *norbi;
589e9e688e2SHidetoshi Shimokawa
5909950b741SHidetoshi Shimokawa SBP_LOCK(sc);
591e9e688e2SHidetoshi Shimokawa for (; orbi != NULL; orbi = norbi) {
5929950b741SHidetoshi Shimokawa printf("%s: status=%d ccb=%p\n", __func__, orbi->state, orbi->ccb);
593e9e688e2SHidetoshi Shimokawa norbi = STAILQ_NEXT(orbi, link);
594e9e688e2SHidetoshi Shimokawa if (orbi->state != ORBI_STATUS_ABORTED) {
595e9e688e2SHidetoshi Shimokawa if (orbi->ccb != NULL) {
596e9e688e2SHidetoshi Shimokawa orbi->ccb->ccb_h.status = CAM_REQ_ABORTED;
597e9e688e2SHidetoshi Shimokawa xpt_done(orbi->ccb);
598e9e688e2SHidetoshi Shimokawa orbi->ccb = NULL;
599e9e688e2SHidetoshi Shimokawa }
600e9e688e2SHidetoshi Shimokawa if (orbi->state <= ORBI_STATUS_ATIO) {
6019950b741SHidetoshi Shimokawa sbp_targ_remove_orb_info_locked(orbi->login, orbi);
6024636d244SSean Bruno if (debug)
6034636d244SSean Bruno printf("%s: free orbi %p\n", __func__, orbi);
604e9e688e2SHidetoshi Shimokawa free(orbi, M_SBP_TARG);
6054636d244SSean Bruno orbi = NULL;
606e9e688e2SHidetoshi Shimokawa } else
607e9e688e2SHidetoshi Shimokawa orbi->state = ORBI_STATUS_ABORTED;
608e9e688e2SHidetoshi Shimokawa }
609e9e688e2SHidetoshi Shimokawa }
6109950b741SHidetoshi Shimokawa SBP_UNLOCK(sc);
611e9e688e2SHidetoshi Shimokawa }
612e9e688e2SHidetoshi Shimokawa
613e9e688e2SHidetoshi Shimokawa static void
sbp_targ_free_orbi(struct fw_xfer * xfer)614e9e688e2SHidetoshi Shimokawa sbp_targ_free_orbi(struct fw_xfer *xfer)
615e9e688e2SHidetoshi Shimokawa {
616e9e688e2SHidetoshi Shimokawa struct orb_info *orbi;
617e9e688e2SHidetoshi Shimokawa
618e9e688e2SHidetoshi Shimokawa if (xfer->resp != 0) {
619e9e688e2SHidetoshi Shimokawa /* XXX */
62010d3ed64SHidetoshi Shimokawa printf("%s: xfer->resp = %d\n", __func__, xfer->resp);
621e9e688e2SHidetoshi Shimokawa }
6224636d244SSean Bruno orbi = (struct orb_info *)xfer->sc;
6234636d244SSean Bruno if ( orbi->page_table != NULL ) {
6244636d244SSean Bruno if (debug)
6254636d244SSean Bruno printf("%s: free orbi->page_table %p\n", __func__, orbi->page_table);
6264636d244SSean Bruno free(orbi->page_table, M_SBP_TARG);
6274636d244SSean Bruno orbi->page_table = NULL;
6284636d244SSean Bruno }
6294636d244SSean Bruno if (debug)
6304636d244SSean Bruno printf("%s: free orbi %p\n", __func__, orbi);
631e9e688e2SHidetoshi Shimokawa free(orbi, M_SBP_TARG);
6324636d244SSean Bruno orbi = NULL;
633e9e688e2SHidetoshi Shimokawa fw_xfer_free(xfer);
634e9e688e2SHidetoshi Shimokawa }
635e9e688e2SHidetoshi Shimokawa
636e9e688e2SHidetoshi Shimokawa static void
sbp_targ_status_FIFO(struct orb_info * orbi,uint32_t fifo_hi,uint32_t fifo_lo,int dequeue)637e9e688e2SHidetoshi Shimokawa sbp_targ_status_FIFO(struct orb_info *orbi,
63803161bbcSDoug Rabson uint32_t fifo_hi, uint32_t fifo_lo, int dequeue)
639e9e688e2SHidetoshi Shimokawa {
640e9e688e2SHidetoshi Shimokawa struct fw_xfer *xfer;
641e9e688e2SHidetoshi Shimokawa
642e9e688e2SHidetoshi Shimokawa if (dequeue)
643a73ff510SHidetoshi Shimokawa sbp_targ_remove_orb_info(orbi->login, orbi);
644e9e688e2SHidetoshi Shimokawa
645e9e688e2SHidetoshi Shimokawa xfer = fwmem_write_block(orbi->fwdev, (void *)orbi,
6464636d244SSean Bruno /*spd*/FWSPD_S400, fifo_hi, fifo_lo,
64703161bbcSDoug Rabson sizeof(uint32_t) * (orbi->status.len + 1), (char *)&orbi->status,
648e9e688e2SHidetoshi Shimokawa sbp_targ_free_orbi);
649e9e688e2SHidetoshi Shimokawa
650e9e688e2SHidetoshi Shimokawa if (xfer == NULL) {
651e9e688e2SHidetoshi Shimokawa /* XXX */
65210d3ed64SHidetoshi Shimokawa printf("%s: xfer == NULL\n", __func__);
653e9e688e2SHidetoshi Shimokawa }
654e9e688e2SHidetoshi Shimokawa }
655e9e688e2SHidetoshi Shimokawa
6564636d244SSean Bruno /*
6574636d244SSean Bruno * Generate the appropriate CAM status for the
6584636d244SSean Bruno * target.
6594636d244SSean Bruno */
660e9e688e2SHidetoshi Shimokawa static void
sbp_targ_send_status(struct orb_info * orbi,union ccb * ccb)661e9e688e2SHidetoshi Shimokawa sbp_targ_send_status(struct orb_info *orbi, union ccb *ccb)
662e9e688e2SHidetoshi Shimokawa {
663e9e688e2SHidetoshi Shimokawa struct sbp_status *sbp_status;
664ea47b6c8SMatt Jacob #if 0
6659950b741SHidetoshi Shimokawa struct orb_info *norbi;
666ea47b6c8SMatt Jacob #endif
667e9e688e2SHidetoshi Shimokawa
668e9e688e2SHidetoshi Shimokawa sbp_status = &orbi->status;
669e9e688e2SHidetoshi Shimokawa
670e9e688e2SHidetoshi Shimokawa orbi->state = ORBI_STATUS_STATUS;
671e9e688e2SHidetoshi Shimokawa
672e9e688e2SHidetoshi Shimokawa sbp_status->resp = 0; /* XXX */
673e9e688e2SHidetoshi Shimokawa sbp_status->status = 0; /* XXX */
674e9e688e2SHidetoshi Shimokawa sbp_status->dead = 0; /* XXX */
675e9e688e2SHidetoshi Shimokawa
6764636d244SSean Bruno ccb->ccb_h.status= CAM_REQ_CMP;
6774636d244SSean Bruno
678e9e688e2SHidetoshi Shimokawa switch (ccb->csio.scsi_status) {
679e9e688e2SHidetoshi Shimokawa case SCSI_STATUS_OK:
680e9e688e2SHidetoshi Shimokawa if (debug)
68110d3ed64SHidetoshi Shimokawa printf("%s: STATUS_OK\n", __func__);
682e9e688e2SHidetoshi Shimokawa sbp_status->len = 1;
683e9e688e2SHidetoshi Shimokawa break;
684e9e688e2SHidetoshi Shimokawa case SCSI_STATUS_CHECK_COND:
6854636d244SSean Bruno if (debug)
6864636d244SSean Bruno printf("%s: STATUS SCSI_STATUS_CHECK_COND\n", __func__);
6874636d244SSean Bruno goto process_scsi_status;
688e9e688e2SHidetoshi Shimokawa case SCSI_STATUS_BUSY:
6894636d244SSean Bruno if (debug)
6904636d244SSean Bruno printf("%s: STATUS SCSI_STATUS_BUSY\n", __func__);
6914636d244SSean Bruno goto process_scsi_status;
692e9e688e2SHidetoshi Shimokawa case SCSI_STATUS_CMD_TERMINATED:
6934636d244SSean Bruno process_scsi_status:
694e9e688e2SHidetoshi Shimokawa {
695e9e688e2SHidetoshi Shimokawa struct sbp_cmd_status *sbp_cmd_status;
696e9e688e2SHidetoshi Shimokawa struct scsi_sense_data *sense;
6971cc052e8SKenneth D. Merry int error_code, sense_key, asc, ascq;
6981cc052e8SKenneth D. Merry uint8_t stream_bits;
6991cc052e8SKenneth D. Merry uint8_t sks[3];
7001cc052e8SKenneth D. Merry uint64_t info;
7011cc052e8SKenneth D. Merry int64_t sinfo;
7021cc052e8SKenneth D. Merry int sense_len;
703e9e688e2SHidetoshi Shimokawa
704e9e688e2SHidetoshi Shimokawa sbp_cmd_status = (struct sbp_cmd_status *)&sbp_status->data[0];
705e9e688e2SHidetoshi Shimokawa sbp_cmd_status->status = ccb->csio.scsi_status;
706e9e688e2SHidetoshi Shimokawa sense = &ccb->csio.sense_data;
707e9e688e2SHidetoshi Shimokawa
7089950b741SHidetoshi Shimokawa #if 0 /* XXX What we should do? */
7099950b741SHidetoshi Shimokawa #if 0
7109950b741SHidetoshi Shimokawa sbp_targ_abort(orbi->sc, STAILQ_NEXT(orbi, link));
7119950b741SHidetoshi Shimokawa #else
7129950b741SHidetoshi Shimokawa norbi = STAILQ_NEXT(orbi, link);
7139950b741SHidetoshi Shimokawa while (norbi) {
7149950b741SHidetoshi Shimokawa printf("%s: status=%d\n", __func__, norbi->state);
7159950b741SHidetoshi Shimokawa if (norbi->ccb != NULL) {
7169950b741SHidetoshi Shimokawa norbi->ccb->ccb_h.status = CAM_REQ_ABORTED;
7179950b741SHidetoshi Shimokawa xpt_done(norbi->ccb);
7189950b741SHidetoshi Shimokawa norbi->ccb = NULL;
7199950b741SHidetoshi Shimokawa }
7209950b741SHidetoshi Shimokawa sbp_targ_remove_orb_info_locked(orbi->login, norbi);
7219950b741SHidetoshi Shimokawa norbi = STAILQ_NEXT(norbi, link);
7229950b741SHidetoshi Shimokawa free(norbi, M_SBP_TARG);
7239950b741SHidetoshi Shimokawa }
7249950b741SHidetoshi Shimokawa #endif
7259950b741SHidetoshi Shimokawa #endif
726e9e688e2SHidetoshi Shimokawa
7271cc052e8SKenneth D. Merry sense_len = ccb->csio.sense_len - ccb->csio.sense_resid;
7281cc052e8SKenneth D. Merry scsi_extract_sense_len(sense, sense_len, &error_code,
7291cc052e8SKenneth D. Merry &sense_key, &asc, &ascq, /*show_errors*/ 0);
7301cc052e8SKenneth D. Merry
7311cc052e8SKenneth D. Merry switch (error_code) {
7321cc052e8SKenneth D. Merry case SSD_CURRENT_ERROR:
7331cc052e8SKenneth D. Merry case SSD_DESC_CURRENT_ERROR:
734e9e688e2SHidetoshi Shimokawa sbp_cmd_status->sfmt = SBP_SFMT_CURR;
7351cc052e8SKenneth D. Merry break;
7361cc052e8SKenneth D. Merry default:
737e9e688e2SHidetoshi Shimokawa sbp_cmd_status->sfmt = SBP_SFMT_DEFER;
7381cc052e8SKenneth D. Merry break;
7391cc052e8SKenneth D. Merry }
740e9e688e2SHidetoshi Shimokawa
7411cc052e8SKenneth D. Merry if (scsi_get_sense_info(sense, sense_len, SSD_DESC_INFO, &info,
7421cc052e8SKenneth D. Merry &sinfo) == 0) {
7431cc052e8SKenneth D. Merry uint32_t info_trunc;
7441cc052e8SKenneth D. Merry sbp_cmd_status->valid = 1;
7451cc052e8SKenneth D. Merry info_trunc = info;
746e9e688e2SHidetoshi Shimokawa
7471cc052e8SKenneth D. Merry sbp_cmd_status->info = htobe32(info_trunc);
7481cc052e8SKenneth D. Merry } else {
7491cc052e8SKenneth D. Merry sbp_cmd_status->valid = 0;
7501cc052e8SKenneth D. Merry }
751e9e688e2SHidetoshi Shimokawa
7521cc052e8SKenneth D. Merry sbp_cmd_status->s_key = sense_key;
7531cc052e8SKenneth D. Merry
7541cc052e8SKenneth D. Merry if (scsi_get_stream_info(sense, sense_len, NULL,
7551cc052e8SKenneth D. Merry &stream_bits) == 0) {
7561cc052e8SKenneth D. Merry sbp_cmd_status->mark =
7571cc052e8SKenneth D. Merry (stream_bits & SSD_FILEMARK) ? 1 : 0;
7581cc052e8SKenneth D. Merry sbp_cmd_status->eom =
7591cc052e8SKenneth D. Merry (stream_bits & SSD_EOM) ? 1 : 0;
7601cc052e8SKenneth D. Merry sbp_cmd_status->ill_len =
7611cc052e8SKenneth D. Merry (stream_bits & SSD_ILI) ? 1 : 0;
7621cc052e8SKenneth D. Merry } else {
7631cc052e8SKenneth D. Merry sbp_cmd_status->mark = 0;
7641cc052e8SKenneth D. Merry sbp_cmd_status->eom = 0;
7651cc052e8SKenneth D. Merry sbp_cmd_status->ill_len = 0;
7661cc052e8SKenneth D. Merry }
7671cc052e8SKenneth D. Merry
7681cc052e8SKenneth D. Merry
769e9e688e2SHidetoshi Shimokawa /* add_sense_code(_qual), info, cmd_spec_info */
770e9e688e2SHidetoshi Shimokawa sbp_status->len = 4;
7711cc052e8SKenneth D. Merry
7721cc052e8SKenneth D. Merry if (scsi_get_sense_info(sense, sense_len, SSD_DESC_COMMAND,
7731cc052e8SKenneth D. Merry &info, &sinfo) == 0) {
7741cc052e8SKenneth D. Merry uint32_t cmdspec_trunc;
7751cc052e8SKenneth D. Merry
7761cc052e8SKenneth D. Merry cmdspec_trunc = info;
7771cc052e8SKenneth D. Merry
7781cc052e8SKenneth D. Merry sbp_cmd_status->cdb = htobe32(cmdspec_trunc);
7791cc052e8SKenneth D. Merry }
7801cc052e8SKenneth D. Merry
7811cc052e8SKenneth D. Merry sbp_cmd_status->s_code = asc;
7821cc052e8SKenneth D. Merry sbp_cmd_status->s_qlfr = ascq;
7831cc052e8SKenneth D. Merry
7841cc052e8SKenneth D. Merry if (scsi_get_sense_info(sense, sense_len, SSD_DESC_FRU, &info,
7851cc052e8SKenneth D. Merry &sinfo) == 0) {
7861cc052e8SKenneth D. Merry sbp_cmd_status->fru = (uint8_t)info;
787e9e688e2SHidetoshi Shimokawa sbp_status->len = 5;
7881cc052e8SKenneth D. Merry } else {
7891cc052e8SKenneth D. Merry sbp_cmd_status->fru = 0;
7901cc052e8SKenneth D. Merry }
791e9e688e2SHidetoshi Shimokawa
7921cc052e8SKenneth D. Merry if (scsi_get_sks(sense, sense_len, sks) == 0) {
7931cc052e8SKenneth D. Merry bcopy(sks, &sbp_cmd_status->s_keydep[0], sizeof(sks));
7941cc052e8SKenneth D. Merry sbp_status->len = 5;
7954636d244SSean Bruno ccb->ccb_h.status |= CAM_SENT_SENSE;
7961cc052e8SKenneth D. Merry }
797e9e688e2SHidetoshi Shimokawa
798e9e688e2SHidetoshi Shimokawa break;
799e9e688e2SHidetoshi Shimokawa }
800e9e688e2SHidetoshi Shimokawa default:
80110d3ed64SHidetoshi Shimokawa printf("%s: unknown scsi status 0x%x\n", __func__,
802e9e688e2SHidetoshi Shimokawa sbp_status->status);
803e9e688e2SHidetoshi Shimokawa }
804e9e688e2SHidetoshi Shimokawa
8059950b741SHidetoshi Shimokawa
8069950b741SHidetoshi Shimokawa sbp_targ_status_FIFO(orbi,
8079950b741SHidetoshi Shimokawa orbi->login->fifo_hi, orbi->login->fifo_lo, /*dequeue*/1);
808e9e688e2SHidetoshi Shimokawa }
809e9e688e2SHidetoshi Shimokawa
8104636d244SSean Bruno /*
8114636d244SSean Bruno * Invoked as a callback handler from fwmem_read/write_block
8124636d244SSean Bruno *
8134636d244SSean Bruno * Process read/write of initiator address space
8144636d244SSean Bruno * completion and pass status onto the backend target.
8154636d244SSean Bruno * If this is a partial read/write for a CCB then
8164636d244SSean Bruno * we decrement the orbi's refcount to indicate
8174636d244SSean Bruno * the status of the read/write is complete
8184636d244SSean Bruno */
819e9e688e2SHidetoshi Shimokawa static void
sbp_targ_cam_done(struct fw_xfer * xfer)820e9e688e2SHidetoshi Shimokawa sbp_targ_cam_done(struct fw_xfer *xfer)
821e9e688e2SHidetoshi Shimokawa {
822e9e688e2SHidetoshi Shimokawa struct orb_info *orbi;
823e9e688e2SHidetoshi Shimokawa union ccb *ccb;
824e9e688e2SHidetoshi Shimokawa
825e9e688e2SHidetoshi Shimokawa orbi = (struct orb_info *)xfer->sc;
826e9e688e2SHidetoshi Shimokawa
8274636d244SSean Bruno if (debug)
82810d3ed64SHidetoshi Shimokawa printf("%s: resp=%d refcount=%d\n", __func__,
829e9e688e2SHidetoshi Shimokawa xfer->resp, orbi->refcount);
830e9e688e2SHidetoshi Shimokawa
831e9e688e2SHidetoshi Shimokawa if (xfer->resp != 0) {
83210d3ed64SHidetoshi Shimokawa printf("%s: xfer->resp = %d\n", __func__, xfer->resp);
833e9e688e2SHidetoshi Shimokawa orbi->status.resp = SBP_TRANS_FAIL;
8341398a889SHidetoshi Shimokawa orbi->status.status = OBJ_DATA | SBE_TIMEOUT/*XXX*/;
835e9e688e2SHidetoshi Shimokawa orbi->status.dead = 1;
8369950b741SHidetoshi Shimokawa sbp_targ_abort(orbi->sc, STAILQ_NEXT(orbi, link));
837e9e688e2SHidetoshi Shimokawa }
838e9e688e2SHidetoshi Shimokawa
839e9e688e2SHidetoshi Shimokawa orbi->refcount--;
840e9e688e2SHidetoshi Shimokawa
841e9e688e2SHidetoshi Shimokawa ccb = orbi->ccb;
842e9e688e2SHidetoshi Shimokawa if (orbi->refcount == 0) {
8439950b741SHidetoshi Shimokawa orbi->ccb = NULL;
844e9e688e2SHidetoshi Shimokawa if (orbi->state == ORBI_STATUS_ABORTED) {
845e9e688e2SHidetoshi Shimokawa if (debug)
84610d3ed64SHidetoshi Shimokawa printf("%s: orbi aborted\n", __func__);
847a73ff510SHidetoshi Shimokawa sbp_targ_remove_orb_info(orbi->login, orbi);
8484636d244SSean Bruno if (orbi->page_table != NULL) {
8494636d244SSean Bruno if (debug)
8504636d244SSean Bruno printf("%s: free orbi->page_table %p\n",
8514636d244SSean Bruno __func__, orbi->page_table);
852e9e688e2SHidetoshi Shimokawa free(orbi->page_table, M_SBP_TARG);
8534636d244SSean Bruno }
8544636d244SSean Bruno if (debug)
8554636d244SSean Bruno printf("%s: free orbi %p\n", __func__, orbi);
856e9e688e2SHidetoshi Shimokawa free(orbi, M_SBP_TARG);
8574636d244SSean Bruno orbi = NULL;
8584636d244SSean Bruno } else if (orbi->status.resp == ORBI_STATUS_NONE) {
8594636d244SSean Bruno if ((ccb->ccb_h.flags & CAM_SEND_STATUS) != 0) {
8604636d244SSean Bruno if (debug)
8614636d244SSean Bruno printf("%s: CAM_SEND_STATUS set %0x\n", __func__, ccb->ccb_h.flags);
862e9e688e2SHidetoshi Shimokawa sbp_targ_send_status(orbi, ccb);
8634636d244SSean Bruno } else {
8644636d244SSean Bruno if (debug)
8654636d244SSean Bruno printf("%s: CAM_SEND_STATUS not set %0x\n", __func__, ccb->ccb_h.flags);
866e9e688e2SHidetoshi Shimokawa ccb->ccb_h.status = CAM_REQ_CMP;
8674636d244SSean Bruno }
868e9e688e2SHidetoshi Shimokawa xpt_done(ccb);
869e9e688e2SHidetoshi Shimokawa } else {
870e9e688e2SHidetoshi Shimokawa orbi->status.len = 1;
871e9e688e2SHidetoshi Shimokawa sbp_targ_status_FIFO(orbi,
872a73ff510SHidetoshi Shimokawa orbi->login->fifo_hi, orbi->login->fifo_lo,
873e9e688e2SHidetoshi Shimokawa /*dequeue*/1);
874e9e688e2SHidetoshi Shimokawa ccb->ccb_h.status = CAM_REQ_ABORTED;
875e9e688e2SHidetoshi Shimokawa xpt_done(ccb);
876e9e688e2SHidetoshi Shimokawa }
877e9e688e2SHidetoshi Shimokawa }
878e9e688e2SHidetoshi Shimokawa
879e9e688e2SHidetoshi Shimokawa fw_xfer_free(xfer);
880e9e688e2SHidetoshi Shimokawa }
881e9e688e2SHidetoshi Shimokawa
882e9e688e2SHidetoshi Shimokawa static cam_status
sbp_targ_abort_ccb(struct sbp_targ_softc * sc,union ccb * ccb)883e9e688e2SHidetoshi Shimokawa sbp_targ_abort_ccb(struct sbp_targ_softc *sc, union ccb *ccb)
884e9e688e2SHidetoshi Shimokawa {
885e9e688e2SHidetoshi Shimokawa union ccb *accb;
886e9e688e2SHidetoshi Shimokawa struct sbp_targ_lstate *lstate;
887e9e688e2SHidetoshi Shimokawa struct ccb_hdr_slist *list;
888e9e688e2SHidetoshi Shimokawa struct ccb_hdr *curelm;
889e9e688e2SHidetoshi Shimokawa int found;
890e9e688e2SHidetoshi Shimokawa cam_status status;
891e9e688e2SHidetoshi Shimokawa
892e9e688e2SHidetoshi Shimokawa status = sbp_targ_find_devs(sc, ccb, &lstate, 0);
893e9e688e2SHidetoshi Shimokawa if (status != CAM_REQ_CMP)
894e9e688e2SHidetoshi Shimokawa return (status);
895e9e688e2SHidetoshi Shimokawa
896e9e688e2SHidetoshi Shimokawa accb = ccb->cab.abort_ccb;
897e9e688e2SHidetoshi Shimokawa
898e9e688e2SHidetoshi Shimokawa if (accb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO)
899e9e688e2SHidetoshi Shimokawa list = &lstate->accept_tios;
900b79dc8a8SKenneth D. Merry else if (accb->ccb_h.func_code == XPT_IMMEDIATE_NOTIFY)
901e9e688e2SHidetoshi Shimokawa list = &lstate->immed_notifies;
902e9e688e2SHidetoshi Shimokawa else
903e9e688e2SHidetoshi Shimokawa return (CAM_UA_ABORT);
904e9e688e2SHidetoshi Shimokawa
905e9e688e2SHidetoshi Shimokawa curelm = SLIST_FIRST(list);
906e9e688e2SHidetoshi Shimokawa found = 0;
907e9e688e2SHidetoshi Shimokawa if (curelm == &accb->ccb_h) {
908e9e688e2SHidetoshi Shimokawa found = 1;
909e9e688e2SHidetoshi Shimokawa SLIST_REMOVE_HEAD(list, sim_links.sle);
910e9e688e2SHidetoshi Shimokawa } else {
911e9e688e2SHidetoshi Shimokawa while (curelm != NULL) {
912e9e688e2SHidetoshi Shimokawa struct ccb_hdr *nextelm;
913e9e688e2SHidetoshi Shimokawa
914e9e688e2SHidetoshi Shimokawa nextelm = SLIST_NEXT(curelm, sim_links.sle);
915e9e688e2SHidetoshi Shimokawa if (nextelm == &accb->ccb_h) {
916e9e688e2SHidetoshi Shimokawa found = 1;
917e9e688e2SHidetoshi Shimokawa SLIST_NEXT(curelm, sim_links.sle) =
918e9e688e2SHidetoshi Shimokawa SLIST_NEXT(nextelm, sim_links.sle);
919e9e688e2SHidetoshi Shimokawa break;
920e9e688e2SHidetoshi Shimokawa }
921e9e688e2SHidetoshi Shimokawa curelm = nextelm;
922e9e688e2SHidetoshi Shimokawa }
923e9e688e2SHidetoshi Shimokawa }
924e9e688e2SHidetoshi Shimokawa if (found) {
925e9e688e2SHidetoshi Shimokawa accb->ccb_h.status = CAM_REQ_ABORTED;
926e9e688e2SHidetoshi Shimokawa xpt_done(accb);
927e9e688e2SHidetoshi Shimokawa return (CAM_REQ_CMP);
928e9e688e2SHidetoshi Shimokawa }
92910d3ed64SHidetoshi Shimokawa printf("%s: not found\n", __func__);
930e9e688e2SHidetoshi Shimokawa return (CAM_PATH_INVALID);
931e9e688e2SHidetoshi Shimokawa }
932e9e688e2SHidetoshi Shimokawa
9334636d244SSean Bruno /*
9344636d244SSean Bruno * directly execute a read or write to the initiator
9354636d244SSean Bruno * address space and set hand(sbp_targ_cam_done) to
9364636d244SSean Bruno * process the completion from the SIM to the target.
9374636d244SSean Bruno * set orbi->refcount to inidicate that a read/write
9384636d244SSean Bruno * is inflight to/from the initiator.
9394636d244SSean Bruno */
940e9e688e2SHidetoshi Shimokawa static void
sbp_targ_xfer_buf(struct orb_info * orbi,u_int offset,uint16_t dst_hi,uint32_t dst_lo,u_int size,void (* hand)(struct fw_xfer *))941e9e688e2SHidetoshi Shimokawa sbp_targ_xfer_buf(struct orb_info *orbi, u_int offset,
94203161bbcSDoug Rabson uint16_t dst_hi, uint32_t dst_lo, u_int size,
943e9e688e2SHidetoshi Shimokawa void (*hand)(struct fw_xfer *))
944e9e688e2SHidetoshi Shimokawa {
945e9e688e2SHidetoshi Shimokawa struct fw_xfer *xfer;
946e9e688e2SHidetoshi Shimokawa u_int len, ccb_dir, off = 0;
947e9e688e2SHidetoshi Shimokawa char *ptr;
948e9e688e2SHidetoshi Shimokawa
949a73ff510SHidetoshi Shimokawa if (debug > 1)
95010d3ed64SHidetoshi Shimokawa printf("%s: offset=%d size=%d\n", __func__, offset, size);
951e9e688e2SHidetoshi Shimokawa ccb_dir = orbi->ccb->ccb_h.flags & CAM_DIR_MASK;
952e9e688e2SHidetoshi Shimokawa ptr = (char *)orbi->ccb->csio.data_ptr + offset;
953e9e688e2SHidetoshi Shimokawa
954e9e688e2SHidetoshi Shimokawa while (size > 0) {
955e9e688e2SHidetoshi Shimokawa /* XXX assume dst_lo + off doesn't overflow */
956e9e688e2SHidetoshi Shimokawa len = MIN(size, 2048 /* XXX */);
957e9e688e2SHidetoshi Shimokawa size -= len;
958e9e688e2SHidetoshi Shimokawa orbi->refcount ++;
9594636d244SSean Bruno if (ccb_dir == CAM_DIR_OUT) {
9604636d244SSean Bruno if (debug)
9614636d244SSean Bruno printf("%s: CAM_DIR_OUT --> read block in?\n",__func__);
962e9e688e2SHidetoshi Shimokawa xfer = fwmem_read_block(orbi->fwdev,
9634636d244SSean Bruno (void *)orbi, /*spd*/FWSPD_S400,
964e9e688e2SHidetoshi Shimokawa dst_hi, dst_lo + off, len,
965e9e688e2SHidetoshi Shimokawa ptr + off, hand);
9664636d244SSean Bruno } else {
9674636d244SSean Bruno if (debug)
9684636d244SSean Bruno printf("%s: CAM_DIR_IN --> write block out?\n",__func__);
969e9e688e2SHidetoshi Shimokawa xfer = fwmem_write_block(orbi->fwdev,
9704636d244SSean Bruno (void *)orbi, /*spd*/FWSPD_S400,
971e9e688e2SHidetoshi Shimokawa dst_hi, dst_lo + off, len,
972e9e688e2SHidetoshi Shimokawa ptr + off, hand);
9734636d244SSean Bruno }
974e9e688e2SHidetoshi Shimokawa if (xfer == NULL) {
97510d3ed64SHidetoshi Shimokawa printf("%s: xfer == NULL", __func__);
976e9e688e2SHidetoshi Shimokawa /* XXX what should we do?? */
977e9e688e2SHidetoshi Shimokawa orbi->refcount--;
978e9e688e2SHidetoshi Shimokawa }
979e9e688e2SHidetoshi Shimokawa off += len;
980e9e688e2SHidetoshi Shimokawa }
981e9e688e2SHidetoshi Shimokawa }
982e9e688e2SHidetoshi Shimokawa
983e9e688e2SHidetoshi Shimokawa static void
sbp_targ_pt_done(struct fw_xfer * xfer)984e9e688e2SHidetoshi Shimokawa sbp_targ_pt_done(struct fw_xfer *xfer)
985e9e688e2SHidetoshi Shimokawa {
986e9e688e2SHidetoshi Shimokawa struct orb_info *orbi;
9874636d244SSean Bruno struct unrestricted_page_table_fmt *pt;
9884636d244SSean Bruno uint32_t i;
989e9e688e2SHidetoshi Shimokawa
990e9e688e2SHidetoshi Shimokawa orbi = (struct orb_info *)xfer->sc;
9914636d244SSean Bruno
992e9e688e2SHidetoshi Shimokawa if (orbi->state == ORBI_STATUS_ABORTED) {
993e9e688e2SHidetoshi Shimokawa if (debug)
99410d3ed64SHidetoshi Shimokawa printf("%s: orbi aborted\n", __func__);
995a73ff510SHidetoshi Shimokawa sbp_targ_remove_orb_info(orbi->login, orbi);
9964636d244SSean Bruno if (debug) {
9974636d244SSean Bruno printf("%s: free orbi->page_table %p\n", __func__, orbi->page_table);
9984636d244SSean Bruno printf("%s: free orbi %p\n", __func__, orbi);
9994636d244SSean Bruno }
1000e9e688e2SHidetoshi Shimokawa free(orbi->page_table, M_SBP_TARG);
1001e9e688e2SHidetoshi Shimokawa free(orbi, M_SBP_TARG);
10024636d244SSean Bruno orbi = NULL;
1003e9e688e2SHidetoshi Shimokawa fw_xfer_free(xfer);
1004e9e688e2SHidetoshi Shimokawa return;
1005e9e688e2SHidetoshi Shimokawa }
1006e9e688e2SHidetoshi Shimokawa if (xfer->resp != 0) {
100710d3ed64SHidetoshi Shimokawa printf("%s: xfer->resp = %d\n", __func__, xfer->resp);
1008e9e688e2SHidetoshi Shimokawa orbi->status.resp = SBP_TRANS_FAIL;
10091398a889SHidetoshi Shimokawa orbi->status.status = OBJ_PT | SBE_TIMEOUT/*XXX*/;
1010e9e688e2SHidetoshi Shimokawa orbi->status.dead = 1;
1011e9e688e2SHidetoshi Shimokawa orbi->status.len = 1;
10129950b741SHidetoshi Shimokawa sbp_targ_abort(orbi->sc, STAILQ_NEXT(orbi, link));
1013e9e688e2SHidetoshi Shimokawa
10144636d244SSean Bruno if (debug)
10154636d244SSean Bruno printf("%s: free orbi->page_table %p\n", __func__, orbi->page_table);
10164636d244SSean Bruno
1017e9e688e2SHidetoshi Shimokawa sbp_targ_status_FIFO(orbi,
1018a73ff510SHidetoshi Shimokawa orbi->login->fifo_hi, orbi->login->fifo_lo, /*dequeue*/1);
1019e9e688e2SHidetoshi Shimokawa free(orbi->page_table, M_SBP_TARG);
10204636d244SSean Bruno orbi->page_table = NULL;
1021e9e688e2SHidetoshi Shimokawa fw_xfer_free(xfer);
1022e9e688e2SHidetoshi Shimokawa return;
1023e9e688e2SHidetoshi Shimokawa }
1024e9e688e2SHidetoshi Shimokawa orbi->refcount++;
10254636d244SSean Bruno /*
1026453130d9SPedro F. Giffuni * Set endianness here so we don't have
10274636d244SSean Bruno * to deal with is later
10284636d244SSean Bruno */
10294636d244SSean Bruno for (i = 0, pt = orbi->page_table; i < orbi->orb4.data_size; i++, pt++) {
10304636d244SSean Bruno pt->segment_len = ntohs(pt->segment_len);
10314636d244SSean Bruno if (debug)
10324636d244SSean Bruno printf("%s:segment_len = %u\n", __func__,pt->segment_len);
10334636d244SSean Bruno pt->segment_base_high = ntohs(pt->segment_base_high);
10344636d244SSean Bruno pt->segment_base_low = ntohl(pt->segment_base_low);
1035e9e688e2SHidetoshi Shimokawa }
10364636d244SSean Bruno
10374636d244SSean Bruno sbp_targ_xfer_pt(orbi);
10384636d244SSean Bruno
1039e9e688e2SHidetoshi Shimokawa orbi->refcount--;
1040e9e688e2SHidetoshi Shimokawa if (orbi->refcount == 0)
104110d3ed64SHidetoshi Shimokawa printf("%s: refcount == 0\n", __func__);
1042e9e688e2SHidetoshi Shimokawa
1043e9e688e2SHidetoshi Shimokawa fw_xfer_free(xfer);
1044e9e688e2SHidetoshi Shimokawa return;
1045e9e688e2SHidetoshi Shimokawa }
1046e9e688e2SHidetoshi Shimokawa
sbp_targ_xfer_pt(struct orb_info * orbi)10474636d244SSean Bruno static void sbp_targ_xfer_pt(struct orb_info *orbi)
10484636d244SSean Bruno {
10494636d244SSean Bruno union ccb *ccb;
10504636d244SSean Bruno uint32_t res, offset, len;
10514636d244SSean Bruno
10524636d244SSean Bruno ccb = orbi->ccb;
10534636d244SSean Bruno if (debug)
10544636d244SSean Bruno printf("%s: dxfer_len=%d\n", __func__, ccb->csio.dxfer_len);
10554636d244SSean Bruno res = ccb->csio.dxfer_len;
10564636d244SSean Bruno /*
10574636d244SSean Bruno * If the page table required multiple CTIO's to
10584636d244SSean Bruno * complete, then cur_pte is non NULL
10594636d244SSean Bruno * and we need to start from the last position
10604636d244SSean Bruno * If this is the first pass over a page table
10614636d244SSean Bruno * then we just start at the beginning of the page
10624636d244SSean Bruno * table.
10634636d244SSean Bruno *
10644636d244SSean Bruno * Parse the unrestricted page table and figure out where we need
10654636d244SSean Bruno * to shove the data from this read request.
10664636d244SSean Bruno */
10674636d244SSean Bruno for (offset = 0, len = 0; (res != 0) && (orbi->cur_pte < orbi->last_pte); offset += len) {
10684636d244SSean Bruno len = MIN(orbi->cur_pte->segment_len, res);
10694636d244SSean Bruno res -= len;
10704636d244SSean Bruno if (debug)
10714636d244SSean Bruno printf("%s:page_table: %04x:%08x segment_len(%u) res(%u) len(%u)\n",
10724636d244SSean Bruno __func__, orbi->cur_pte->segment_base_high,
10734636d244SSean Bruno orbi->cur_pte->segment_base_low,
10744636d244SSean Bruno orbi->cur_pte->segment_len,
10754636d244SSean Bruno res, len);
10764636d244SSean Bruno sbp_targ_xfer_buf(orbi, offset,
10774636d244SSean Bruno orbi->cur_pte->segment_base_high,
10784636d244SSean Bruno orbi->cur_pte->segment_base_low,
10794636d244SSean Bruno len, sbp_targ_cam_done);
10804636d244SSean Bruno /*
10814636d244SSean Bruno * If we have only written partially to
10824636d244SSean Bruno * this page table, then we need to save
10834636d244SSean Bruno * our position for the next CTIO. If we
10844636d244SSean Bruno * have completed the page table, then we
10854636d244SSean Bruno * are safe to move on to the next entry.
10864636d244SSean Bruno */
10874636d244SSean Bruno if (len == orbi->cur_pte->segment_len) {
10884636d244SSean Bruno orbi->cur_pte++;
10894636d244SSean Bruno } else {
10904636d244SSean Bruno uint32_t saved_base_low;
10914636d244SSean Bruno
10924636d244SSean Bruno /* Handle transfers that cross a 4GB boundary. */
10934636d244SSean Bruno saved_base_low = orbi->cur_pte->segment_base_low;
10944636d244SSean Bruno orbi->cur_pte->segment_base_low += len;
10954636d244SSean Bruno if (orbi->cur_pte->segment_base_low < saved_base_low)
10964636d244SSean Bruno orbi->cur_pte->segment_base_high++;
10974636d244SSean Bruno
10984636d244SSean Bruno orbi->cur_pte->segment_len -= len;
10994636d244SSean Bruno }
11004636d244SSean Bruno }
11014636d244SSean Bruno if (debug) {
11024636d244SSean Bruno printf("%s: base_low(%08x) page_table_off(%p) last_block(%u)\n",
11034636d244SSean Bruno __func__, orbi->cur_pte->segment_base_low,
11044636d244SSean Bruno orbi->cur_pte, orbi->last_block_read);
11054636d244SSean Bruno }
11064636d244SSean Bruno if (res != 0)
11074636d244SSean Bruno printf("Warning - short pt encountered. "
11084636d244SSean Bruno "Could not transfer all data.\n");
11094636d244SSean Bruno return;
11104636d244SSean Bruno }
11114636d244SSean Bruno
11124636d244SSean Bruno /*
11134636d244SSean Bruno * Create page table in local memory
11144636d244SSean Bruno * and transfer it from the initiator
11154636d244SSean Bruno * in order to know where we are supposed
11164636d244SSean Bruno * to put the data.
11174636d244SSean Bruno */
11184636d244SSean Bruno
1119e9e688e2SHidetoshi Shimokawa static void
sbp_targ_fetch_pt(struct orb_info * orbi)1120e9e688e2SHidetoshi Shimokawa sbp_targ_fetch_pt(struct orb_info *orbi)
1121e9e688e2SHidetoshi Shimokawa {
1122e9e688e2SHidetoshi Shimokawa struct fw_xfer *xfer;
1123e9e688e2SHidetoshi Shimokawa
11244636d244SSean Bruno /*
11254636d244SSean Bruno * Pull in page table from initiator
11264636d244SSean Bruno * and setup for data from our
11274636d244SSean Bruno * backend device.
11284636d244SSean Bruno */
11294636d244SSean Bruno if (orbi->page_table == NULL) {
11304636d244SSean Bruno orbi->page_table = malloc(orbi->orb4.data_size*
11314636d244SSean Bruno sizeof(struct unrestricted_page_table_fmt),
11324636d244SSean Bruno M_SBP_TARG, M_NOWAIT|M_ZERO);
1133e9e688e2SHidetoshi Shimokawa if (orbi->page_table == NULL)
1134e9e688e2SHidetoshi Shimokawa goto error;
11354636d244SSean Bruno orbi->cur_pte = orbi->page_table;
11364636d244SSean Bruno orbi->last_pte = orbi->page_table + orbi->orb4.data_size;
11374636d244SSean Bruno orbi->last_block_read = orbi->orb4.data_size;
11384636d244SSean Bruno if (debug && orbi->page_table != NULL)
11394636d244SSean Bruno printf("%s: malloc'd orbi->page_table(%p), orb4.data_size(%u)\n",
11404636d244SSean Bruno __func__, orbi->page_table, orbi->orb4.data_size);
11414636d244SSean Bruno
11424636d244SSean Bruno xfer = fwmem_read_block(orbi->fwdev, (void *)orbi, /*spd*/FWSPD_S400,
11434636d244SSean Bruno orbi->data_hi, orbi->data_lo, orbi->orb4.data_size*
11444636d244SSean Bruno sizeof(struct unrestricted_page_table_fmt),
1145e9e688e2SHidetoshi Shimokawa (void *)orbi->page_table, sbp_targ_pt_done);
11464636d244SSean Bruno
1147e9e688e2SHidetoshi Shimokawa if (xfer != NULL)
1148e9e688e2SHidetoshi Shimokawa return;
11494636d244SSean Bruno } else {
11504636d244SSean Bruno /*
11514636d244SSean Bruno * This is a CTIO for a page table we have
11524636d244SSean Bruno * already malloc'd, so just directly invoke
11534636d244SSean Bruno * the xfer function on the orbi.
11544636d244SSean Bruno */
11554636d244SSean Bruno sbp_targ_xfer_pt(orbi);
11564636d244SSean Bruno return;
11574636d244SSean Bruno }
1158e9e688e2SHidetoshi Shimokawa error:
1159e9e688e2SHidetoshi Shimokawa orbi->ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
11604636d244SSean Bruno if (debug)
11614636d244SSean Bruno printf("%s: free orbi->page_table %p due to xfer == NULL\n", __func__, orbi->page_table);
11624636d244SSean Bruno if (orbi->page_table != NULL) {
11634636d244SSean Bruno free(orbi->page_table, M_SBP_TARG);
11644636d244SSean Bruno orbi->page_table = NULL;
11654636d244SSean Bruno }
1166e9e688e2SHidetoshi Shimokawa xpt_done(orbi->ccb);
1167e9e688e2SHidetoshi Shimokawa return;
1168e9e688e2SHidetoshi Shimokawa }
1169e9e688e2SHidetoshi Shimokawa
1170e9e688e2SHidetoshi Shimokawa static void
sbp_targ_action1(struct cam_sim * sim,union ccb * ccb)1171e9e688e2SHidetoshi Shimokawa sbp_targ_action1(struct cam_sim *sim, union ccb *ccb)
1172e9e688e2SHidetoshi Shimokawa {
1173e9e688e2SHidetoshi Shimokawa struct sbp_targ_softc *sc;
1174e9e688e2SHidetoshi Shimokawa struct sbp_targ_lstate *lstate;
1175e9e688e2SHidetoshi Shimokawa cam_status status;
1176e9e688e2SHidetoshi Shimokawa u_int ccb_dir;
1177e9e688e2SHidetoshi Shimokawa
1178e9e688e2SHidetoshi Shimokawa sc = (struct sbp_targ_softc *)cam_sim_softc(sim);
1179e9e688e2SHidetoshi Shimokawa
1180e9e688e2SHidetoshi Shimokawa status = sbp_targ_find_devs(sc, ccb, &lstate, TRUE);
1181e9e688e2SHidetoshi Shimokawa
1182e9e688e2SHidetoshi Shimokawa switch (ccb->ccb_h.func_code) {
1183e9e688e2SHidetoshi Shimokawa case XPT_CONT_TARGET_IO:
1184e9e688e2SHidetoshi Shimokawa {
1185e9e688e2SHidetoshi Shimokawa struct orb_info *orbi;
1186e9e688e2SHidetoshi Shimokawa
1187e9e688e2SHidetoshi Shimokawa if (debug)
11889950b741SHidetoshi Shimokawa printf("%s: XPT_CONT_TARGET_IO (0x%08x)\n",
11899950b741SHidetoshi Shimokawa __func__, ccb->csio.tag_id);
1190e9e688e2SHidetoshi Shimokawa
1191e9e688e2SHidetoshi Shimokawa if (status != CAM_REQ_CMP) {
1192e9e688e2SHidetoshi Shimokawa ccb->ccb_h.status = status;
1193e9e688e2SHidetoshi Shimokawa xpt_done(ccb);
1194e9e688e2SHidetoshi Shimokawa break;
1195e9e688e2SHidetoshi Shimokawa }
1196e9e688e2SHidetoshi Shimokawa /* XXX transfer from/to initiator */
1197e9e688e2SHidetoshi Shimokawa orbi = sbp_targ_get_orb_info(lstate,
1198e9e688e2SHidetoshi Shimokawa ccb->csio.tag_id, ccb->csio.init_id);
1199e9e688e2SHidetoshi Shimokawa if (orbi == NULL) {
1200e9e688e2SHidetoshi Shimokawa ccb->ccb_h.status = CAM_REQ_ABORTED; /* XXX */
1201e9e688e2SHidetoshi Shimokawa xpt_done(ccb);
1202e9e688e2SHidetoshi Shimokawa break;
1203e9e688e2SHidetoshi Shimokawa }
1204e9e688e2SHidetoshi Shimokawa if (orbi->state == ORBI_STATUS_ABORTED) {
1205e9e688e2SHidetoshi Shimokawa if (debug)
120610d3ed64SHidetoshi Shimokawa printf("%s: ctio aborted\n", __func__);
12079950b741SHidetoshi Shimokawa sbp_targ_remove_orb_info_locked(orbi->login, orbi);
12084636d244SSean Bruno if (debug)
12094636d244SSean Bruno printf("%s: free orbi %p\n", __func__, orbi);
1210e9e688e2SHidetoshi Shimokawa free(orbi, M_SBP_TARG);
12119950b741SHidetoshi Shimokawa ccb->ccb_h.status = CAM_REQ_ABORTED;
12129950b741SHidetoshi Shimokawa xpt_done(ccb);
1213e9e688e2SHidetoshi Shimokawa break;
1214e9e688e2SHidetoshi Shimokawa }
1215e9e688e2SHidetoshi Shimokawa orbi->state = ORBI_STATUS_CTIO;
1216e9e688e2SHidetoshi Shimokawa
1217e9e688e2SHidetoshi Shimokawa orbi->ccb = ccb;
1218e9e688e2SHidetoshi Shimokawa ccb_dir = ccb->ccb_h.flags & CAM_DIR_MASK;
1219e9e688e2SHidetoshi Shimokawa
1220e9e688e2SHidetoshi Shimokawa /* XXX */
1221e9e688e2SHidetoshi Shimokawa if (ccb->csio.dxfer_len == 0)
1222e9e688e2SHidetoshi Shimokawa ccb_dir = CAM_DIR_NONE;
1223e9e688e2SHidetoshi Shimokawa
1224e9e688e2SHidetoshi Shimokawa /* Sanity check */
1225e9e688e2SHidetoshi Shimokawa if (ccb_dir == CAM_DIR_IN && orbi->orb4.dir == 0)
122610d3ed64SHidetoshi Shimokawa printf("%s: direction mismatch\n", __func__);
1227e9e688e2SHidetoshi Shimokawa
1228e9e688e2SHidetoshi Shimokawa /* check page table */
1229e9e688e2SHidetoshi Shimokawa if (ccb_dir != CAM_DIR_NONE && orbi->orb4.page_table_present) {
1230e9e688e2SHidetoshi Shimokawa if (debug)
1231e9e688e2SHidetoshi Shimokawa printf("%s: page_table_present\n",
123210d3ed64SHidetoshi Shimokawa __func__);
1233e9e688e2SHidetoshi Shimokawa if (orbi->orb4.page_size != 0) {
1234e9e688e2SHidetoshi Shimokawa printf("%s: unsupported pagesize %d != 0\n",
123510d3ed64SHidetoshi Shimokawa __func__, orbi->orb4.page_size);
1236e9e688e2SHidetoshi Shimokawa ccb->ccb_h.status = CAM_REQ_INVALID;
1237e9e688e2SHidetoshi Shimokawa xpt_done(ccb);
1238e9e688e2SHidetoshi Shimokawa break;
1239e9e688e2SHidetoshi Shimokawa }
1240e9e688e2SHidetoshi Shimokawa sbp_targ_fetch_pt(orbi);
1241e9e688e2SHidetoshi Shimokawa break;
1242e9e688e2SHidetoshi Shimokawa }
1243e9e688e2SHidetoshi Shimokawa
1244e9e688e2SHidetoshi Shimokawa /* Sanity check */
12454636d244SSean Bruno if (ccb_dir != CAM_DIR_NONE) {
1246e9e688e2SHidetoshi Shimokawa sbp_targ_xfer_buf(orbi, 0, orbi->data_hi,
1247e9e688e2SHidetoshi Shimokawa orbi->data_lo,
1248e9e688e2SHidetoshi Shimokawa MIN(orbi->orb4.data_size, ccb->csio.dxfer_len),
1249e9e688e2SHidetoshi Shimokawa sbp_targ_cam_done);
12504636d244SSean Bruno if ( orbi->orb4.data_size > ccb->csio.dxfer_len ) {
12514636d244SSean Bruno orbi->data_lo += ccb->csio.dxfer_len;
12524636d244SSean Bruno orbi->orb4.data_size -= ccb->csio.dxfer_len;
12534636d244SSean Bruno }
12544636d244SSean Bruno }
1255e9e688e2SHidetoshi Shimokawa
1256e9e688e2SHidetoshi Shimokawa if (ccb_dir == CAM_DIR_NONE) {
12579950b741SHidetoshi Shimokawa if ((ccb->ccb_h.flags & CAM_SEND_STATUS) != 0) {
12589950b741SHidetoshi Shimokawa /* XXX */
12599950b741SHidetoshi Shimokawa SBP_UNLOCK(sc);
1260e9e688e2SHidetoshi Shimokawa sbp_targ_send_status(orbi, ccb);
12619950b741SHidetoshi Shimokawa SBP_LOCK(sc);
12629950b741SHidetoshi Shimokawa }
1263e9e688e2SHidetoshi Shimokawa ccb->ccb_h.status = CAM_REQ_CMP;
1264e9e688e2SHidetoshi Shimokawa xpt_done(ccb);
1265e9e688e2SHidetoshi Shimokawa }
1266e9e688e2SHidetoshi Shimokawa break;
1267e9e688e2SHidetoshi Shimokawa }
1268e9e688e2SHidetoshi Shimokawa case XPT_ACCEPT_TARGET_IO: /* Add Accept Target IO Resource */
1269e9e688e2SHidetoshi Shimokawa if (status != CAM_REQ_CMP) {
1270e9e688e2SHidetoshi Shimokawa ccb->ccb_h.status = status;
1271e9e688e2SHidetoshi Shimokawa xpt_done(ccb);
1272e9e688e2SHidetoshi Shimokawa break;
1273e9e688e2SHidetoshi Shimokawa }
1274e9e688e2SHidetoshi Shimokawa SLIST_INSERT_HEAD(&lstate->accept_tios, &ccb->ccb_h,
1275e9e688e2SHidetoshi Shimokawa sim_links.sle);
1276e9e688e2SHidetoshi Shimokawa ccb->ccb_h.status = CAM_REQ_INPROG;
1277a73ff510SHidetoshi Shimokawa if ((lstate->flags & F_ATIO_STARVED) != 0) {
1278a73ff510SHidetoshi Shimokawa struct sbp_targ_login *login;
1279a73ff510SHidetoshi Shimokawa
1280e9e688e2SHidetoshi Shimokawa if (debug)
128110d3ed64SHidetoshi Shimokawa printf("%s: new atio arrived\n", __func__);
1282a73ff510SHidetoshi Shimokawa lstate->flags &= ~F_ATIO_STARVED;
1283a73ff510SHidetoshi Shimokawa STAILQ_FOREACH(login, &lstate->logins, link)
1284a73ff510SHidetoshi Shimokawa if ((login->flags & F_ATIO_STARVED) != 0) {
1285a73ff510SHidetoshi Shimokawa login->flags &= ~F_ATIO_STARVED;
1286a73ff510SHidetoshi Shimokawa sbp_targ_fetch_orb(lstate->sc,
1287a73ff510SHidetoshi Shimokawa login->fwdev,
1288a73ff510SHidetoshi Shimokawa login->last_hi, login->last_lo,
1289a73ff510SHidetoshi Shimokawa login, FETCH_CMD);
1290a73ff510SHidetoshi Shimokawa }
1291e9e688e2SHidetoshi Shimokawa }
1292e9e688e2SHidetoshi Shimokawa break;
1293b79dc8a8SKenneth D. Merry case XPT_NOTIFY_ACKNOWLEDGE: /* recycle notify ack */
1294b79dc8a8SKenneth D. Merry case XPT_IMMEDIATE_NOTIFY: /* Add Immediate Notify Resource */
1295e9e688e2SHidetoshi Shimokawa if (status != CAM_REQ_CMP) {
1296e9e688e2SHidetoshi Shimokawa ccb->ccb_h.status = status;
1297e9e688e2SHidetoshi Shimokawa xpt_done(ccb);
1298e9e688e2SHidetoshi Shimokawa break;
1299e9e688e2SHidetoshi Shimokawa }
1300e9e688e2SHidetoshi Shimokawa SLIST_INSERT_HEAD(&lstate->immed_notifies, &ccb->ccb_h,
1301e9e688e2SHidetoshi Shimokawa sim_links.sle);
1302e9e688e2SHidetoshi Shimokawa ccb->ccb_h.status = CAM_REQ_INPROG;
1303e9e688e2SHidetoshi Shimokawa sbp_targ_send_lstate_events(sc, lstate);
1304e9e688e2SHidetoshi Shimokawa break;
1305e9e688e2SHidetoshi Shimokawa case XPT_EN_LUN:
1306e9e688e2SHidetoshi Shimokawa sbp_targ_en_lun(sc, ccb);
1307e9e688e2SHidetoshi Shimokawa xpt_done(ccb);
1308e9e688e2SHidetoshi Shimokawa break;
1309e9e688e2SHidetoshi Shimokawa case XPT_PATH_INQ:
1310e9e688e2SHidetoshi Shimokawa {
1311e9e688e2SHidetoshi Shimokawa struct ccb_pathinq *cpi = &ccb->cpi;
1312e9e688e2SHidetoshi Shimokawa
1313e9e688e2SHidetoshi Shimokawa cpi->version_num = 1; /* XXX??? */
1314e9e688e2SHidetoshi Shimokawa cpi->hba_inquiry = PI_TAG_ABLE;
1315e9e688e2SHidetoshi Shimokawa cpi->target_sprt = PIT_PROCESSOR
1316e9e688e2SHidetoshi Shimokawa | PIT_DISCONNECT
1317e9e688e2SHidetoshi Shimokawa | PIT_TERM_IO;
13184636d244SSean Bruno cpi->transport = XPORT_SPI; /* FIXME add XPORT_FW type to cam */
131964e574c2SAlexander Motin cpi->hba_misc = PIM_NOINITIATOR | PIM_NOBUSRESET |
132064e574c2SAlexander Motin PIM_NO_6_BYTE;
1321e9e688e2SHidetoshi Shimokawa cpi->hba_eng_cnt = 0;
1322e9e688e2SHidetoshi Shimokawa cpi->max_target = 7; /* XXX */
1323e9e688e2SHidetoshi Shimokawa cpi->max_lun = MAX_LUN - 1;
1324e9e688e2SHidetoshi Shimokawa cpi->initiator_id = 7; /* XXX */
1325e9e688e2SHidetoshi Shimokawa cpi->bus_id = sim->bus_id;
1326e9e688e2SHidetoshi Shimokawa cpi->base_transfer_speed = 400 * 1000 / 8;
13274195c7deSAlan Somers strlcpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
13284195c7deSAlan Somers strlcpy(cpi->hba_vid, "SBP_TARG", HBA_IDLEN);
13294195c7deSAlan Somers strlcpy(cpi->dev_name, sim->sim_name, DEV_IDLEN);
1330e9e688e2SHidetoshi Shimokawa cpi->unit_number = sim->unit_number;
1331e9e688e2SHidetoshi Shimokawa
1332e9e688e2SHidetoshi Shimokawa cpi->ccb_h.status = CAM_REQ_CMP;
1333e9e688e2SHidetoshi Shimokawa xpt_done(ccb);
1334e9e688e2SHidetoshi Shimokawa break;
1335e9e688e2SHidetoshi Shimokawa }
1336e9e688e2SHidetoshi Shimokawa case XPT_ABORT:
1337e9e688e2SHidetoshi Shimokawa {
1338e9e688e2SHidetoshi Shimokawa union ccb *accb = ccb->cab.abort_ccb;
1339e9e688e2SHidetoshi Shimokawa
1340e9e688e2SHidetoshi Shimokawa switch (accb->ccb_h.func_code) {
1341e9e688e2SHidetoshi Shimokawa case XPT_ACCEPT_TARGET_IO:
1342b79dc8a8SKenneth D. Merry case XPT_IMMEDIATE_NOTIFY:
1343e9e688e2SHidetoshi Shimokawa ccb->ccb_h.status = sbp_targ_abort_ccb(sc, ccb);
1344e9e688e2SHidetoshi Shimokawa break;
1345e9e688e2SHidetoshi Shimokawa case XPT_CONT_TARGET_IO:
1346e9e688e2SHidetoshi Shimokawa /* XXX */
1347e9e688e2SHidetoshi Shimokawa ccb->ccb_h.status = CAM_UA_ABORT;
1348e9e688e2SHidetoshi Shimokawa break;
1349e9e688e2SHidetoshi Shimokawa default:
1350e9e688e2SHidetoshi Shimokawa printf("%s: aborting unknown function %d\n",
135110d3ed64SHidetoshi Shimokawa __func__, accb->ccb_h.func_code);
1352e9e688e2SHidetoshi Shimokawa ccb->ccb_h.status = CAM_REQ_INVALID;
1353e9e688e2SHidetoshi Shimokawa break;
1354e9e688e2SHidetoshi Shimokawa }
1355e9e688e2SHidetoshi Shimokawa xpt_done(ccb);
1356e9e688e2SHidetoshi Shimokawa break;
1357e9e688e2SHidetoshi Shimokawa }
13584636d244SSean Bruno #ifdef CAM_NEW_TRAN_CODE
13594636d244SSean Bruno case XPT_SET_TRAN_SETTINGS:
1360e9e688e2SHidetoshi Shimokawa ccb->ccb_h.status = CAM_REQ_INVALID;
1361e9e688e2SHidetoshi Shimokawa xpt_done(ccb);
1362e9e688e2SHidetoshi Shimokawa break;
13634636d244SSean Bruno case XPT_GET_TRAN_SETTINGS:
13644636d244SSean Bruno {
13654636d244SSean Bruno struct ccb_trans_settings *cts = &ccb->cts;
13664636d244SSean Bruno struct ccb_trans_settings_scsi *scsi =
13674636d244SSean Bruno &cts->proto_specific.scsi;
13684636d244SSean Bruno struct ccb_trans_settings_spi *spi =
13694636d244SSean Bruno &cts->xport_specific.spi;
13704636d244SSean Bruno
13714636d244SSean Bruno cts->protocol = PROTO_SCSI;
13724636d244SSean Bruno cts->protocol_version = SCSI_REV_2;
13734636d244SSean Bruno cts->transport = XPORT_FW; /* should have a FireWire */
13744636d244SSean Bruno cts->transport_version = 2;
13754636d244SSean Bruno spi->valid = CTS_SPI_VALID_DISC;
13764636d244SSean Bruno spi->flags = CTS_SPI_FLAGS_DISC_ENB;
13774636d244SSean Bruno scsi->valid = CTS_SCSI_VALID_TQ;
13784636d244SSean Bruno scsi->flags = CTS_SCSI_FLAGS_TAG_ENB;
13794636d244SSean Bruno #if 0
13804636d244SSean Bruno printf("%s:%d:%d XPT_GET_TRAN_SETTINGS:\n",
13814636d244SSean Bruno device_get_nameunit(sc->fd.dev),
13824636d244SSean Bruno ccb->ccb_h.target_id, ccb->ccb_h.target_lun);
13834636d244SSean Bruno #endif
13844636d244SSean Bruno cts->ccb_h.status = CAM_REQ_CMP;
13854636d244SSean Bruno xpt_done(ccb);
13864636d244SSean Bruno break;
13874636d244SSean Bruno }
13884636d244SSean Bruno #endif
13894636d244SSean Bruno
13904636d244SSean Bruno default:
13914636d244SSean Bruno printf("%s: unknown function 0x%x\n",
13924636d244SSean Bruno __func__, ccb->ccb_h.func_code);
13934636d244SSean Bruno ccb->ccb_h.status = CAM_PROVIDE_FAIL;
13944636d244SSean Bruno xpt_done(ccb);
13954636d244SSean Bruno break;
1396e9e688e2SHidetoshi Shimokawa }
1397e9e688e2SHidetoshi Shimokawa return;
1398e9e688e2SHidetoshi Shimokawa }
1399e9e688e2SHidetoshi Shimokawa
1400e9e688e2SHidetoshi Shimokawa static void
sbp_targ_action(struct cam_sim * sim,union ccb * ccb)1401e9e688e2SHidetoshi Shimokawa sbp_targ_action(struct cam_sim *sim, union ccb *ccb)
1402e9e688e2SHidetoshi Shimokawa {
1403e9e688e2SHidetoshi Shimokawa int s;
1404e9e688e2SHidetoshi Shimokawa
1405e9e688e2SHidetoshi Shimokawa s = splfw();
1406e9e688e2SHidetoshi Shimokawa sbp_targ_action1(sim, ccb);
1407e9e688e2SHidetoshi Shimokawa splx(s);
1408e9e688e2SHidetoshi Shimokawa }
1409e9e688e2SHidetoshi Shimokawa
1410e9e688e2SHidetoshi Shimokawa static void
sbp_targ_poll(struct cam_sim * sim)1411e9e688e2SHidetoshi Shimokawa sbp_targ_poll(struct cam_sim *sim)
1412e9e688e2SHidetoshi Shimokawa {
1413e9e688e2SHidetoshi Shimokawa /* XXX */
1414e9e688e2SHidetoshi Shimokawa return;
1415e9e688e2SHidetoshi Shimokawa }
1416e9e688e2SHidetoshi Shimokawa
1417e9e688e2SHidetoshi Shimokawa static void
sbp_targ_cmd_handler(struct fw_xfer * xfer)1418e9e688e2SHidetoshi Shimokawa sbp_targ_cmd_handler(struct fw_xfer *xfer)
1419e9e688e2SHidetoshi Shimokawa {
142003161bbcSDoug Rabson uint32_t *orb;
1421e9e688e2SHidetoshi Shimokawa struct corb4 *orb4;
1422e9e688e2SHidetoshi Shimokawa struct orb_info *orbi;
1423e9e688e2SHidetoshi Shimokawa struct ccb_accept_tio *atio;
1424e9e688e2SHidetoshi Shimokawa u_char *bytes;
1425e9e688e2SHidetoshi Shimokawa int i;
1426e9e688e2SHidetoshi Shimokawa
1427e9e688e2SHidetoshi Shimokawa orbi = (struct orb_info *)xfer->sc;
1428e9e688e2SHidetoshi Shimokawa if (xfer->resp != 0) {
142910d3ed64SHidetoshi Shimokawa printf("%s: xfer->resp = %d\n", __func__, xfer->resp);
1430e9e688e2SHidetoshi Shimokawa orbi->status.resp = SBP_TRANS_FAIL;
14311398a889SHidetoshi Shimokawa orbi->status.status = OBJ_ORB | SBE_TIMEOUT/*XXX*/;
1432e9e688e2SHidetoshi Shimokawa orbi->status.dead = 1;
1433e9e688e2SHidetoshi Shimokawa orbi->status.len = 1;
14349950b741SHidetoshi Shimokawa sbp_targ_abort(orbi->sc, STAILQ_NEXT(orbi, link));
1435e9e688e2SHidetoshi Shimokawa
1436e9e688e2SHidetoshi Shimokawa sbp_targ_status_FIFO(orbi,
1437a73ff510SHidetoshi Shimokawa orbi->login->fifo_hi, orbi->login->fifo_lo, /*dequeue*/1);
1438e9e688e2SHidetoshi Shimokawa fw_xfer_free(xfer);
1439e9e688e2SHidetoshi Shimokawa return;
1440e9e688e2SHidetoshi Shimokawa }
1441e9e688e2SHidetoshi Shimokawa
14429950b741SHidetoshi Shimokawa atio = orbi->atio;
14439950b741SHidetoshi Shimokawa
1444e9e688e2SHidetoshi Shimokawa if (orbi->state == ORBI_STATUS_ABORTED) {
144510d3ed64SHidetoshi Shimokawa printf("%s: aborted\n", __func__);
1446a73ff510SHidetoshi Shimokawa sbp_targ_remove_orb_info(orbi->login, orbi);
1447e9e688e2SHidetoshi Shimokawa free(orbi, M_SBP_TARG);
14489950b741SHidetoshi Shimokawa atio->ccb_h.status = CAM_REQ_ABORTED;
14499950b741SHidetoshi Shimokawa xpt_done((union ccb*)atio);
1450e9e688e2SHidetoshi Shimokawa goto done0;
1451e9e688e2SHidetoshi Shimokawa }
1452e9e688e2SHidetoshi Shimokawa orbi->state = ORBI_STATUS_ATIO;
1453e9e688e2SHidetoshi Shimokawa
1454e9e688e2SHidetoshi Shimokawa orb = orbi->orb;
1455e9e688e2SHidetoshi Shimokawa /* swap payload except SCSI command */
1456e9e688e2SHidetoshi Shimokawa for (i = 0; i < 5; i++)
1457e9e688e2SHidetoshi Shimokawa orb[i] = ntohl(orb[i]);
1458e9e688e2SHidetoshi Shimokawa
1459e9e688e2SHidetoshi Shimokawa orb4 = (struct corb4 *)&orb[4];
1460e9e688e2SHidetoshi Shimokawa if (orb4->rq_fmt != 0) {
1461e9e688e2SHidetoshi Shimokawa /* XXX */
146210d3ed64SHidetoshi Shimokawa printf("%s: rq_fmt(%d) != 0\n", __func__, orb4->rq_fmt);
1463e9e688e2SHidetoshi Shimokawa }
1464e9e688e2SHidetoshi Shimokawa
1465e9e688e2SHidetoshi Shimokawa atio->ccb_h.target_id = 0; /* XXX */
1466a73ff510SHidetoshi Shimokawa atio->ccb_h.target_lun = orbi->login->lstate->lun;
1467e9e688e2SHidetoshi Shimokawa atio->sense_len = 0;
14684636d244SSean Bruno atio->tag_action = MSG_SIMPLE_TASK;
1469e9e688e2SHidetoshi Shimokawa atio->tag_id = orbi->orb_lo;
1470a73ff510SHidetoshi Shimokawa atio->init_id = orbi->login->id;
1471a73ff510SHidetoshi Shimokawa
14725e63cdb4SAlexander Motin atio->ccb_h.flags |= CAM_TAG_ACTION_VALID;
14739950b741SHidetoshi Shimokawa bytes = (u_char *)&orb[5];
1474e9e688e2SHidetoshi Shimokawa if (debug)
14759950b741SHidetoshi Shimokawa printf("%s: %p %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
14769950b741SHidetoshi Shimokawa __func__, (void *)atio,
1477e9e688e2SHidetoshi Shimokawa bytes[0], bytes[1], bytes[2], bytes[3], bytes[4],
1478e9e688e2SHidetoshi Shimokawa bytes[5], bytes[6], bytes[7], bytes[8], bytes[9]);
1479e9e688e2SHidetoshi Shimokawa switch (bytes[0] >> 5) {
1480e9e688e2SHidetoshi Shimokawa case 0:
1481e9e688e2SHidetoshi Shimokawa atio->cdb_len = 6;
1482e9e688e2SHidetoshi Shimokawa break;
1483e9e688e2SHidetoshi Shimokawa case 1:
1484e9e688e2SHidetoshi Shimokawa case 2:
1485e9e688e2SHidetoshi Shimokawa atio->cdb_len = 10;
1486e9e688e2SHidetoshi Shimokawa break;
1487e9e688e2SHidetoshi Shimokawa case 4:
1488e9e688e2SHidetoshi Shimokawa atio->cdb_len = 16;
1489e9e688e2SHidetoshi Shimokawa break;
1490e9e688e2SHidetoshi Shimokawa case 5:
1491e9e688e2SHidetoshi Shimokawa atio->cdb_len = 12;
1492e9e688e2SHidetoshi Shimokawa break;
1493e9e688e2SHidetoshi Shimokawa case 3:
1494e9e688e2SHidetoshi Shimokawa default:
1495e9e688e2SHidetoshi Shimokawa /* Only copy the opcode. */
1496e9e688e2SHidetoshi Shimokawa atio->cdb_len = 1;
1497e9e688e2SHidetoshi Shimokawa printf("Reserved or VU command code type encountered\n");
1498e9e688e2SHidetoshi Shimokawa break;
1499e9e688e2SHidetoshi Shimokawa }
1500e9e688e2SHidetoshi Shimokawa
1501e9e688e2SHidetoshi Shimokawa memcpy(atio->cdb_io.cdb_bytes, bytes, atio->cdb_len);
1502e9e688e2SHidetoshi Shimokawa
1503e9e688e2SHidetoshi Shimokawa atio->ccb_h.status |= CAM_CDB_RECVD;
1504e9e688e2SHidetoshi Shimokawa
1505e9e688e2SHidetoshi Shimokawa /* next ORB */
1506e9e688e2SHidetoshi Shimokawa if ((orb[0] & (1<<31)) == 0) {
1507e9e688e2SHidetoshi Shimokawa if (debug)
150810d3ed64SHidetoshi Shimokawa printf("%s: fetch next orb\n", __func__);
1509e9e688e2SHidetoshi Shimokawa orbi->status.src = SRC_NEXT_EXISTS;
1510e9e688e2SHidetoshi Shimokawa sbp_targ_fetch_orb(orbi->sc, orbi->fwdev,
1511a73ff510SHidetoshi Shimokawa orb[0], orb[1], orbi->login, FETCH_CMD);
1512e9e688e2SHidetoshi Shimokawa } else {
1513e9e688e2SHidetoshi Shimokawa orbi->status.src = SRC_NO_NEXT;
1514a73ff510SHidetoshi Shimokawa orbi->login->flags &= ~F_LINK_ACTIVE;
1515e9e688e2SHidetoshi Shimokawa }
1516e9e688e2SHidetoshi Shimokawa
1517e9e688e2SHidetoshi Shimokawa orbi->data_hi = orb[2];
1518e9e688e2SHidetoshi Shimokawa orbi->data_lo = orb[3];
1519e9e688e2SHidetoshi Shimokawa orbi->orb4 = *orb4;
1520e9e688e2SHidetoshi Shimokawa
1521e9e688e2SHidetoshi Shimokawa xpt_done((union ccb*)atio);
1522e9e688e2SHidetoshi Shimokawa done0:
1523e9e688e2SHidetoshi Shimokawa fw_xfer_free(xfer);
1524e9e688e2SHidetoshi Shimokawa return;
1525e9e688e2SHidetoshi Shimokawa }
1526e9e688e2SHidetoshi Shimokawa
1527a73ff510SHidetoshi Shimokawa static struct sbp_targ_login *
sbp_targ_get_login(struct sbp_targ_softc * sc,struct fw_device * fwdev,int lun)1528a73ff510SHidetoshi Shimokawa sbp_targ_get_login(struct sbp_targ_softc *sc, struct fw_device *fwdev, int lun)
1529a73ff510SHidetoshi Shimokawa {
1530a73ff510SHidetoshi Shimokawa struct sbp_targ_lstate *lstate;
1531a73ff510SHidetoshi Shimokawa struct sbp_targ_login *login;
1532a73ff510SHidetoshi Shimokawa int i;
1533a73ff510SHidetoshi Shimokawa
1534a73ff510SHidetoshi Shimokawa lstate = sc->lstate[lun];
1535a73ff510SHidetoshi Shimokawa
1536a73ff510SHidetoshi Shimokawa STAILQ_FOREACH(login, &lstate->logins, link)
1537a73ff510SHidetoshi Shimokawa if (login->fwdev == fwdev)
1538a73ff510SHidetoshi Shimokawa return (login);
1539a73ff510SHidetoshi Shimokawa
1540a73ff510SHidetoshi Shimokawa for (i = 0; i < MAX_LOGINS; i++)
1541a73ff510SHidetoshi Shimokawa if (sc->logins[i] == NULL)
1542a73ff510SHidetoshi Shimokawa goto found;
1543a73ff510SHidetoshi Shimokawa
154410d3ed64SHidetoshi Shimokawa printf("%s: increase MAX_LOGIN\n", __func__);
1545a73ff510SHidetoshi Shimokawa return (NULL);
1546a73ff510SHidetoshi Shimokawa
1547a73ff510SHidetoshi Shimokawa found:
1548a73ff510SHidetoshi Shimokawa login = (struct sbp_targ_login *)malloc(
1549a73ff510SHidetoshi Shimokawa sizeof(struct sbp_targ_login), M_SBP_TARG, M_NOWAIT | M_ZERO);
1550a73ff510SHidetoshi Shimokawa
1551a73ff510SHidetoshi Shimokawa if (login == NULL) {
155210d3ed64SHidetoshi Shimokawa printf("%s: malloc failed\n", __func__);
1553a73ff510SHidetoshi Shimokawa return (NULL);
1554a73ff510SHidetoshi Shimokawa }
1555a73ff510SHidetoshi Shimokawa
1556c6cf3e20SHidetoshi Shimokawa login->id = i;
1557a73ff510SHidetoshi Shimokawa login->fwdev = fwdev;
1558a73ff510SHidetoshi Shimokawa login->lstate = lstate;
1559a73ff510SHidetoshi Shimokawa login->last_hi = 0xffff;
1560a73ff510SHidetoshi Shimokawa login->last_lo = 0xffffffff;
1561a73ff510SHidetoshi Shimokawa login->hold_sec = 1;
1562a73ff510SHidetoshi Shimokawa STAILQ_INIT(&login->orbs);
1563a73ff510SHidetoshi Shimokawa CALLOUT_INIT(&login->hold_callout);
1564a73ff510SHidetoshi Shimokawa sc->logins[i] = login;
1565a73ff510SHidetoshi Shimokawa return (login);
1566a73ff510SHidetoshi Shimokawa }
1567a73ff510SHidetoshi Shimokawa
1568e9e688e2SHidetoshi Shimokawa static void
sbp_targ_mgm_handler(struct fw_xfer * xfer)1569e9e688e2SHidetoshi Shimokawa sbp_targ_mgm_handler(struct fw_xfer *xfer)
1570e9e688e2SHidetoshi Shimokawa {
1571e9e688e2SHidetoshi Shimokawa struct sbp_targ_lstate *lstate;
1572a73ff510SHidetoshi Shimokawa struct sbp_targ_login *login;
157303161bbcSDoug Rabson uint32_t *orb;
1574e9e688e2SHidetoshi Shimokawa struct morb4 *orb4;
1575e9e688e2SHidetoshi Shimokawa struct orb_info *orbi;
1576e9e688e2SHidetoshi Shimokawa int i;
1577e9e688e2SHidetoshi Shimokawa
1578e9e688e2SHidetoshi Shimokawa orbi = (struct orb_info *)xfer->sc;
1579e9e688e2SHidetoshi Shimokawa if (xfer->resp != 0) {
158010d3ed64SHidetoshi Shimokawa printf("%s: xfer->resp = %d\n", __func__, xfer->resp);
1581e9e688e2SHidetoshi Shimokawa orbi->status.resp = SBP_TRANS_FAIL;
15821398a889SHidetoshi Shimokawa orbi->status.status = OBJ_ORB | SBE_TIMEOUT/*XXX*/;
1583e9e688e2SHidetoshi Shimokawa orbi->status.dead = 1;
1584e9e688e2SHidetoshi Shimokawa orbi->status.len = 1;
15859950b741SHidetoshi Shimokawa sbp_targ_abort(orbi->sc, STAILQ_NEXT(orbi, link));
1586e9e688e2SHidetoshi Shimokawa
1587e9e688e2SHidetoshi Shimokawa sbp_targ_status_FIFO(orbi,
1588a73ff510SHidetoshi Shimokawa orbi->login->fifo_hi, orbi->login->fifo_lo, /*dequeue*/0);
1589e9e688e2SHidetoshi Shimokawa fw_xfer_free(xfer);
1590e9e688e2SHidetoshi Shimokawa return;
1591e9e688e2SHidetoshi Shimokawa }
1592e9e688e2SHidetoshi Shimokawa
1593e9e688e2SHidetoshi Shimokawa orb = orbi->orb;
1594e9e688e2SHidetoshi Shimokawa /* swap payload */
1595e9e688e2SHidetoshi Shimokawa for (i = 0; i < 8; i++) {
1596e9e688e2SHidetoshi Shimokawa orb[i] = ntohl(orb[i]);
1597e9e688e2SHidetoshi Shimokawa }
1598e9e688e2SHidetoshi Shimokawa orb4 = (struct morb4 *)&orb[4];
1599e9e688e2SHidetoshi Shimokawa if (debug)
160010d3ed64SHidetoshi Shimokawa printf("%s: %s\n", __func__, orb_fun_name[orb4->fun]);
1601e9e688e2SHidetoshi Shimokawa
1602e9e688e2SHidetoshi Shimokawa orbi->status.src = SRC_NO_NEXT;
1603e9e688e2SHidetoshi Shimokawa
1604e9e688e2SHidetoshi Shimokawa switch (orb4->fun << 16) {
1605e9e688e2SHidetoshi Shimokawa case ORB_FUN_LGI:
1606e9e688e2SHidetoshi Shimokawa {
1607a73ff510SHidetoshi Shimokawa int exclusive = 0, lun;
1608e9e688e2SHidetoshi Shimokawa
1609a73ff510SHidetoshi Shimokawa if (orb[4] & ORB_EXV)
1610a73ff510SHidetoshi Shimokawa exclusive = 1;
1611a73ff510SHidetoshi Shimokawa
1612a73ff510SHidetoshi Shimokawa lun = orb4->id;
1613a73ff510SHidetoshi Shimokawa lstate = orbi->sc->lstate[lun];
1614a73ff510SHidetoshi Shimokawa
1615a73ff510SHidetoshi Shimokawa if (lun >= MAX_LUN || lstate == NULL ||
1616a73ff510SHidetoshi Shimokawa (exclusive &&
1617a73ff510SHidetoshi Shimokawa STAILQ_FIRST(&lstate->logins) != NULL &&
1618a73ff510SHidetoshi Shimokawa STAILQ_FIRST(&lstate->logins)->fwdev != orbi->fwdev)
1619a73ff510SHidetoshi Shimokawa ) {
1620e9e688e2SHidetoshi Shimokawa /* error */
1621e9e688e2SHidetoshi Shimokawa orbi->status.dead = 1;
1622e9e688e2SHidetoshi Shimokawa orbi->status.status = STATUS_ACCESS_DENY;
1623e9e688e2SHidetoshi Shimokawa orbi->status.len = 1;
1624e9e688e2SHidetoshi Shimokawa break;
1625e9e688e2SHidetoshi Shimokawa }
1626a73ff510SHidetoshi Shimokawa
1627a73ff510SHidetoshi Shimokawa /* allocate login */
1628a73ff510SHidetoshi Shimokawa login = sbp_targ_get_login(orbi->sc, orbi->fwdev, lun);
1629a73ff510SHidetoshi Shimokawa if (login == NULL) {
1630a73ff510SHidetoshi Shimokawa printf("%s: sbp_targ_get_login failed\n",
163110d3ed64SHidetoshi Shimokawa __func__);
1632a73ff510SHidetoshi Shimokawa orbi->status.dead = 1;
1633a73ff510SHidetoshi Shimokawa orbi->status.status = STATUS_RES_UNAVAIL;
1634a73ff510SHidetoshi Shimokawa orbi->status.len = 1;
1635a73ff510SHidetoshi Shimokawa break;
1636a73ff510SHidetoshi Shimokawa }
16379950b741SHidetoshi Shimokawa printf("%s: login id=%d\n", __func__, login->id);
1638a73ff510SHidetoshi Shimokawa
1639a73ff510SHidetoshi Shimokawa login->fifo_hi = orb[6];
1640a73ff510SHidetoshi Shimokawa login->fifo_lo = orb[7];
164103161bbcSDoug Rabson login->loginres.len = htons(sizeof(uint32_t) * 4);
1642a73ff510SHidetoshi Shimokawa login->loginres.id = htons(login->id);
1643a73ff510SHidetoshi Shimokawa login->loginres.cmd_hi = htons(SBP_TARG_BIND_HI);
1644a73ff510SHidetoshi Shimokawa login->loginres.cmd_lo = htonl(SBP_TARG_BIND_LO(login->id));
1645a73ff510SHidetoshi Shimokawa login->loginres.recon_hold = htons(login->hold_sec);
1646a73ff510SHidetoshi Shimokawa
16479950b741SHidetoshi Shimokawa STAILQ_INSERT_TAIL(&lstate->logins, login, link);
16484636d244SSean Bruno fwmem_write_block(orbi->fwdev, NULL, /*spd*/FWSPD_S400, orb[2], orb[3],
1649a73ff510SHidetoshi Shimokawa sizeof(struct sbp_login_res), (void *)&login->loginres,
1650e9e688e2SHidetoshi Shimokawa fw_asy_callback_free);
1651c54d1fe2SHidetoshi Shimokawa /* XXX return status after loginres is successfully written */
1652e9e688e2SHidetoshi Shimokawa break;
1653e9e688e2SHidetoshi Shimokawa }
1654e9e688e2SHidetoshi Shimokawa case ORB_FUN_RCN:
1655a73ff510SHidetoshi Shimokawa login = orbi->sc->logins[orb4->id];
1656a73ff510SHidetoshi Shimokawa if (login != NULL && login->fwdev == orbi->fwdev) {
1657a73ff510SHidetoshi Shimokawa login->flags &= ~F_HOLD;
1658a73ff510SHidetoshi Shimokawa callout_stop(&login->hold_callout);
1659a73ff510SHidetoshi Shimokawa printf("%s: reconnected id=%d\n",
166010d3ed64SHidetoshi Shimokawa __func__, login->id);
1661a73ff510SHidetoshi Shimokawa } else {
1662e9e688e2SHidetoshi Shimokawa orbi->status.dead = 1;
1663e9e688e2SHidetoshi Shimokawa orbi->status.status = STATUS_ACCESS_DENY;
1664*c03e35acSGordon Bergling printf("%s: reconnection failed id=%d\n",
166510d3ed64SHidetoshi Shimokawa __func__, orb4->id);
1666a73ff510SHidetoshi Shimokawa }
1667a73ff510SHidetoshi Shimokawa break;
1668a73ff510SHidetoshi Shimokawa case ORB_FUN_LGO:
1669a73ff510SHidetoshi Shimokawa login = orbi->sc->logins[orb4->id];
1670a73ff510SHidetoshi Shimokawa if (login->fwdev != orbi->fwdev) {
167110d3ed64SHidetoshi Shimokawa printf("%s: wrong initiator\n", __func__);
1672a73ff510SHidetoshi Shimokawa break;
1673a73ff510SHidetoshi Shimokawa }
1674a73ff510SHidetoshi Shimokawa sbp_targ_dealloc_login(login);
1675e9e688e2SHidetoshi Shimokawa break;
1676e9e688e2SHidetoshi Shimokawa default:
1677e9e688e2SHidetoshi Shimokawa printf("%s: %s not implemented yet\n",
167810d3ed64SHidetoshi Shimokawa __func__, orb_fun_name[orb4->fun]);
1679e9e688e2SHidetoshi Shimokawa break;
1680e9e688e2SHidetoshi Shimokawa }
1681e9e688e2SHidetoshi Shimokawa orbi->status.len = 1;
1682e9e688e2SHidetoshi Shimokawa sbp_targ_status_FIFO(orbi, orb[6], orb[7], /*dequeue*/0);
1683e9e688e2SHidetoshi Shimokawa fw_xfer_free(xfer);
1684e9e688e2SHidetoshi Shimokawa return;
1685e9e688e2SHidetoshi Shimokawa }
1686e9e688e2SHidetoshi Shimokawa
1687e9e688e2SHidetoshi Shimokawa static void
sbp_targ_pointer_handler(struct fw_xfer * xfer)1688e9e688e2SHidetoshi Shimokawa sbp_targ_pointer_handler(struct fw_xfer *xfer)
1689e9e688e2SHidetoshi Shimokawa {
1690e9e688e2SHidetoshi Shimokawa struct orb_info *orbi;
169103161bbcSDoug Rabson uint32_t orb0, orb1;
1692e9e688e2SHidetoshi Shimokawa
1693e9e688e2SHidetoshi Shimokawa orbi = (struct orb_info *)xfer->sc;
1694e9e688e2SHidetoshi Shimokawa if (xfer->resp != 0) {
169510d3ed64SHidetoshi Shimokawa printf("%s: xfer->resp = %d\n", __func__, xfer->resp);
1696e9e688e2SHidetoshi Shimokawa goto done;
1697e9e688e2SHidetoshi Shimokawa }
1698e9e688e2SHidetoshi Shimokawa
1699e9e688e2SHidetoshi Shimokawa orb0 = ntohl(orbi->orb[0]);
1700e9e688e2SHidetoshi Shimokawa orb1 = ntohl(orbi->orb[1]);
17017a22215cSEitan Adler if ((orb0 & (1U << 31)) != 0) {
170210d3ed64SHidetoshi Shimokawa printf("%s: invalid pointer\n", __func__);
1703e9e688e2SHidetoshi Shimokawa goto done;
1704e9e688e2SHidetoshi Shimokawa }
1705a73ff510SHidetoshi Shimokawa sbp_targ_fetch_orb(orbi->login->lstate->sc, orbi->fwdev,
170603161bbcSDoug Rabson (uint16_t)orb0, orb1, orbi->login, FETCH_CMD);
1707e9e688e2SHidetoshi Shimokawa done:
1708e9e688e2SHidetoshi Shimokawa free(orbi, M_SBP_TARG);
1709e9e688e2SHidetoshi Shimokawa fw_xfer_free(xfer);
1710e9e688e2SHidetoshi Shimokawa return;
1711e9e688e2SHidetoshi Shimokawa }
1712e9e688e2SHidetoshi Shimokawa
1713e9e688e2SHidetoshi Shimokawa static void
sbp_targ_fetch_orb(struct sbp_targ_softc * sc,struct fw_device * fwdev,uint16_t orb_hi,uint32_t orb_lo,struct sbp_targ_login * login,int mode)1714e9e688e2SHidetoshi Shimokawa sbp_targ_fetch_orb(struct sbp_targ_softc *sc, struct fw_device *fwdev,
171503161bbcSDoug Rabson uint16_t orb_hi, uint32_t orb_lo, struct sbp_targ_login *login,
1716e9e688e2SHidetoshi Shimokawa int mode)
1717e9e688e2SHidetoshi Shimokawa {
1718e9e688e2SHidetoshi Shimokawa struct orb_info *orbi;
1719e9e688e2SHidetoshi Shimokawa
1720e9e688e2SHidetoshi Shimokawa if (debug)
172110d3ed64SHidetoshi Shimokawa printf("%s: fetch orb %04x:%08x\n", __func__, orb_hi, orb_lo);
1722e9e688e2SHidetoshi Shimokawa orbi = malloc(sizeof(struct orb_info), M_SBP_TARG, M_NOWAIT | M_ZERO);
1723e9e688e2SHidetoshi Shimokawa if (orbi == NULL) {
172410d3ed64SHidetoshi Shimokawa printf("%s: malloc failed\n", __func__);
1725e9e688e2SHidetoshi Shimokawa return;
1726e9e688e2SHidetoshi Shimokawa }
1727e9e688e2SHidetoshi Shimokawa orbi->sc = sc;
1728e9e688e2SHidetoshi Shimokawa orbi->fwdev = fwdev;
1729a73ff510SHidetoshi Shimokawa orbi->login = login;
1730e9e688e2SHidetoshi Shimokawa orbi->orb_hi = orb_hi;
1731e9e688e2SHidetoshi Shimokawa orbi->orb_lo = orb_lo;
1732e9e688e2SHidetoshi Shimokawa orbi->status.orb_hi = htons(orb_hi);
1733e9e688e2SHidetoshi Shimokawa orbi->status.orb_lo = htonl(orb_lo);
17344636d244SSean Bruno orbi->page_table = NULL;
1735e9e688e2SHidetoshi Shimokawa
1736e9e688e2SHidetoshi Shimokawa switch (mode) {
1737e9e688e2SHidetoshi Shimokawa case FETCH_MGM:
17384636d244SSean Bruno fwmem_read_block(fwdev, (void *)orbi, /*spd*/FWSPD_S400, orb_hi, orb_lo,
173903161bbcSDoug Rabson sizeof(uint32_t) * 8, &orbi->orb[0],
1740e9e688e2SHidetoshi Shimokawa sbp_targ_mgm_handler);
1741e9e688e2SHidetoshi Shimokawa break;
1742e9e688e2SHidetoshi Shimokawa case FETCH_CMD:
1743e9e688e2SHidetoshi Shimokawa orbi->state = ORBI_STATUS_FETCH;
1744a73ff510SHidetoshi Shimokawa login->last_hi = orb_hi;
1745a73ff510SHidetoshi Shimokawa login->last_lo = orb_lo;
1746a73ff510SHidetoshi Shimokawa login->flags |= F_LINK_ACTIVE;
1747e9e688e2SHidetoshi Shimokawa /* dequeue */
17489950b741SHidetoshi Shimokawa SBP_LOCK(sc);
1749e9e688e2SHidetoshi Shimokawa orbi->atio = (struct ccb_accept_tio *)
1750a73ff510SHidetoshi Shimokawa SLIST_FIRST(&login->lstate->accept_tios);
1751e9e688e2SHidetoshi Shimokawa if (orbi->atio == NULL) {
17529950b741SHidetoshi Shimokawa SBP_UNLOCK(sc);
175310d3ed64SHidetoshi Shimokawa printf("%s: no free atio\n", __func__);
1754a73ff510SHidetoshi Shimokawa login->lstate->flags |= F_ATIO_STARVED;
1755a73ff510SHidetoshi Shimokawa login->flags |= F_ATIO_STARVED;
1756a73ff510SHidetoshi Shimokawa #if 0
1757a73ff510SHidetoshi Shimokawa /* XXX ?? */
1758a73ff510SHidetoshi Shimokawa login->fwdev = fwdev;
1759a73ff510SHidetoshi Shimokawa #endif
1760e9e688e2SHidetoshi Shimokawa break;
1761e9e688e2SHidetoshi Shimokawa }
1762a73ff510SHidetoshi Shimokawa SLIST_REMOVE_HEAD(&login->lstate->accept_tios, sim_links.sle);
17639950b741SHidetoshi Shimokawa STAILQ_INSERT_TAIL(&login->orbs, orbi, link);
17649950b741SHidetoshi Shimokawa SBP_UNLOCK(sc);
17654636d244SSean Bruno fwmem_read_block(fwdev, (void *)orbi, /*spd*/FWSPD_S400, orb_hi, orb_lo,
176603161bbcSDoug Rabson sizeof(uint32_t) * 8, &orbi->orb[0],
1767e9e688e2SHidetoshi Shimokawa sbp_targ_cmd_handler);
1768e9e688e2SHidetoshi Shimokawa break;
1769e9e688e2SHidetoshi Shimokawa case FETCH_POINTER:
1770e9e688e2SHidetoshi Shimokawa orbi->state = ORBI_STATUS_POINTER;
1771a73ff510SHidetoshi Shimokawa login->flags |= F_LINK_ACTIVE;
17724636d244SSean Bruno fwmem_read_block(fwdev, (void *)orbi, /*spd*/FWSPD_S400, orb_hi, orb_lo,
177303161bbcSDoug Rabson sizeof(uint32_t) * 2, &orbi->orb[0],
1774e9e688e2SHidetoshi Shimokawa sbp_targ_pointer_handler);
1775e9e688e2SHidetoshi Shimokawa break;
1776e9e688e2SHidetoshi Shimokawa default:
177710d3ed64SHidetoshi Shimokawa printf("%s: invalid mode %d\n", __func__, mode);
1778e9e688e2SHidetoshi Shimokawa }
1779e9e688e2SHidetoshi Shimokawa }
1780e9e688e2SHidetoshi Shimokawa
1781e9e688e2SHidetoshi Shimokawa static void
sbp_targ_resp_callback(struct fw_xfer * xfer)1782e9e688e2SHidetoshi Shimokawa sbp_targ_resp_callback(struct fw_xfer *xfer)
1783e9e688e2SHidetoshi Shimokawa {
1784e9e688e2SHidetoshi Shimokawa struct sbp_targ_softc *sc;
1785e9e688e2SHidetoshi Shimokawa int s;
1786e9e688e2SHidetoshi Shimokawa
1787e9e688e2SHidetoshi Shimokawa if (debug)
178810d3ed64SHidetoshi Shimokawa printf("%s: xfer=%p\n", __func__, xfer);
1789e9e688e2SHidetoshi Shimokawa sc = (struct sbp_targ_softc *)xfer->sc;
1790e9e688e2SHidetoshi Shimokawa fw_xfer_unload(xfer);
1791e9e688e2SHidetoshi Shimokawa xfer->recv.pay_len = SBP_TARG_RECV_LEN;
1792801167a8SHidetoshi Shimokawa xfer->hand = sbp_targ_recv;
1793e9e688e2SHidetoshi Shimokawa s = splfw();
1794e9e688e2SHidetoshi Shimokawa STAILQ_INSERT_TAIL(&sc->fwb.xferlist, xfer, link);
1795e9e688e2SHidetoshi Shimokawa splx(s);
1796e9e688e2SHidetoshi Shimokawa }
1797e9e688e2SHidetoshi Shimokawa
1798e9e688e2SHidetoshi Shimokawa static int
sbp_targ_cmd(struct fw_xfer * xfer,struct fw_device * fwdev,int login_id,int reg)1799a73ff510SHidetoshi Shimokawa sbp_targ_cmd(struct fw_xfer *xfer, struct fw_device *fwdev, int login_id,
1800a73ff510SHidetoshi Shimokawa int reg)
1801e9e688e2SHidetoshi Shimokawa {
1802a73ff510SHidetoshi Shimokawa struct sbp_targ_login *login;
1803e9e688e2SHidetoshi Shimokawa struct sbp_targ_softc *sc;
1804e9e688e2SHidetoshi Shimokawa int rtcode = 0;
1805e9e688e2SHidetoshi Shimokawa
1806a73ff510SHidetoshi Shimokawa if (login_id < 0 || login_id >= MAX_LOGINS)
1807e9e688e2SHidetoshi Shimokawa return (RESP_ADDRESS_ERROR);
1808e9e688e2SHidetoshi Shimokawa
1809e9e688e2SHidetoshi Shimokawa sc = (struct sbp_targ_softc *)xfer->sc;
1810a73ff510SHidetoshi Shimokawa login = sc->logins[login_id];
1811a73ff510SHidetoshi Shimokawa if (login == NULL)
1812e9e688e2SHidetoshi Shimokawa return (RESP_ADDRESS_ERROR);
1813e9e688e2SHidetoshi Shimokawa
1814a73ff510SHidetoshi Shimokawa if (login->fwdev != fwdev) {
1815a73ff510SHidetoshi Shimokawa /* XXX */
1816a73ff510SHidetoshi Shimokawa return (RESP_ADDRESS_ERROR);
1817a73ff510SHidetoshi Shimokawa }
1818a73ff510SHidetoshi Shimokawa
1819e9e688e2SHidetoshi Shimokawa switch (reg) {
1820e9e688e2SHidetoshi Shimokawa case 0x08: /* ORB_POINTER */
1821e9e688e2SHidetoshi Shimokawa if (debug)
18229950b741SHidetoshi Shimokawa printf("%s: ORB_POINTER(%d)\n", __func__, login_id);
1823a73ff510SHidetoshi Shimokawa if ((login->flags & F_LINK_ACTIVE) != 0) {
1824a73ff510SHidetoshi Shimokawa if (debug)
1825a73ff510SHidetoshi Shimokawa printf("link active (ORB_POINTER)\n");
1826a73ff510SHidetoshi Shimokawa break;
1827a73ff510SHidetoshi Shimokawa }
1828a73ff510SHidetoshi Shimokawa sbp_targ_fetch_orb(sc, fwdev,
1829e9e688e2SHidetoshi Shimokawa ntohl(xfer->recv.payload[0]),
1830e9e688e2SHidetoshi Shimokawa ntohl(xfer->recv.payload[1]),
1831a73ff510SHidetoshi Shimokawa login, FETCH_CMD);
1832e9e688e2SHidetoshi Shimokawa break;
1833e9e688e2SHidetoshi Shimokawa case 0x04: /* AGENT_RESET */
1834e9e688e2SHidetoshi Shimokawa if (debug)
18359950b741SHidetoshi Shimokawa printf("%s: AGENT RESET(%d)\n", __func__, login_id);
1836a73ff510SHidetoshi Shimokawa login->last_hi = 0xffff;
1837a73ff510SHidetoshi Shimokawa login->last_lo = 0xffffffff;
18389950b741SHidetoshi Shimokawa sbp_targ_abort(sc, STAILQ_FIRST(&login->orbs));
1839e9e688e2SHidetoshi Shimokawa break;
1840e9e688e2SHidetoshi Shimokawa case 0x10: /* DOORBELL */
1841e9e688e2SHidetoshi Shimokawa if (debug)
18429950b741SHidetoshi Shimokawa printf("%s: DOORBELL(%d)\n", __func__, login_id);
1843a73ff510SHidetoshi Shimokawa if (login->last_hi == 0xffff &&
1844a73ff510SHidetoshi Shimokawa login->last_lo == 0xffffffff) {
1845e9e688e2SHidetoshi Shimokawa printf("%s: no previous pointer(DOORBELL)\n",
184610d3ed64SHidetoshi Shimokawa __func__);
1847e9e688e2SHidetoshi Shimokawa break;
1848e9e688e2SHidetoshi Shimokawa }
1849a73ff510SHidetoshi Shimokawa if ((login->flags & F_LINK_ACTIVE) != 0) {
1850e9e688e2SHidetoshi Shimokawa if (debug)
1851e9e688e2SHidetoshi Shimokawa printf("link active (DOORBELL)\n");
1852e9e688e2SHidetoshi Shimokawa break;
1853e9e688e2SHidetoshi Shimokawa }
1854a73ff510SHidetoshi Shimokawa sbp_targ_fetch_orb(sc, fwdev,
1855a73ff510SHidetoshi Shimokawa login->last_hi, login->last_lo,
1856a73ff510SHidetoshi Shimokawa login, FETCH_POINTER);
1857e9e688e2SHidetoshi Shimokawa break;
1858e9e688e2SHidetoshi Shimokawa case 0x00: /* AGENT_STATE */
18599950b741SHidetoshi Shimokawa printf("%s: AGENT_STATE (%d:ignore)\n", __func__, login_id);
1860e9e688e2SHidetoshi Shimokawa break;
1861e9e688e2SHidetoshi Shimokawa case 0x14: /* UNSOLICITED_STATE_ENABLE */
18629950b741SHidetoshi Shimokawa printf("%s: UNSOLICITED_STATE_ENABLE (%d:ignore)\n",
18639950b741SHidetoshi Shimokawa __func__, login_id);
1864e9e688e2SHidetoshi Shimokawa break;
1865e9e688e2SHidetoshi Shimokawa default:
18669950b741SHidetoshi Shimokawa printf("%s: invalid register %d(%d)\n",
18679950b741SHidetoshi Shimokawa __func__, reg, login_id);
1868e9e688e2SHidetoshi Shimokawa rtcode = RESP_ADDRESS_ERROR;
1869e9e688e2SHidetoshi Shimokawa }
1870e9e688e2SHidetoshi Shimokawa
1871e9e688e2SHidetoshi Shimokawa return (rtcode);
1872e9e688e2SHidetoshi Shimokawa }
1873e9e688e2SHidetoshi Shimokawa
1874e9e688e2SHidetoshi Shimokawa static int
sbp_targ_mgm(struct fw_xfer * xfer,struct fw_device * fwdev)1875e9e688e2SHidetoshi Shimokawa sbp_targ_mgm(struct fw_xfer *xfer, struct fw_device *fwdev)
1876e9e688e2SHidetoshi Shimokawa {
1877e9e688e2SHidetoshi Shimokawa struct sbp_targ_softc *sc;
1878e9e688e2SHidetoshi Shimokawa struct fw_pkt *fp;
1879e9e688e2SHidetoshi Shimokawa
1880e9e688e2SHidetoshi Shimokawa sc = (struct sbp_targ_softc *)xfer->sc;
1881e9e688e2SHidetoshi Shimokawa
1882e9e688e2SHidetoshi Shimokawa fp = &xfer->recv.hdr;
1883e9e688e2SHidetoshi Shimokawa if (fp->mode.wreqb.tcode != FWTCODE_WREQB) {
188410d3ed64SHidetoshi Shimokawa printf("%s: tcode = %d\n", __func__, fp->mode.wreqb.tcode);
1885e9e688e2SHidetoshi Shimokawa return (RESP_TYPE_ERROR);
1886e9e688e2SHidetoshi Shimokawa }
1887e9e688e2SHidetoshi Shimokawa
1888e9e688e2SHidetoshi Shimokawa sbp_targ_fetch_orb(sc, fwdev,
1889e9e688e2SHidetoshi Shimokawa ntohl(xfer->recv.payload[0]),
1890e9e688e2SHidetoshi Shimokawa ntohl(xfer->recv.payload[1]),
1891e9e688e2SHidetoshi Shimokawa NULL, FETCH_MGM);
1892e9e688e2SHidetoshi Shimokawa
1893e9e688e2SHidetoshi Shimokawa return (0);
1894e9e688e2SHidetoshi Shimokawa }
1895e9e688e2SHidetoshi Shimokawa
1896e9e688e2SHidetoshi Shimokawa static void
sbp_targ_recv(struct fw_xfer * xfer)1897e9e688e2SHidetoshi Shimokawa sbp_targ_recv(struct fw_xfer *xfer)
1898e9e688e2SHidetoshi Shimokawa {
1899e9e688e2SHidetoshi Shimokawa struct fw_pkt *fp, *sfp;
1900e9e688e2SHidetoshi Shimokawa struct fw_device *fwdev;
190103161bbcSDoug Rabson uint32_t lo;
1902e9e688e2SHidetoshi Shimokawa int s, rtcode;
1903e9e688e2SHidetoshi Shimokawa struct sbp_targ_softc *sc;
1904e9e688e2SHidetoshi Shimokawa
1905e9e688e2SHidetoshi Shimokawa s = splfw();
1906e9e688e2SHidetoshi Shimokawa sc = (struct sbp_targ_softc *)xfer->sc;
1907e9e688e2SHidetoshi Shimokawa fp = &xfer->recv.hdr;
1908e9e688e2SHidetoshi Shimokawa fwdev = fw_noderesolve_nodeid(sc->fd.fc, fp->mode.wreqb.src & 0x3f);
1909e9e688e2SHidetoshi Shimokawa if (fwdev == NULL) {
1910e9e688e2SHidetoshi Shimokawa printf("%s: cannot resolve nodeid=%d\n",
191110d3ed64SHidetoshi Shimokawa __func__, fp->mode.wreqb.src & 0x3f);
1912e9e688e2SHidetoshi Shimokawa rtcode = RESP_TYPE_ERROR; /* XXX */
1913e9e688e2SHidetoshi Shimokawa goto done;
1914e9e688e2SHidetoshi Shimokawa }
1915e9e688e2SHidetoshi Shimokawa lo = fp->mode.wreqb.dest_lo;
19169950b741SHidetoshi Shimokawa
1917e9e688e2SHidetoshi Shimokawa if (lo == SBP_TARG_BIND_LO(-1))
1918e9e688e2SHidetoshi Shimokawa rtcode = sbp_targ_mgm(xfer, fwdev);
1919e9e688e2SHidetoshi Shimokawa else if (lo >= SBP_TARG_BIND_LO(0))
1920a73ff510SHidetoshi Shimokawa rtcode = sbp_targ_cmd(xfer, fwdev, SBP_TARG_LOGIN_ID(lo),
1921a73ff510SHidetoshi Shimokawa lo % 0x20);
1922e9e688e2SHidetoshi Shimokawa else
1923e9e688e2SHidetoshi Shimokawa rtcode = RESP_ADDRESS_ERROR;
1924e9e688e2SHidetoshi Shimokawa
1925e9e688e2SHidetoshi Shimokawa done:
1926e9e688e2SHidetoshi Shimokawa if (rtcode != 0)
192710d3ed64SHidetoshi Shimokawa printf("%s: rtcode = %d\n", __func__, rtcode);
1928e9e688e2SHidetoshi Shimokawa sfp = &xfer->send.hdr;
19294636d244SSean Bruno xfer->send.spd = FWSPD_S400;
1930801167a8SHidetoshi Shimokawa xfer->hand = sbp_targ_resp_callback;
1931e9e688e2SHidetoshi Shimokawa sfp->mode.wres.dst = fp->mode.wreqb.src;
1932e9e688e2SHidetoshi Shimokawa sfp->mode.wres.tlrt = fp->mode.wreqb.tlrt;
1933e9e688e2SHidetoshi Shimokawa sfp->mode.wres.tcode = FWTCODE_WRES;
1934e9e688e2SHidetoshi Shimokawa sfp->mode.wres.rtcode = rtcode;
1935e9e688e2SHidetoshi Shimokawa sfp->mode.wres.pri = 0;
1936e9e688e2SHidetoshi Shimokawa
1937e9e688e2SHidetoshi Shimokawa fw_asyreq(xfer->fc, -1, xfer);
1938e9e688e2SHidetoshi Shimokawa splx(s);
1939e9e688e2SHidetoshi Shimokawa }
1940e9e688e2SHidetoshi Shimokawa
1941e9e688e2SHidetoshi Shimokawa static int
sbp_targ_attach(device_t dev)1942e9e688e2SHidetoshi Shimokawa sbp_targ_attach(device_t dev)
1943e9e688e2SHidetoshi Shimokawa {
1944e9e688e2SHidetoshi Shimokawa struct sbp_targ_softc *sc;
1945e9e688e2SHidetoshi Shimokawa struct cam_devq *devq;
19469950b741SHidetoshi Shimokawa struct firewire_comm *fc;
1947e9e688e2SHidetoshi Shimokawa
1948e9e688e2SHidetoshi Shimokawa sc = (struct sbp_targ_softc *) device_get_softc(dev);
1949e9e688e2SHidetoshi Shimokawa bzero((void *)sc, sizeof(struct sbp_targ_softc));
1950e9e688e2SHidetoshi Shimokawa
19519950b741SHidetoshi Shimokawa mtx_init(&sc->mtx, "sbp_targ", NULL, MTX_DEF);
19529950b741SHidetoshi Shimokawa sc->fd.fc = fc = device_get_ivars(dev);
1953e9e688e2SHidetoshi Shimokawa sc->fd.dev = dev;
1954a73ff510SHidetoshi Shimokawa sc->fd.post_explore = (void *) sbp_targ_post_explore;
1955e9e688e2SHidetoshi Shimokawa sc->fd.post_busreset = (void *) sbp_targ_post_busreset;
1956e9e688e2SHidetoshi Shimokawa
1957c6cf3e20SHidetoshi Shimokawa devq = cam_simq_alloc(/*maxopenings*/MAX_LUN*MAX_INITIATORS);
1958e9e688e2SHidetoshi Shimokawa if (devq == NULL)
1959e9e688e2SHidetoshi Shimokawa return (ENXIO);
1960e9e688e2SHidetoshi Shimokawa
1961e9e688e2SHidetoshi Shimokawa sc->sim = cam_sim_alloc(sbp_targ_action, sbp_targ_poll,
19629950b741SHidetoshi Shimokawa "sbp_targ", sc, device_get_unit(dev), &sc->mtx,
1963e9e688e2SHidetoshi Shimokawa /*untagged*/ 1, /*tagged*/ 1, devq);
1964e9e688e2SHidetoshi Shimokawa if (sc->sim == NULL) {
1965e9e688e2SHidetoshi Shimokawa cam_simq_free(devq);
1966e9e688e2SHidetoshi Shimokawa return (ENXIO);
1967e9e688e2SHidetoshi Shimokawa }
1968e9e688e2SHidetoshi Shimokawa
19699950b741SHidetoshi Shimokawa SBP_LOCK(sc);
1970b50569b7SScott Long if (xpt_bus_register(sc->sim, dev, /*bus*/0) != CAM_SUCCESS)
1971e9e688e2SHidetoshi Shimokawa goto fail;
1972e9e688e2SHidetoshi Shimokawa
1973e9e688e2SHidetoshi Shimokawa if (xpt_create_path(&sc->path, /*periph*/ NULL, cam_sim_path(sc->sim),
1974e9e688e2SHidetoshi Shimokawa CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
1975e9e688e2SHidetoshi Shimokawa xpt_bus_deregister(cam_sim_path(sc->sim));
1976e9e688e2SHidetoshi Shimokawa goto fail;
1977e9e688e2SHidetoshi Shimokawa }
19789950b741SHidetoshi Shimokawa SBP_UNLOCK(sc);
1979e9e688e2SHidetoshi Shimokawa
1980e9e688e2SHidetoshi Shimokawa sc->fwb.start = SBP_TARG_BIND_START;
1981e9e688e2SHidetoshi Shimokawa sc->fwb.end = SBP_TARG_BIND_END;
1982e9e688e2SHidetoshi Shimokawa
1983e9e688e2SHidetoshi Shimokawa /* pre-allocate xfer */
1984e9e688e2SHidetoshi Shimokawa STAILQ_INIT(&sc->fwb.xferlist);
19850892f4c5SHidetoshi Shimokawa fw_xferlist_add(&sc->fwb.xferlist, M_SBP_TARG,
19860892f4c5SHidetoshi Shimokawa /*send*/ 0, /*recv*/ SBP_TARG_RECV_LEN, MAX_LUN /* XXX */,
19879950b741SHidetoshi Shimokawa fc, (void *)sc, sbp_targ_recv);
19889950b741SHidetoshi Shimokawa fw_bindadd(fc, &sc->fwb);
1989e9e688e2SHidetoshi Shimokawa return 0;
1990e9e688e2SHidetoshi Shimokawa
1991e9e688e2SHidetoshi Shimokawa fail:
19929950b741SHidetoshi Shimokawa SBP_UNLOCK(sc);
1993e9e688e2SHidetoshi Shimokawa cam_sim_free(sc->sim, /*free_devq*/TRUE);
1994e9e688e2SHidetoshi Shimokawa return (ENXIO);
1995e9e688e2SHidetoshi Shimokawa }
1996e9e688e2SHidetoshi Shimokawa
1997e9e688e2SHidetoshi Shimokawa static int
sbp_targ_detach(device_t dev)1998e9e688e2SHidetoshi Shimokawa sbp_targ_detach(device_t dev)
1999e9e688e2SHidetoshi Shimokawa {
2000e9e688e2SHidetoshi Shimokawa struct sbp_targ_softc *sc;
2001e9e688e2SHidetoshi Shimokawa struct sbp_targ_lstate *lstate;
2002e9e688e2SHidetoshi Shimokawa int i;
2003e9e688e2SHidetoshi Shimokawa
2004e9e688e2SHidetoshi Shimokawa sc = (struct sbp_targ_softc *)device_get_softc(dev);
2005e9e688e2SHidetoshi Shimokawa sc->fd.post_busreset = NULL;
2006e9e688e2SHidetoshi Shimokawa
20079950b741SHidetoshi Shimokawa SBP_LOCK(sc);
2008e9e688e2SHidetoshi Shimokawa xpt_free_path(sc->path);
2009e9e688e2SHidetoshi Shimokawa xpt_bus_deregister(cam_sim_path(sc->sim));
2010e9e688e2SHidetoshi Shimokawa cam_sim_free(sc->sim, /*free_devq*/TRUE);
201194792a2cSAlexander Motin SBP_UNLOCK(sc);
2012e9e688e2SHidetoshi Shimokawa
2013e9e688e2SHidetoshi Shimokawa for (i = 0; i < MAX_LUN; i++) {
2014e9e688e2SHidetoshi Shimokawa lstate = sc->lstate[i];
2015e9e688e2SHidetoshi Shimokawa if (lstate != NULL) {
2016e9e688e2SHidetoshi Shimokawa xpt_free_path(lstate->path);
2017e9e688e2SHidetoshi Shimokawa free(lstate, M_SBP_TARG);
2018e9e688e2SHidetoshi Shimokawa }
2019e9e688e2SHidetoshi Shimokawa }
2020e9e688e2SHidetoshi Shimokawa if (sc->black_hole != NULL) {
2021e9e688e2SHidetoshi Shimokawa xpt_free_path(sc->black_hole->path);
2022e9e688e2SHidetoshi Shimokawa free(sc->black_hole, M_SBP_TARG);
2023e9e688e2SHidetoshi Shimokawa }
2024e9e688e2SHidetoshi Shimokawa
2025e9e688e2SHidetoshi Shimokawa fw_bindremove(sc->fd.fc, &sc->fwb);
20260892f4c5SHidetoshi Shimokawa fw_xferlist_remove(&sc->fwb.xferlist);
2027e9e688e2SHidetoshi Shimokawa
20289950b741SHidetoshi Shimokawa mtx_destroy(&sc->mtx);
20299950b741SHidetoshi Shimokawa
2030e9e688e2SHidetoshi Shimokawa return 0;
2031e9e688e2SHidetoshi Shimokawa }
2032e9e688e2SHidetoshi Shimokawa
2033e9e688e2SHidetoshi Shimokawa static device_method_t sbp_targ_methods[] = {
2034e9e688e2SHidetoshi Shimokawa /* device interface */
2035e9e688e2SHidetoshi Shimokawa DEVMETHOD(device_identify, sbp_targ_identify),
2036e9e688e2SHidetoshi Shimokawa DEVMETHOD(device_probe, sbp_targ_probe),
2037e9e688e2SHidetoshi Shimokawa DEVMETHOD(device_attach, sbp_targ_attach),
2038e9e688e2SHidetoshi Shimokawa DEVMETHOD(device_detach, sbp_targ_detach),
2039e9e688e2SHidetoshi Shimokawa { 0, 0 }
2040e9e688e2SHidetoshi Shimokawa };
2041e9e688e2SHidetoshi Shimokawa
2042e9e688e2SHidetoshi Shimokawa static driver_t sbp_targ_driver = {
2043e9e688e2SHidetoshi Shimokawa "sbp_targ",
2044e9e688e2SHidetoshi Shimokawa sbp_targ_methods,
2045e9e688e2SHidetoshi Shimokawa sizeof(struct sbp_targ_softc),
2046e9e688e2SHidetoshi Shimokawa };
2047e9e688e2SHidetoshi Shimokawa
20488984411bSJohn Baldwin DRIVER_MODULE(sbp_targ, firewire, sbp_targ_driver, 0, 0);
2049e9e688e2SHidetoshi Shimokawa MODULE_VERSION(sbp_targ, 1);
2050e9e688e2SHidetoshi Shimokawa MODULE_DEPEND(sbp_targ, firewire, 1, 1, 1);
2051e9e688e2SHidetoshi Shimokawa MODULE_DEPEND(sbp_targ, cam, 1, 1, 1);
2052