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