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