1098ca2bdSWarner Losh /*- 2e9e688e2SHidetoshi Shimokawa * Copyright (C) 2003 3e9e688e2SHidetoshi Shimokawa * Hidetoshi Shimokawa. All rights reserved. 4e9e688e2SHidetoshi Shimokawa * 5e9e688e2SHidetoshi Shimokawa * Redistribution and use in source and binary forms, with or without 6e9e688e2SHidetoshi Shimokawa * modification, are permitted provided that the following conditions 7e9e688e2SHidetoshi Shimokawa * are met: 8e9e688e2SHidetoshi Shimokawa * 1. Redistributions of source code must retain the above copyright 9e9e688e2SHidetoshi Shimokawa * notice, this list of conditions and the following disclaimer. 10e9e688e2SHidetoshi Shimokawa * 2. Redistributions in binary form must reproduce the above copyright 11e9e688e2SHidetoshi Shimokawa * notice, this list of conditions and the following disclaimer in the 12e9e688e2SHidetoshi Shimokawa * documentation and/or other materials provided with the distribution. 13e9e688e2SHidetoshi Shimokawa * 3. All advertising materials mentioning features or use of this software 14e9e688e2SHidetoshi Shimokawa * must display the following acknowledgement: 15e9e688e2SHidetoshi Shimokawa * 16e9e688e2SHidetoshi Shimokawa * This product includes software developed by Hidetoshi Shimokawa. 17e9e688e2SHidetoshi Shimokawa * 18e9e688e2SHidetoshi Shimokawa * 4. Neither the name of the author nor the names of its contributors 19e9e688e2SHidetoshi Shimokawa * may be used to endorse or promote products derived from this software 20e9e688e2SHidetoshi Shimokawa * without specific prior written permission. 21e9e688e2SHidetoshi Shimokawa * 22e9e688e2SHidetoshi Shimokawa * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23e9e688e2SHidetoshi Shimokawa * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24e9e688e2SHidetoshi Shimokawa * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25e9e688e2SHidetoshi Shimokawa * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26e9e688e2SHidetoshi Shimokawa * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27e9e688e2SHidetoshi Shimokawa * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28e9e688e2SHidetoshi Shimokawa * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29e9e688e2SHidetoshi Shimokawa * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30e9e688e2SHidetoshi Shimokawa * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31e9e688e2SHidetoshi Shimokawa * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32e9e688e2SHidetoshi Shimokawa * SUCH DAMAGE. 33e9e688e2SHidetoshi Shimokawa * 34e9e688e2SHidetoshi Shimokawa * $FreeBSD$ 35e9e688e2SHidetoshi Shimokawa */ 36e9e688e2SHidetoshi Shimokawa 37e9e688e2SHidetoshi Shimokawa #include <sys/param.h> 38e9e688e2SHidetoshi Shimokawa #include <sys/kernel.h> 39e9e688e2SHidetoshi Shimokawa #include <sys/systm.h> 40e9e688e2SHidetoshi Shimokawa #include <sys/sysctl.h> 41e9e688e2SHidetoshi Shimokawa #include <sys/types.h> 42e9e688e2SHidetoshi Shimokawa #include <sys/conf.h> 43e9e688e2SHidetoshi Shimokawa #include <sys/malloc.h> 44*1cc052e8SKenneth D. Merry #include <sys/endian.h> 45e9e688e2SHidetoshi Shimokawa #if __FreeBSD_version < 500000 46e9e688e2SHidetoshi Shimokawa #include <sys/devicestat.h> 47e9e688e2SHidetoshi Shimokawa #endif 48e9e688e2SHidetoshi Shimokawa 49e9e688e2SHidetoshi Shimokawa #include <sys/bus.h> 50e9e688e2SHidetoshi Shimokawa #include <machine/bus.h> 51e9e688e2SHidetoshi Shimokawa 52e9e688e2SHidetoshi Shimokawa #include <dev/firewire/firewire.h> 53e9e688e2SHidetoshi Shimokawa #include <dev/firewire/firewirereg.h> 54e9e688e2SHidetoshi Shimokawa #include <dev/firewire/iec13213.h> 55e9e688e2SHidetoshi Shimokawa #include <dev/firewire/sbp.h> 56e9e688e2SHidetoshi Shimokawa #include <dev/firewire/fwmem.h> 57e9e688e2SHidetoshi Shimokawa 58e9e688e2SHidetoshi Shimokawa #include <cam/cam.h> 59e9e688e2SHidetoshi Shimokawa #include <cam/cam_ccb.h> 60e9e688e2SHidetoshi Shimokawa #include <cam/cam_sim.h> 61e9e688e2SHidetoshi Shimokawa #include <cam/cam_xpt_sim.h> 62e9e688e2SHidetoshi Shimokawa #include <cam/cam_debug.h> 63e9e688e2SHidetoshi Shimokawa #include <cam/cam_periph.h> 64e9e688e2SHidetoshi Shimokawa #include <cam/scsi/scsi_all.h> 65e9e688e2SHidetoshi Shimokawa 66a73ff510SHidetoshi Shimokawa #define SBP_TARG_RECV_LEN 8 67a73ff510SHidetoshi Shimokawa #define MAX_INITIATORS 8 68e9e688e2SHidetoshi Shimokawa #define MAX_LUN 63 69a73ff510SHidetoshi Shimokawa #define MAX_LOGINS 63 70a73ff510SHidetoshi Shimokawa #define MAX_NODES 63 71e9e688e2SHidetoshi Shimokawa /* 72e9e688e2SHidetoshi Shimokawa * management/command block agent registers 73e9e688e2SHidetoshi Shimokawa * 74e9e688e2SHidetoshi Shimokawa * BASE 0xffff f001 0000 management port 75a73ff510SHidetoshi Shimokawa * BASE 0xffff f001 0020 command port for login id 0 76a73ff510SHidetoshi Shimokawa * BASE 0xffff f001 0040 command port for login id 1 77e9e688e2SHidetoshi Shimokawa * 78e9e688e2SHidetoshi Shimokawa */ 79e9e688e2SHidetoshi Shimokawa #define SBP_TARG_MGM 0x10000 /* offset from 0xffff f000 000 */ 80e9e688e2SHidetoshi Shimokawa #define SBP_TARG_BIND_HI 0xffff 81e9e688e2SHidetoshi Shimokawa #define SBP_TARG_BIND_LO(l) (0xf0000000 + SBP_TARG_MGM + 0x20 * ((l) + 1)) 82e9e688e2SHidetoshi Shimokawa #define SBP_TARG_BIND_START (((u_int64_t)SBP_TARG_BIND_HI << 32) | \ 83e9e688e2SHidetoshi Shimokawa SBP_TARG_BIND_LO(-1)) 84e9e688e2SHidetoshi Shimokawa #define SBP_TARG_BIND_END (((u_int64_t)SBP_TARG_BIND_HI << 32) | \ 85a73ff510SHidetoshi Shimokawa SBP_TARG_BIND_LO(MAX_LOGINS)) 86a73ff510SHidetoshi Shimokawa #define SBP_TARG_LOGIN_ID(lo) (((lo) - SBP_TARG_BIND_LO(0))/0x20) 87e9e688e2SHidetoshi Shimokawa 88e9e688e2SHidetoshi Shimokawa #define FETCH_MGM 0 89e9e688e2SHidetoshi Shimokawa #define FETCH_CMD 1 90e9e688e2SHidetoshi Shimokawa #define FETCH_POINTER 2 91e9e688e2SHidetoshi Shimokawa 92a73ff510SHidetoshi Shimokawa #define F_LINK_ACTIVE (1 << 0) 93a73ff510SHidetoshi Shimokawa #define F_ATIO_STARVED (1 << 1) 94a73ff510SHidetoshi Shimokawa #define F_LOGIN (1 << 2) 95a73ff510SHidetoshi Shimokawa #define F_HOLD (1 << 3) 96a73ff510SHidetoshi Shimokawa #define F_FREEZED (1 << 4) 97a73ff510SHidetoshi Shimokawa 98e9e688e2SHidetoshi Shimokawa MALLOC_DEFINE(M_SBP_TARG, "sbp_targ", "SBP-II/FireWire target mode"); 99e9e688e2SHidetoshi Shimokawa 100e9e688e2SHidetoshi Shimokawa static int debug = 0; 101e9e688e2SHidetoshi Shimokawa 102e9e688e2SHidetoshi Shimokawa SYSCTL_INT(_debug, OID_AUTO, sbp_targ_debug, CTLFLAG_RW, &debug, 0, 103e9e688e2SHidetoshi Shimokawa "SBP target mode debug flag"); 104e9e688e2SHidetoshi Shimokawa 105a73ff510SHidetoshi Shimokawa struct sbp_targ_login { 106a73ff510SHidetoshi Shimokawa struct sbp_targ_lstate *lstate; 107a73ff510SHidetoshi Shimokawa struct fw_device *fwdev; 108a73ff510SHidetoshi Shimokawa struct sbp_login_res loginres; 10903161bbcSDoug Rabson uint16_t fifo_hi; 11003161bbcSDoug Rabson uint16_t last_hi; 11103161bbcSDoug Rabson uint32_t fifo_lo; 11203161bbcSDoug Rabson uint32_t last_lo; 113a73ff510SHidetoshi Shimokawa STAILQ_HEAD(, orb_info) orbs; 114a73ff510SHidetoshi Shimokawa STAILQ_ENTRY(sbp_targ_login) link; 11503161bbcSDoug Rabson uint16_t hold_sec; 11603161bbcSDoug Rabson uint16_t id; 11703161bbcSDoug Rabson uint8_t flags; 11803161bbcSDoug Rabson uint8_t spd; 119a73ff510SHidetoshi Shimokawa struct callout hold_callout; 120a73ff510SHidetoshi Shimokawa }; 121a73ff510SHidetoshi Shimokawa 122a73ff510SHidetoshi Shimokawa struct sbp_targ_lstate { 12303161bbcSDoug Rabson uint16_t lun; 124a73ff510SHidetoshi Shimokawa struct sbp_targ_softc *sc; 125a73ff510SHidetoshi Shimokawa struct cam_path *path; 126a73ff510SHidetoshi Shimokawa struct ccb_hdr_slist accept_tios; 127a73ff510SHidetoshi Shimokawa struct ccb_hdr_slist immed_notifies; 128a73ff510SHidetoshi Shimokawa struct crom_chunk model; 12903161bbcSDoug Rabson uint32_t flags; 130a73ff510SHidetoshi Shimokawa STAILQ_HEAD(, sbp_targ_login) logins; 131a73ff510SHidetoshi Shimokawa }; 132a73ff510SHidetoshi Shimokawa 133e9e688e2SHidetoshi Shimokawa struct sbp_targ_softc { 134e9e688e2SHidetoshi Shimokawa struct firewire_dev_comm fd; 135e9e688e2SHidetoshi Shimokawa struct cam_sim *sim; 136e9e688e2SHidetoshi Shimokawa struct cam_path *path; 137e9e688e2SHidetoshi Shimokawa struct fw_bind fwb; 138e9e688e2SHidetoshi Shimokawa int ndevs; 139a73ff510SHidetoshi Shimokawa int flags; 140e9e688e2SHidetoshi Shimokawa struct crom_chunk unit; 141e9e688e2SHidetoshi Shimokawa struct sbp_targ_lstate *lstate[MAX_LUN]; 142e9e688e2SHidetoshi Shimokawa struct sbp_targ_lstate *black_hole; 143a73ff510SHidetoshi Shimokawa struct sbp_targ_login *logins[MAX_LOGINS]; 1449950b741SHidetoshi Shimokawa struct mtx mtx; 145e9e688e2SHidetoshi Shimokawa }; 1469950b741SHidetoshi Shimokawa #define SBP_LOCK(sc) mtx_lock(&(sc)->mtx) 1479950b741SHidetoshi Shimokawa #define SBP_UNLOCK(sc) mtx_unlock(&(sc)->mtx) 148e9e688e2SHidetoshi Shimokawa 149e9e688e2SHidetoshi Shimokawa struct corb4 { 150e9e688e2SHidetoshi Shimokawa #if BYTE_ORDER == BIG_ENDIAN 15103161bbcSDoug Rabson uint32_t n:1, 152e9e688e2SHidetoshi Shimokawa rq_fmt:2, 153e9e688e2SHidetoshi Shimokawa :1, 154e9e688e2SHidetoshi Shimokawa dir:1, 155e9e688e2SHidetoshi Shimokawa spd:3, 156e9e688e2SHidetoshi Shimokawa max_payload:4, 157e9e688e2SHidetoshi Shimokawa page_table_present:1, 158e9e688e2SHidetoshi Shimokawa page_size:3, 159e9e688e2SHidetoshi Shimokawa data_size:16; 160e9e688e2SHidetoshi Shimokawa #else 16103161bbcSDoug Rabson uint32_t data_size:16, 162e9e688e2SHidetoshi Shimokawa page_size:3, 163e9e688e2SHidetoshi Shimokawa page_table_present:1, 164e9e688e2SHidetoshi Shimokawa max_payload:4, 165e9e688e2SHidetoshi Shimokawa spd:3, 166e9e688e2SHidetoshi Shimokawa dir:1, 167e9e688e2SHidetoshi Shimokawa :1, 168e9e688e2SHidetoshi Shimokawa rq_fmt:2, 169e9e688e2SHidetoshi Shimokawa n:1; 170e9e688e2SHidetoshi Shimokawa #endif 171e9e688e2SHidetoshi Shimokawa }; 172e9e688e2SHidetoshi Shimokawa 173e9e688e2SHidetoshi Shimokawa struct morb4 { 174e9e688e2SHidetoshi Shimokawa #if BYTE_ORDER == BIG_ENDIAN 17503161bbcSDoug Rabson uint32_t n:1, 176e9e688e2SHidetoshi Shimokawa rq_fmt:2, 177e9e688e2SHidetoshi Shimokawa :9, 178e9e688e2SHidetoshi Shimokawa fun:4, 179e9e688e2SHidetoshi Shimokawa id:16; 180e9e688e2SHidetoshi Shimokawa #else 18103161bbcSDoug Rabson uint32_t id:16, 182e9e688e2SHidetoshi Shimokawa fun:4, 183e9e688e2SHidetoshi Shimokawa :9, 184e9e688e2SHidetoshi Shimokawa rq_fmt:2, 185e9e688e2SHidetoshi Shimokawa n:1; 186e9e688e2SHidetoshi Shimokawa #endif 187e9e688e2SHidetoshi Shimokawa }; 188e9e688e2SHidetoshi Shimokawa 189e9e688e2SHidetoshi Shimokawa struct orb_info { 190e9e688e2SHidetoshi Shimokawa struct sbp_targ_softc *sc; 191e9e688e2SHidetoshi Shimokawa struct fw_device *fwdev; 192a73ff510SHidetoshi Shimokawa struct sbp_targ_login *login; 193e9e688e2SHidetoshi Shimokawa union ccb *ccb; 194e9e688e2SHidetoshi Shimokawa struct ccb_accept_tio *atio; 19503161bbcSDoug Rabson uint8_t state; 196e9e688e2SHidetoshi Shimokawa #define ORBI_STATUS_NONE 0 197e9e688e2SHidetoshi Shimokawa #define ORBI_STATUS_FETCH 1 198e9e688e2SHidetoshi Shimokawa #define ORBI_STATUS_ATIO 2 199e9e688e2SHidetoshi Shimokawa #define ORBI_STATUS_CTIO 3 200e9e688e2SHidetoshi Shimokawa #define ORBI_STATUS_STATUS 4 201e9e688e2SHidetoshi Shimokawa #define ORBI_STATUS_POINTER 5 202e9e688e2SHidetoshi Shimokawa #define ORBI_STATUS_ABORTED 7 20303161bbcSDoug Rabson uint8_t refcount; 20403161bbcSDoug Rabson uint16_t orb_hi; 20503161bbcSDoug Rabson uint32_t orb_lo; 20603161bbcSDoug Rabson uint32_t data_hi; 20703161bbcSDoug Rabson uint32_t data_lo; 208e9e688e2SHidetoshi Shimokawa struct corb4 orb4; 209e9e688e2SHidetoshi Shimokawa STAILQ_ENTRY(orb_info) link; 21003161bbcSDoug Rabson uint32_t orb[8]; 21103161bbcSDoug Rabson uint32_t *page_table; 212e9e688e2SHidetoshi Shimokawa struct sbp_status status; 213e9e688e2SHidetoshi Shimokawa }; 214e9e688e2SHidetoshi Shimokawa 215e9e688e2SHidetoshi Shimokawa static char *orb_fun_name[] = { 216e9e688e2SHidetoshi Shimokawa ORB_FUN_NAMES 217e9e688e2SHidetoshi Shimokawa }; 218e9e688e2SHidetoshi Shimokawa 219e9e688e2SHidetoshi Shimokawa static void sbp_targ_recv(struct fw_xfer *); 220e9e688e2SHidetoshi Shimokawa static void sbp_targ_fetch_orb(struct sbp_targ_softc *, struct fw_device *, 22103161bbcSDoug Rabson uint16_t, uint32_t, struct sbp_targ_login *, int); 2229950b741SHidetoshi Shimokawa static void sbp_targ_abort(struct sbp_targ_softc *, struct orb_info *); 223e9e688e2SHidetoshi Shimokawa 224e9e688e2SHidetoshi Shimokawa static void 225e9e688e2SHidetoshi Shimokawa sbp_targ_identify(driver_t *driver, device_t parent) 226e9e688e2SHidetoshi Shimokawa { 227e9e688e2SHidetoshi Shimokawa BUS_ADD_CHILD(parent, 0, "sbp_targ", device_get_unit(parent)); 228e9e688e2SHidetoshi Shimokawa } 229e9e688e2SHidetoshi Shimokawa 230e9e688e2SHidetoshi Shimokawa static int 231e9e688e2SHidetoshi Shimokawa sbp_targ_probe(device_t dev) 232e9e688e2SHidetoshi Shimokawa { 233e9e688e2SHidetoshi Shimokawa device_t pa; 234e9e688e2SHidetoshi Shimokawa 235e9e688e2SHidetoshi Shimokawa pa = device_get_parent(dev); 236e9e688e2SHidetoshi Shimokawa if(device_get_unit(dev) != device_get_unit(pa)){ 237e9e688e2SHidetoshi Shimokawa return(ENXIO); 238e9e688e2SHidetoshi Shimokawa } 239e9e688e2SHidetoshi Shimokawa 240e9e688e2SHidetoshi Shimokawa device_set_desc(dev, "SBP-2/SCSI over FireWire target mode"); 241e9e688e2SHidetoshi Shimokawa return (0); 242e9e688e2SHidetoshi Shimokawa } 243e9e688e2SHidetoshi Shimokawa 244a73ff510SHidetoshi Shimokawa static void 245a73ff510SHidetoshi Shimokawa sbp_targ_dealloc_login(struct sbp_targ_login *login) 246a73ff510SHidetoshi Shimokawa { 247a73ff510SHidetoshi Shimokawa struct orb_info *orbi, *next; 248a73ff510SHidetoshi Shimokawa 249a73ff510SHidetoshi Shimokawa if (login == NULL) { 25010d3ed64SHidetoshi Shimokawa printf("%s: login = NULL\n", __func__); 251a73ff510SHidetoshi Shimokawa return; 252a73ff510SHidetoshi Shimokawa } 253a73ff510SHidetoshi Shimokawa for (orbi = STAILQ_FIRST(&login->orbs); orbi != NULL; orbi = next) { 254a73ff510SHidetoshi Shimokawa next = STAILQ_NEXT(orbi, link); 255a73ff510SHidetoshi Shimokawa free(orbi, M_SBP_TARG); 256a73ff510SHidetoshi Shimokawa } 257a73ff510SHidetoshi Shimokawa callout_stop(&login->hold_callout); 258a73ff510SHidetoshi Shimokawa 259a73ff510SHidetoshi Shimokawa STAILQ_REMOVE(&login->lstate->logins, login, sbp_targ_login, link); 260a73ff510SHidetoshi Shimokawa login->lstate->sc->logins[login->id] = NULL; 261a73ff510SHidetoshi Shimokawa free((void *)login, M_SBP_TARG); 262a73ff510SHidetoshi Shimokawa } 263a73ff510SHidetoshi Shimokawa 264a73ff510SHidetoshi Shimokawa static void 265a73ff510SHidetoshi Shimokawa sbp_targ_hold_expire(void *arg) 266a73ff510SHidetoshi Shimokawa { 267a73ff510SHidetoshi Shimokawa struct sbp_targ_login *login; 268a73ff510SHidetoshi Shimokawa 269a73ff510SHidetoshi Shimokawa login = (struct sbp_targ_login *)arg; 270a73ff510SHidetoshi Shimokawa 271a73ff510SHidetoshi Shimokawa if (login->flags & F_HOLD) { 27210d3ed64SHidetoshi Shimokawa printf("%s: login_id=%d expired\n", __func__, login->id); 273a73ff510SHidetoshi Shimokawa sbp_targ_dealloc_login(login); 274a73ff510SHidetoshi Shimokawa } else { 27510d3ed64SHidetoshi Shimokawa printf("%s: login_id=%d not hold\n", __func__, login->id); 276a73ff510SHidetoshi Shimokawa } 277a73ff510SHidetoshi Shimokawa } 278a73ff510SHidetoshi Shimokawa 279e9e688e2SHidetoshi Shimokawa static void 280e9e688e2SHidetoshi Shimokawa sbp_targ_post_busreset(void *arg) 281e9e688e2SHidetoshi Shimokawa { 282e9e688e2SHidetoshi Shimokawa struct sbp_targ_softc *sc; 283e9e688e2SHidetoshi Shimokawa struct crom_src *src; 284e9e688e2SHidetoshi Shimokawa struct crom_chunk *root; 285e9e688e2SHidetoshi Shimokawa struct crom_chunk *unit; 286e9e688e2SHidetoshi Shimokawa struct sbp_targ_lstate *lstate; 287a73ff510SHidetoshi Shimokawa struct sbp_targ_login *login; 288e9e688e2SHidetoshi Shimokawa int i; 289e9e688e2SHidetoshi Shimokawa 290e9e688e2SHidetoshi Shimokawa sc = (struct sbp_targ_softc *)arg; 291e9e688e2SHidetoshi Shimokawa src = sc->fd.fc->crom_src; 292e9e688e2SHidetoshi Shimokawa root = sc->fd.fc->crom_root; 293e9e688e2SHidetoshi Shimokawa 294e9e688e2SHidetoshi Shimokawa unit = &sc->unit; 295e9e688e2SHidetoshi Shimokawa 296a73ff510SHidetoshi Shimokawa if ((sc->flags & F_FREEZED) == 0) { 2979950b741SHidetoshi Shimokawa SBP_LOCK(sc); 298a73ff510SHidetoshi Shimokawa sc->flags |= F_FREEZED; 299a73ff510SHidetoshi Shimokawa xpt_freeze_simq(sc->sim, /*count*/1); 3009950b741SHidetoshi Shimokawa SBP_UNLOCK(sc); 301a73ff510SHidetoshi Shimokawa } else { 30210d3ed64SHidetoshi Shimokawa printf("%s: already freezed\n", __func__); 303a73ff510SHidetoshi Shimokawa } 304a73ff510SHidetoshi Shimokawa 305e9e688e2SHidetoshi Shimokawa bzero(unit, sizeof(struct crom_chunk)); 306e9e688e2SHidetoshi Shimokawa 307e9e688e2SHidetoshi Shimokawa crom_add_chunk(src, root, unit, CROM_UDIR); 308e9e688e2SHidetoshi Shimokawa crom_add_entry(unit, CSRKEY_SPEC, CSRVAL_ANSIT10); 309e9e688e2SHidetoshi Shimokawa crom_add_entry(unit, CSRKEY_VER, CSRVAL_T10SBP2); 310e9e688e2SHidetoshi Shimokawa crom_add_entry(unit, CSRKEY_COM_SPEC, CSRVAL_ANSIT10); 311e9e688e2SHidetoshi Shimokawa crom_add_entry(unit, CSRKEY_COM_SET, CSRVAL_SCSI); 312e9e688e2SHidetoshi Shimokawa 313e9e688e2SHidetoshi Shimokawa crom_add_entry(unit, CROM_MGM, SBP_TARG_MGM >> 2); 314e9e688e2SHidetoshi Shimokawa crom_add_entry(unit, CSRKEY_UNIT_CH, (10<<8) | 8); 315e9e688e2SHidetoshi Shimokawa 316e9e688e2SHidetoshi Shimokawa for (i = 0; i < MAX_LUN; i ++) { 317e9e688e2SHidetoshi Shimokawa lstate = sc->lstate[i]; 318e9e688e2SHidetoshi Shimokawa if (lstate == NULL) 319e9e688e2SHidetoshi Shimokawa continue; 320e9e688e2SHidetoshi Shimokawa crom_add_entry(unit, CSRKEY_FIRM_VER, 1); 321e9e688e2SHidetoshi Shimokawa crom_add_entry(unit, CROM_LUN, i); 322e9e688e2SHidetoshi Shimokawa crom_add_entry(unit, CSRKEY_MODEL, 1); 323e9e688e2SHidetoshi Shimokawa crom_add_simple_text(src, unit, &lstate->model, "TargetMode"); 324e9e688e2SHidetoshi Shimokawa } 325a73ff510SHidetoshi Shimokawa 326a73ff510SHidetoshi Shimokawa /* Process for reconnection hold time */ 327a73ff510SHidetoshi Shimokawa for (i = 0; i < MAX_LOGINS; i ++) { 328a73ff510SHidetoshi Shimokawa login = sc->logins[i]; 329a73ff510SHidetoshi Shimokawa if (login == NULL) 330a73ff510SHidetoshi Shimokawa continue; 3319950b741SHidetoshi Shimokawa sbp_targ_abort(sc, STAILQ_FIRST(&login->orbs)); 332a73ff510SHidetoshi Shimokawa if (login->flags & F_LOGIN) { 333a73ff510SHidetoshi Shimokawa login->flags |= F_HOLD; 334a73ff510SHidetoshi Shimokawa callout_reset(&login->hold_callout, 335a73ff510SHidetoshi Shimokawa hz * login->hold_sec, 336a73ff510SHidetoshi Shimokawa sbp_targ_hold_expire, (void *)login); 337a73ff510SHidetoshi Shimokawa } 338a73ff510SHidetoshi Shimokawa } 339a73ff510SHidetoshi Shimokawa } 340a73ff510SHidetoshi Shimokawa 341a73ff510SHidetoshi Shimokawa static void 342a73ff510SHidetoshi Shimokawa sbp_targ_post_explore(void *arg) 343a73ff510SHidetoshi Shimokawa { 344a73ff510SHidetoshi Shimokawa struct sbp_targ_softc *sc; 345a73ff510SHidetoshi Shimokawa 346a73ff510SHidetoshi Shimokawa sc = (struct sbp_targ_softc *)arg; 3479950b741SHidetoshi Shimokawa SBP_LOCK(sc); 348a73ff510SHidetoshi Shimokawa sc->flags &= ~F_FREEZED; 349a73ff510SHidetoshi Shimokawa xpt_release_simq(sc->sim, /*run queue*/TRUE); 3509950b741SHidetoshi Shimokawa SBP_UNLOCK(sc); 351a73ff510SHidetoshi Shimokawa return; 352e9e688e2SHidetoshi Shimokawa } 353e9e688e2SHidetoshi Shimokawa 354e9e688e2SHidetoshi Shimokawa static cam_status 355e9e688e2SHidetoshi Shimokawa sbp_targ_find_devs(struct sbp_targ_softc *sc, union ccb *ccb, 356e9e688e2SHidetoshi Shimokawa struct sbp_targ_lstate **lstate, int notfound_failure) 357e9e688e2SHidetoshi Shimokawa { 358e9e688e2SHidetoshi Shimokawa u_int lun; 359e9e688e2SHidetoshi Shimokawa 360e9e688e2SHidetoshi Shimokawa /* XXX 0 is the only vaild target_id */ 361e9e688e2SHidetoshi Shimokawa if (ccb->ccb_h.target_id == CAM_TARGET_WILDCARD && 362e9e688e2SHidetoshi Shimokawa ccb->ccb_h.target_lun == CAM_LUN_WILDCARD) { 363e9e688e2SHidetoshi Shimokawa *lstate = sc->black_hole; 364e9e688e2SHidetoshi Shimokawa return (CAM_REQ_CMP); 365e9e688e2SHidetoshi Shimokawa } 366e9e688e2SHidetoshi Shimokawa 367e9e688e2SHidetoshi Shimokawa if (ccb->ccb_h.target_id != 0) 368e9e688e2SHidetoshi Shimokawa return (CAM_TID_INVALID); 369e9e688e2SHidetoshi Shimokawa 370e9e688e2SHidetoshi Shimokawa lun = ccb->ccb_h.target_lun; 371e9e688e2SHidetoshi Shimokawa if (lun >= MAX_LUN) 372e9e688e2SHidetoshi Shimokawa return (CAM_LUN_INVALID); 373e9e688e2SHidetoshi Shimokawa 374e9e688e2SHidetoshi Shimokawa *lstate = sc->lstate[lun]; 375e9e688e2SHidetoshi Shimokawa 376e9e688e2SHidetoshi Shimokawa if (notfound_failure != 0 && *lstate == NULL) 377e9e688e2SHidetoshi Shimokawa return (CAM_PATH_INVALID); 378e9e688e2SHidetoshi Shimokawa 379e9e688e2SHidetoshi Shimokawa return (CAM_REQ_CMP); 380e9e688e2SHidetoshi Shimokawa } 381e9e688e2SHidetoshi Shimokawa 382e9e688e2SHidetoshi Shimokawa static void 383e9e688e2SHidetoshi Shimokawa sbp_targ_en_lun(struct sbp_targ_softc *sc, union ccb *ccb) 384e9e688e2SHidetoshi Shimokawa { 385e9e688e2SHidetoshi Shimokawa struct ccb_en_lun *cel = &ccb->cel; 386e9e688e2SHidetoshi Shimokawa struct sbp_targ_lstate *lstate; 387e9e688e2SHidetoshi Shimokawa cam_status status; 388e9e688e2SHidetoshi Shimokawa 389e9e688e2SHidetoshi Shimokawa status = sbp_targ_find_devs(sc, ccb, &lstate, 0); 390e9e688e2SHidetoshi Shimokawa if (status != CAM_REQ_CMP) { 391e9e688e2SHidetoshi Shimokawa ccb->ccb_h.status = status; 392e9e688e2SHidetoshi Shimokawa return; 393e9e688e2SHidetoshi Shimokawa } 394e9e688e2SHidetoshi Shimokawa 395e9e688e2SHidetoshi Shimokawa if (cel->enable != 0) { 396e9e688e2SHidetoshi Shimokawa if (lstate != NULL) { 397e9e688e2SHidetoshi Shimokawa xpt_print_path(ccb->ccb_h.path); 398e9e688e2SHidetoshi Shimokawa printf("Lun already enabled\n"); 399e9e688e2SHidetoshi Shimokawa ccb->ccb_h.status = CAM_LUN_ALRDY_ENA; 400e9e688e2SHidetoshi Shimokawa return; 401e9e688e2SHidetoshi Shimokawa } 402e9e688e2SHidetoshi Shimokawa if (cel->grp6_len != 0 || cel->grp7_len != 0) { 403e9e688e2SHidetoshi Shimokawa ccb->ccb_h.status = CAM_REQ_INVALID; 404e9e688e2SHidetoshi Shimokawa printf("Non-zero Group Codes\n"); 405e9e688e2SHidetoshi Shimokawa return; 406e9e688e2SHidetoshi Shimokawa } 407e9e688e2SHidetoshi Shimokawa lstate = (struct sbp_targ_lstate *) 408e9e688e2SHidetoshi Shimokawa malloc(sizeof(*lstate), M_SBP_TARG, M_NOWAIT | M_ZERO); 409e9e688e2SHidetoshi Shimokawa if (lstate == NULL) { 410e9e688e2SHidetoshi Shimokawa xpt_print_path(ccb->ccb_h.path); 411e9e688e2SHidetoshi Shimokawa printf("Couldn't allocate lstate\n"); 412e9e688e2SHidetoshi Shimokawa ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 413e9e688e2SHidetoshi Shimokawa return; 414e9e688e2SHidetoshi Shimokawa } 415e9e688e2SHidetoshi Shimokawa if (ccb->ccb_h.target_id == CAM_TARGET_WILDCARD) 416e9e688e2SHidetoshi Shimokawa sc->black_hole = lstate; 417e9e688e2SHidetoshi Shimokawa else 418e9e688e2SHidetoshi Shimokawa sc->lstate[ccb->ccb_h.target_lun] = lstate; 419e9e688e2SHidetoshi Shimokawa memset(lstate, 0, sizeof(*lstate)); 420e9e688e2SHidetoshi Shimokawa lstate->sc = sc; 421e9e688e2SHidetoshi Shimokawa status = xpt_create_path(&lstate->path, /*periph*/NULL, 422e9e688e2SHidetoshi Shimokawa xpt_path_path_id(ccb->ccb_h.path), 423e9e688e2SHidetoshi Shimokawa xpt_path_target_id(ccb->ccb_h.path), 424e9e688e2SHidetoshi Shimokawa xpt_path_lun_id(ccb->ccb_h.path)); 425e9e688e2SHidetoshi Shimokawa if (status != CAM_REQ_CMP) { 426e9e688e2SHidetoshi Shimokawa free(lstate, M_SBP_TARG); 427e9e688e2SHidetoshi Shimokawa xpt_print_path(ccb->ccb_h.path); 428e9e688e2SHidetoshi Shimokawa printf("Couldn't allocate path\n"); 429e9e688e2SHidetoshi Shimokawa ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 430e9e688e2SHidetoshi Shimokawa return; 431e9e688e2SHidetoshi Shimokawa } 432e9e688e2SHidetoshi Shimokawa SLIST_INIT(&lstate->accept_tios); 433e9e688e2SHidetoshi Shimokawa SLIST_INIT(&lstate->immed_notifies); 434a73ff510SHidetoshi Shimokawa STAILQ_INIT(&lstate->logins); 435e9e688e2SHidetoshi Shimokawa 436e9e688e2SHidetoshi Shimokawa ccb->ccb_h.status = CAM_REQ_CMP; 437e9e688e2SHidetoshi Shimokawa xpt_print_path(ccb->ccb_h.path); 438e9e688e2SHidetoshi Shimokawa printf("Lun now enabled for target mode\n"); 439e9e688e2SHidetoshi Shimokawa /* bus reset */ 440e9e688e2SHidetoshi Shimokawa sc->fd.fc->ibr(sc->fd.fc); 441e9e688e2SHidetoshi Shimokawa } else { 442a73ff510SHidetoshi Shimokawa struct sbp_targ_login *login, *next; 443a73ff510SHidetoshi Shimokawa 444e9e688e2SHidetoshi Shimokawa if (lstate == NULL) { 445e9e688e2SHidetoshi Shimokawa ccb->ccb_h.status = CAM_LUN_INVALID; 446e9e688e2SHidetoshi Shimokawa return; 447e9e688e2SHidetoshi Shimokawa } 448e9e688e2SHidetoshi Shimokawa ccb->ccb_h.status = CAM_REQ_CMP; 449e9e688e2SHidetoshi Shimokawa 450e9e688e2SHidetoshi Shimokawa if (SLIST_FIRST(&lstate->accept_tios) != NULL) { 451e9e688e2SHidetoshi Shimokawa printf("ATIOs pending\n"); 452e9e688e2SHidetoshi Shimokawa ccb->ccb_h.status = CAM_REQ_INVALID; 453e9e688e2SHidetoshi Shimokawa } 454e9e688e2SHidetoshi Shimokawa 455e9e688e2SHidetoshi Shimokawa if (SLIST_FIRST(&lstate->immed_notifies) != NULL) { 456e9e688e2SHidetoshi Shimokawa printf("INOTs pending\n"); 457e9e688e2SHidetoshi Shimokawa ccb->ccb_h.status = CAM_REQ_INVALID; 458e9e688e2SHidetoshi Shimokawa } 459e9e688e2SHidetoshi Shimokawa 460e9e688e2SHidetoshi Shimokawa if (ccb->ccb_h.status != CAM_REQ_CMP) { 461e9e688e2SHidetoshi Shimokawa return; 462e9e688e2SHidetoshi Shimokawa } 463e9e688e2SHidetoshi Shimokawa 464e9e688e2SHidetoshi Shimokawa xpt_print_path(ccb->ccb_h.path); 465e9e688e2SHidetoshi Shimokawa printf("Target mode disabled\n"); 466e9e688e2SHidetoshi Shimokawa xpt_free_path(lstate->path); 467e9e688e2SHidetoshi Shimokawa 468a73ff510SHidetoshi Shimokawa for (login = STAILQ_FIRST(&lstate->logins); login != NULL; 469a73ff510SHidetoshi Shimokawa login = next) { 470a73ff510SHidetoshi Shimokawa next = STAILQ_NEXT(login, link); 471a73ff510SHidetoshi Shimokawa sbp_targ_dealloc_login(login); 472e9e688e2SHidetoshi Shimokawa } 473e9e688e2SHidetoshi Shimokawa 474e9e688e2SHidetoshi Shimokawa if (ccb->ccb_h.target_id == CAM_TARGET_WILDCARD) 475e9e688e2SHidetoshi Shimokawa sc->black_hole = NULL; 476e9e688e2SHidetoshi Shimokawa else 477e9e688e2SHidetoshi Shimokawa sc->lstate[ccb->ccb_h.target_lun] = NULL; 478e9e688e2SHidetoshi Shimokawa free(lstate, M_SBP_TARG); 479e9e688e2SHidetoshi Shimokawa 480e9e688e2SHidetoshi Shimokawa /* bus reset */ 481e9e688e2SHidetoshi Shimokawa sc->fd.fc->ibr(sc->fd.fc); 482e9e688e2SHidetoshi Shimokawa } 483e9e688e2SHidetoshi Shimokawa } 484e9e688e2SHidetoshi Shimokawa 485e9e688e2SHidetoshi Shimokawa static void 486e9e688e2SHidetoshi Shimokawa sbp_targ_send_lstate_events(struct sbp_targ_softc *sc, 487e9e688e2SHidetoshi Shimokawa struct sbp_targ_lstate *lstate) 488e9e688e2SHidetoshi Shimokawa { 489e9e688e2SHidetoshi Shimokawa #if 0 490e9e688e2SHidetoshi Shimokawa struct ccb_hdr *ccbh; 491e9e688e2SHidetoshi Shimokawa struct ccb_immed_notify *inot; 492e9e688e2SHidetoshi Shimokawa 49310d3ed64SHidetoshi Shimokawa printf("%s: not implemented yet\n", __func__); 494e9e688e2SHidetoshi Shimokawa #endif 495e9e688e2SHidetoshi Shimokawa } 496e9e688e2SHidetoshi Shimokawa 4979950b741SHidetoshi Shimokawa 4989950b741SHidetoshi Shimokawa static __inline void 4999950b741SHidetoshi Shimokawa sbp_targ_remove_orb_info_locked(struct sbp_targ_login *login, struct orb_info *orbi) 5009950b741SHidetoshi Shimokawa { 5019950b741SHidetoshi Shimokawa STAILQ_REMOVE(&login->orbs, orbi, orb_info, link); 5029950b741SHidetoshi Shimokawa } 5039950b741SHidetoshi Shimokawa 504e9e688e2SHidetoshi Shimokawa static __inline void 505a73ff510SHidetoshi Shimokawa sbp_targ_remove_orb_info(struct sbp_targ_login *login, struct orb_info *orbi) 506e9e688e2SHidetoshi Shimokawa { 5079950b741SHidetoshi Shimokawa SBP_LOCK(orbi->sc); 508a73ff510SHidetoshi Shimokawa STAILQ_REMOVE(&login->orbs, orbi, orb_info, link); 5099950b741SHidetoshi Shimokawa SBP_UNLOCK(orbi->sc); 510e9e688e2SHidetoshi Shimokawa } 511e9e688e2SHidetoshi Shimokawa 512e9e688e2SHidetoshi Shimokawa /* 513e9e688e2SHidetoshi Shimokawa * tag_id/init_id encoding 514e9e688e2SHidetoshi Shimokawa * 515e9e688e2SHidetoshi Shimokawa * tag_id and init_id has only 32bit for each. 516e9e688e2SHidetoshi Shimokawa * scsi_target can handle very limited number(up to 15) of init_id. 517e9e688e2SHidetoshi Shimokawa * we have to encode 48bit orb and 64bit EUI64 into these 518e9e688e2SHidetoshi Shimokawa * variables. 519e9e688e2SHidetoshi Shimokawa * 520e9e688e2SHidetoshi Shimokawa * tag_id represents lower 32bit of ORB address. 521a73ff510SHidetoshi Shimokawa * init_id represents login_id. 522e9e688e2SHidetoshi Shimokawa * 523e9e688e2SHidetoshi Shimokawa */ 524e9e688e2SHidetoshi Shimokawa 525e9e688e2SHidetoshi Shimokawa static struct orb_info * 526e9e688e2SHidetoshi Shimokawa sbp_targ_get_orb_info(struct sbp_targ_lstate *lstate, 527e9e688e2SHidetoshi Shimokawa u_int tag_id, u_int init_id) 528e9e688e2SHidetoshi Shimokawa { 529a73ff510SHidetoshi Shimokawa struct sbp_targ_login *login; 530e9e688e2SHidetoshi Shimokawa struct orb_info *orbi; 531e9e688e2SHidetoshi Shimokawa 532a73ff510SHidetoshi Shimokawa login = lstate->sc->logins[init_id]; 533a73ff510SHidetoshi Shimokawa if (login == NULL) { 53410d3ed64SHidetoshi Shimokawa printf("%s: no such login\n", __func__); 535a73ff510SHidetoshi Shimokawa return (NULL); 536a73ff510SHidetoshi Shimokawa } 537a73ff510SHidetoshi Shimokawa STAILQ_FOREACH(orbi, &login->orbs, link) 538a73ff510SHidetoshi Shimokawa if (orbi->orb_lo == tag_id) 539e9e688e2SHidetoshi Shimokawa goto found; 5409950b741SHidetoshi Shimokawa printf("%s: orb not found tag_id=0x%08x init_id=%d\n", 5419950b741SHidetoshi Shimokawa __func__, tag_id, init_id); 542e9e688e2SHidetoshi Shimokawa return (NULL); 543e9e688e2SHidetoshi Shimokawa found: 544e9e688e2SHidetoshi Shimokawa return (orbi); 545e9e688e2SHidetoshi Shimokawa } 546e9e688e2SHidetoshi Shimokawa 547e9e688e2SHidetoshi Shimokawa static void 5489950b741SHidetoshi Shimokawa sbp_targ_abort(struct sbp_targ_softc *sc, struct orb_info *orbi) 549e9e688e2SHidetoshi Shimokawa { 550e9e688e2SHidetoshi Shimokawa struct orb_info *norbi; 551e9e688e2SHidetoshi Shimokawa 5529950b741SHidetoshi Shimokawa SBP_LOCK(sc); 553e9e688e2SHidetoshi Shimokawa for (; orbi != NULL; orbi = norbi) { 5549950b741SHidetoshi Shimokawa printf("%s: status=%d ccb=%p\n", __func__, orbi->state, orbi->ccb); 555e9e688e2SHidetoshi Shimokawa norbi = STAILQ_NEXT(orbi, link); 556e9e688e2SHidetoshi Shimokawa if (orbi->state != ORBI_STATUS_ABORTED) { 557e9e688e2SHidetoshi Shimokawa if (orbi->ccb != NULL) { 558e9e688e2SHidetoshi Shimokawa orbi->ccb->ccb_h.status = CAM_REQ_ABORTED; 559e9e688e2SHidetoshi Shimokawa xpt_done(orbi->ccb); 560e9e688e2SHidetoshi Shimokawa orbi->ccb = NULL; 561e9e688e2SHidetoshi Shimokawa } 5629950b741SHidetoshi Shimokawa #if 0 563e9e688e2SHidetoshi Shimokawa if (orbi->state <= ORBI_STATUS_ATIO) { 5649950b741SHidetoshi Shimokawa sbp_targ_remove_orb_info_locked(orbi->login, orbi); 565e9e688e2SHidetoshi Shimokawa free(orbi, M_SBP_TARG); 566e9e688e2SHidetoshi Shimokawa } else 5679950b741SHidetoshi Shimokawa #endif 568e9e688e2SHidetoshi Shimokawa orbi->state = ORBI_STATUS_ABORTED; 569e9e688e2SHidetoshi Shimokawa } 570e9e688e2SHidetoshi Shimokawa } 5719950b741SHidetoshi Shimokawa SBP_UNLOCK(sc); 572e9e688e2SHidetoshi Shimokawa } 573e9e688e2SHidetoshi Shimokawa 574e9e688e2SHidetoshi Shimokawa static void 575e9e688e2SHidetoshi Shimokawa sbp_targ_free_orbi(struct fw_xfer *xfer) 576e9e688e2SHidetoshi Shimokawa { 577e9e688e2SHidetoshi Shimokawa struct orb_info *orbi; 578e9e688e2SHidetoshi Shimokawa 579e9e688e2SHidetoshi Shimokawa orbi = (struct orb_info *)xfer->sc; 580e9e688e2SHidetoshi Shimokawa if (xfer->resp != 0) { 581e9e688e2SHidetoshi Shimokawa /* XXX */ 58210d3ed64SHidetoshi Shimokawa printf("%s: xfer->resp = %d\n", __func__, xfer->resp); 583e9e688e2SHidetoshi Shimokawa } 584e9e688e2SHidetoshi Shimokawa free(orbi, M_SBP_TARG); 585e9e688e2SHidetoshi Shimokawa fw_xfer_free(xfer); 586e9e688e2SHidetoshi Shimokawa } 587e9e688e2SHidetoshi Shimokawa 588e9e688e2SHidetoshi Shimokawa static void 589e9e688e2SHidetoshi Shimokawa sbp_targ_status_FIFO(struct orb_info *orbi, 59003161bbcSDoug Rabson uint32_t fifo_hi, uint32_t fifo_lo, int dequeue) 591e9e688e2SHidetoshi Shimokawa { 592e9e688e2SHidetoshi Shimokawa struct fw_xfer *xfer; 593e9e688e2SHidetoshi Shimokawa 594e9e688e2SHidetoshi Shimokawa if (dequeue) 595a73ff510SHidetoshi Shimokawa sbp_targ_remove_orb_info(orbi->login, orbi); 596e9e688e2SHidetoshi Shimokawa 597e9e688e2SHidetoshi Shimokawa xfer = fwmem_write_block(orbi->fwdev, (void *)orbi, 598e9e688e2SHidetoshi Shimokawa /*spd*/2, fifo_hi, fifo_lo, 59903161bbcSDoug Rabson sizeof(uint32_t) * (orbi->status.len + 1), (char *)&orbi->status, 600e9e688e2SHidetoshi Shimokawa sbp_targ_free_orbi); 601e9e688e2SHidetoshi Shimokawa 602e9e688e2SHidetoshi Shimokawa if (xfer == NULL) { 603e9e688e2SHidetoshi Shimokawa /* XXX */ 60410d3ed64SHidetoshi Shimokawa printf("%s: xfer == NULL\n", __func__); 605e9e688e2SHidetoshi Shimokawa } 606e9e688e2SHidetoshi Shimokawa } 607e9e688e2SHidetoshi Shimokawa 608e9e688e2SHidetoshi Shimokawa static void 609e9e688e2SHidetoshi Shimokawa sbp_targ_send_status(struct orb_info *orbi, union ccb *ccb) 610e9e688e2SHidetoshi Shimokawa { 611e9e688e2SHidetoshi Shimokawa struct sbp_status *sbp_status; 612ea47b6c8SMatt Jacob #if 0 6139950b741SHidetoshi Shimokawa struct orb_info *norbi; 614ea47b6c8SMatt Jacob #endif 615e9e688e2SHidetoshi Shimokawa 616e9e688e2SHidetoshi Shimokawa sbp_status = &orbi->status; 617e9e688e2SHidetoshi Shimokawa 618e9e688e2SHidetoshi Shimokawa orbi->state = ORBI_STATUS_STATUS; 619e9e688e2SHidetoshi Shimokawa 620e9e688e2SHidetoshi Shimokawa sbp_status->resp = 0; /* XXX */ 621e9e688e2SHidetoshi Shimokawa sbp_status->status = 0; /* XXX */ 622e9e688e2SHidetoshi Shimokawa sbp_status->dead = 0; /* XXX */ 623e9e688e2SHidetoshi Shimokawa 624e9e688e2SHidetoshi Shimokawa switch (ccb->csio.scsi_status) { 625e9e688e2SHidetoshi Shimokawa case SCSI_STATUS_OK: 626e9e688e2SHidetoshi Shimokawa if (debug) 62710d3ed64SHidetoshi Shimokawa printf("%s: STATUS_OK\n", __func__); 628e9e688e2SHidetoshi Shimokawa sbp_status->len = 1; 629e9e688e2SHidetoshi Shimokawa break; 630e9e688e2SHidetoshi Shimokawa case SCSI_STATUS_CHECK_COND: 631e9e688e2SHidetoshi Shimokawa case SCSI_STATUS_BUSY: 632e9e688e2SHidetoshi Shimokawa case SCSI_STATUS_CMD_TERMINATED: 633e9e688e2SHidetoshi Shimokawa { 634e9e688e2SHidetoshi Shimokawa struct sbp_cmd_status *sbp_cmd_status; 635e9e688e2SHidetoshi Shimokawa struct scsi_sense_data *sense; 636*1cc052e8SKenneth D. Merry int error_code, sense_key, asc, ascq; 637*1cc052e8SKenneth D. Merry uint8_t stream_bits; 638*1cc052e8SKenneth D. Merry uint8_t sks[3]; 639*1cc052e8SKenneth D. Merry uint64_t info; 640*1cc052e8SKenneth D. Merry int64_t sinfo; 641*1cc052e8SKenneth D. Merry int sense_len; 642e9e688e2SHidetoshi Shimokawa 643e9e688e2SHidetoshi Shimokawa if (debug) 64410d3ed64SHidetoshi Shimokawa printf("%s: STATUS %d\n", __func__, 645e9e688e2SHidetoshi Shimokawa ccb->csio.scsi_status); 646e9e688e2SHidetoshi Shimokawa sbp_cmd_status = (struct sbp_cmd_status *)&sbp_status->data[0]; 647e9e688e2SHidetoshi Shimokawa sbp_cmd_status->status = ccb->csio.scsi_status; 648e9e688e2SHidetoshi Shimokawa sense = &ccb->csio.sense_data; 649e9e688e2SHidetoshi Shimokawa 6509950b741SHidetoshi Shimokawa #if 0 /* XXX What we should do? */ 6519950b741SHidetoshi Shimokawa #if 0 6529950b741SHidetoshi Shimokawa sbp_targ_abort(orbi->sc, STAILQ_NEXT(orbi, link)); 6539950b741SHidetoshi Shimokawa #else 6549950b741SHidetoshi Shimokawa norbi = STAILQ_NEXT(orbi, link); 6559950b741SHidetoshi Shimokawa while (norbi) { 6569950b741SHidetoshi Shimokawa printf("%s: status=%d\n", __func__, norbi->state); 6579950b741SHidetoshi Shimokawa if (norbi->ccb != NULL) { 6589950b741SHidetoshi Shimokawa norbi->ccb->ccb_h.status = CAM_REQ_ABORTED; 6599950b741SHidetoshi Shimokawa xpt_done(norbi->ccb); 6609950b741SHidetoshi Shimokawa norbi->ccb = NULL; 6619950b741SHidetoshi Shimokawa } 6629950b741SHidetoshi Shimokawa sbp_targ_remove_orb_info_locked(orbi->login, norbi); 6639950b741SHidetoshi Shimokawa norbi = STAILQ_NEXT(norbi, link); 6649950b741SHidetoshi Shimokawa free(norbi, M_SBP_TARG); 6659950b741SHidetoshi Shimokawa } 6669950b741SHidetoshi Shimokawa #endif 6679950b741SHidetoshi Shimokawa #endif 668e9e688e2SHidetoshi Shimokawa 669*1cc052e8SKenneth D. Merry sense_len = ccb->csio.sense_len - ccb->csio.sense_resid; 670*1cc052e8SKenneth D. Merry scsi_extract_sense_len(sense, sense_len, &error_code, 671*1cc052e8SKenneth D. Merry &sense_key, &asc, &ascq, /*show_errors*/ 0); 672*1cc052e8SKenneth D. Merry 673*1cc052e8SKenneth D. Merry switch (error_code) { 674*1cc052e8SKenneth D. Merry case SSD_CURRENT_ERROR: 675*1cc052e8SKenneth D. Merry case SSD_DESC_CURRENT_ERROR: 676e9e688e2SHidetoshi Shimokawa sbp_cmd_status->sfmt = SBP_SFMT_CURR; 677*1cc052e8SKenneth D. Merry break; 678*1cc052e8SKenneth D. Merry default: 679e9e688e2SHidetoshi Shimokawa sbp_cmd_status->sfmt = SBP_SFMT_DEFER; 680*1cc052e8SKenneth D. Merry break; 681*1cc052e8SKenneth D. Merry } 682e9e688e2SHidetoshi Shimokawa 683*1cc052e8SKenneth D. Merry if (scsi_get_sense_info(sense, sense_len, SSD_DESC_INFO, &info, 684*1cc052e8SKenneth D. Merry &sinfo) == 0) { 685*1cc052e8SKenneth D. Merry uint32_t info_trunc; 686*1cc052e8SKenneth D. Merry sbp_cmd_status->valid = 1; 687*1cc052e8SKenneth D. Merry info_trunc = info; 688e9e688e2SHidetoshi Shimokawa 689*1cc052e8SKenneth D. Merry sbp_cmd_status->info = htobe32(info_trunc); 690*1cc052e8SKenneth D. Merry } else { 691*1cc052e8SKenneth D. Merry sbp_cmd_status->valid = 0; 692*1cc052e8SKenneth D. Merry } 693e9e688e2SHidetoshi Shimokawa 694*1cc052e8SKenneth D. Merry sbp_cmd_status->s_key = sense_key; 695*1cc052e8SKenneth D. Merry 696*1cc052e8SKenneth D. Merry if (scsi_get_stream_info(sense, sense_len, NULL, 697*1cc052e8SKenneth D. Merry &stream_bits) == 0) { 698*1cc052e8SKenneth D. Merry sbp_cmd_status->mark = 699*1cc052e8SKenneth D. Merry (stream_bits & SSD_FILEMARK) ? 1 : 0; 700*1cc052e8SKenneth D. Merry sbp_cmd_status->eom = 701*1cc052e8SKenneth D. Merry (stream_bits & SSD_EOM) ? 1 : 0; 702*1cc052e8SKenneth D. Merry sbp_cmd_status->ill_len = 703*1cc052e8SKenneth D. Merry (stream_bits & SSD_ILI) ? 1 : 0; 704*1cc052e8SKenneth D. Merry } else { 705*1cc052e8SKenneth D. Merry sbp_cmd_status->mark = 0; 706*1cc052e8SKenneth D. Merry sbp_cmd_status->eom = 0; 707*1cc052e8SKenneth D. Merry sbp_cmd_status->ill_len = 0; 708*1cc052e8SKenneth D. Merry } 709*1cc052e8SKenneth D. Merry 710*1cc052e8SKenneth D. Merry 711e9e688e2SHidetoshi Shimokawa /* add_sense_code(_qual), info, cmd_spec_info */ 712e9e688e2SHidetoshi Shimokawa sbp_status->len = 4; 713*1cc052e8SKenneth D. Merry 714*1cc052e8SKenneth D. Merry if (scsi_get_sense_info(sense, sense_len, SSD_DESC_COMMAND, 715*1cc052e8SKenneth D. Merry &info, &sinfo) == 0) { 716*1cc052e8SKenneth D. Merry uint32_t cmdspec_trunc; 717*1cc052e8SKenneth D. Merry 718*1cc052e8SKenneth D. Merry cmdspec_trunc = info; 719*1cc052e8SKenneth D. Merry 720*1cc052e8SKenneth D. Merry sbp_cmd_status->cdb = htobe32(cmdspec_trunc); 721*1cc052e8SKenneth D. Merry } 722*1cc052e8SKenneth D. Merry 723*1cc052e8SKenneth D. Merry sbp_cmd_status->s_code = asc; 724*1cc052e8SKenneth D. Merry sbp_cmd_status->s_qlfr = ascq; 725*1cc052e8SKenneth D. Merry 726*1cc052e8SKenneth D. Merry if (scsi_get_sense_info(sense, sense_len, SSD_DESC_FRU, &info, 727*1cc052e8SKenneth D. Merry &sinfo) == 0) { 728*1cc052e8SKenneth D. Merry sbp_cmd_status->fru = (uint8_t)info; 729e9e688e2SHidetoshi Shimokawa sbp_status->len = 5; 730*1cc052e8SKenneth D. Merry } else { 731*1cc052e8SKenneth D. Merry sbp_cmd_status->fru = 0; 732*1cc052e8SKenneth D. Merry } 733e9e688e2SHidetoshi Shimokawa 734*1cc052e8SKenneth D. Merry if (scsi_get_sks(sense, sense_len, sks) == 0) { 735*1cc052e8SKenneth D. Merry bcopy(sks, &sbp_cmd_status->s_keydep[0], sizeof(sks)); 736*1cc052e8SKenneth D. Merry sbp_status->len = 5; 737*1cc052e8SKenneth D. Merry } 738e9e688e2SHidetoshi Shimokawa 739e9e688e2SHidetoshi Shimokawa break; 740e9e688e2SHidetoshi Shimokawa } 741e9e688e2SHidetoshi Shimokawa default: 74210d3ed64SHidetoshi Shimokawa printf("%s: unknown scsi status 0x%x\n", __func__, 743e9e688e2SHidetoshi Shimokawa sbp_status->status); 744e9e688e2SHidetoshi Shimokawa } 745e9e688e2SHidetoshi Shimokawa 746e9e688e2SHidetoshi Shimokawa if (orbi->page_table != NULL) 747e9e688e2SHidetoshi Shimokawa free(orbi->page_table, M_SBP_TARG); 7489950b741SHidetoshi Shimokawa 7499950b741SHidetoshi Shimokawa sbp_targ_status_FIFO(orbi, 7509950b741SHidetoshi Shimokawa orbi->login->fifo_hi, orbi->login->fifo_lo, /*dequeue*/1); 751e9e688e2SHidetoshi Shimokawa } 752e9e688e2SHidetoshi Shimokawa 753e9e688e2SHidetoshi Shimokawa static void 754e9e688e2SHidetoshi Shimokawa sbp_targ_cam_done(struct fw_xfer *xfer) 755e9e688e2SHidetoshi Shimokawa { 756e9e688e2SHidetoshi Shimokawa struct orb_info *orbi; 757e9e688e2SHidetoshi Shimokawa union ccb *ccb; 758e9e688e2SHidetoshi Shimokawa 759e9e688e2SHidetoshi Shimokawa orbi = (struct orb_info *)xfer->sc; 760e9e688e2SHidetoshi Shimokawa 761a73ff510SHidetoshi Shimokawa if (debug > 1) 76210d3ed64SHidetoshi Shimokawa printf("%s: resp=%d refcount=%d\n", __func__, 763e9e688e2SHidetoshi Shimokawa xfer->resp, orbi->refcount); 764e9e688e2SHidetoshi Shimokawa 765e9e688e2SHidetoshi Shimokawa if (xfer->resp != 0) { 76610d3ed64SHidetoshi Shimokawa printf("%s: xfer->resp = %d\n", __func__, xfer->resp); 767e9e688e2SHidetoshi Shimokawa orbi->status.resp = SBP_TRANS_FAIL; 7681398a889SHidetoshi Shimokawa orbi->status.status = OBJ_DATA | SBE_TIMEOUT/*XXX*/; 769e9e688e2SHidetoshi Shimokawa orbi->status.dead = 1; 7709950b741SHidetoshi Shimokawa sbp_targ_abort(orbi->sc, STAILQ_NEXT(orbi, link)); 771e9e688e2SHidetoshi Shimokawa } 772e9e688e2SHidetoshi Shimokawa 773e9e688e2SHidetoshi Shimokawa orbi->refcount --; 774e9e688e2SHidetoshi Shimokawa 775e9e688e2SHidetoshi Shimokawa ccb = orbi->ccb; 776e9e688e2SHidetoshi Shimokawa if (orbi->refcount == 0) { 7779950b741SHidetoshi Shimokawa orbi->ccb = NULL; 778e9e688e2SHidetoshi Shimokawa if (orbi->state == ORBI_STATUS_ABORTED) { 779e9e688e2SHidetoshi Shimokawa if (debug) 78010d3ed64SHidetoshi Shimokawa printf("%s: orbi aborted\n", __func__); 781a73ff510SHidetoshi Shimokawa sbp_targ_remove_orb_info(orbi->login, orbi); 782e9e688e2SHidetoshi Shimokawa if (orbi->page_table != NULL) 783e9e688e2SHidetoshi Shimokawa free(orbi->page_table, M_SBP_TARG); 784e9e688e2SHidetoshi Shimokawa free(orbi, M_SBP_TARG); 785e9e688e2SHidetoshi Shimokawa } else if (orbi->status.resp == 0) { 786e9e688e2SHidetoshi Shimokawa if ((ccb->ccb_h.flags & CAM_SEND_STATUS) != 0) 787e9e688e2SHidetoshi Shimokawa sbp_targ_send_status(orbi, ccb); 788e9e688e2SHidetoshi Shimokawa ccb->ccb_h.status = CAM_REQ_CMP; 7899950b741SHidetoshi Shimokawa SBP_LOCK(orbi->sc); 790e9e688e2SHidetoshi Shimokawa xpt_done(ccb); 7919950b741SHidetoshi Shimokawa SBP_UNLOCK(orbi->sc); 792e9e688e2SHidetoshi Shimokawa } else { 793e9e688e2SHidetoshi Shimokawa orbi->status.len = 1; 794e9e688e2SHidetoshi Shimokawa sbp_targ_status_FIFO(orbi, 795a73ff510SHidetoshi Shimokawa orbi->login->fifo_hi, orbi->login->fifo_lo, 796e9e688e2SHidetoshi Shimokawa /*dequeue*/1); 797e9e688e2SHidetoshi Shimokawa ccb->ccb_h.status = CAM_REQ_ABORTED; 7989950b741SHidetoshi Shimokawa SBP_LOCK(orbi->sc); 799e9e688e2SHidetoshi Shimokawa xpt_done(ccb); 8009950b741SHidetoshi Shimokawa SBP_UNLOCK(orbi->sc); 801e9e688e2SHidetoshi Shimokawa } 802e9e688e2SHidetoshi Shimokawa } 803e9e688e2SHidetoshi Shimokawa 804e9e688e2SHidetoshi Shimokawa fw_xfer_free(xfer); 805e9e688e2SHidetoshi Shimokawa } 806e9e688e2SHidetoshi Shimokawa 807e9e688e2SHidetoshi Shimokawa static cam_status 808e9e688e2SHidetoshi Shimokawa sbp_targ_abort_ccb(struct sbp_targ_softc *sc, union ccb *ccb) 809e9e688e2SHidetoshi Shimokawa { 810e9e688e2SHidetoshi Shimokawa union ccb *accb; 811e9e688e2SHidetoshi Shimokawa struct sbp_targ_lstate *lstate; 812e9e688e2SHidetoshi Shimokawa struct ccb_hdr_slist *list; 813e9e688e2SHidetoshi Shimokawa struct ccb_hdr *curelm; 814e9e688e2SHidetoshi Shimokawa int found; 815e9e688e2SHidetoshi Shimokawa cam_status status; 816e9e688e2SHidetoshi Shimokawa 817e9e688e2SHidetoshi Shimokawa status = sbp_targ_find_devs(sc, ccb, &lstate, 0); 818e9e688e2SHidetoshi Shimokawa if (status != CAM_REQ_CMP) 819e9e688e2SHidetoshi Shimokawa return (status); 820e9e688e2SHidetoshi Shimokawa 821e9e688e2SHidetoshi Shimokawa accb = ccb->cab.abort_ccb; 822e9e688e2SHidetoshi Shimokawa 823e9e688e2SHidetoshi Shimokawa if (accb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO) 824e9e688e2SHidetoshi Shimokawa list = &lstate->accept_tios; 825e9e688e2SHidetoshi Shimokawa else if (accb->ccb_h.func_code == XPT_IMMED_NOTIFY) 826e9e688e2SHidetoshi Shimokawa list = &lstate->immed_notifies; 827e9e688e2SHidetoshi Shimokawa else 828e9e688e2SHidetoshi Shimokawa return (CAM_UA_ABORT); 829e9e688e2SHidetoshi Shimokawa 830e9e688e2SHidetoshi Shimokawa curelm = SLIST_FIRST(list); 831e9e688e2SHidetoshi Shimokawa found = 0; 832e9e688e2SHidetoshi Shimokawa if (curelm == &accb->ccb_h) { 833e9e688e2SHidetoshi Shimokawa found = 1; 834e9e688e2SHidetoshi Shimokawa SLIST_REMOVE_HEAD(list, sim_links.sle); 835e9e688e2SHidetoshi Shimokawa } else { 836e9e688e2SHidetoshi Shimokawa while(curelm != NULL) { 837e9e688e2SHidetoshi Shimokawa struct ccb_hdr *nextelm; 838e9e688e2SHidetoshi Shimokawa 839e9e688e2SHidetoshi Shimokawa nextelm = SLIST_NEXT(curelm, sim_links.sle); 840e9e688e2SHidetoshi Shimokawa if (nextelm == &accb->ccb_h) { 841e9e688e2SHidetoshi Shimokawa found = 1; 842e9e688e2SHidetoshi Shimokawa SLIST_NEXT(curelm, sim_links.sle) = 843e9e688e2SHidetoshi Shimokawa SLIST_NEXT(nextelm, sim_links.sle); 844e9e688e2SHidetoshi Shimokawa break; 845e9e688e2SHidetoshi Shimokawa } 846e9e688e2SHidetoshi Shimokawa curelm = nextelm; 847e9e688e2SHidetoshi Shimokawa } 848e9e688e2SHidetoshi Shimokawa } 849e9e688e2SHidetoshi Shimokawa if (found) { 850e9e688e2SHidetoshi Shimokawa accb->ccb_h.status = CAM_REQ_ABORTED; 851e9e688e2SHidetoshi Shimokawa xpt_done(accb); 852e9e688e2SHidetoshi Shimokawa return (CAM_REQ_CMP); 853e9e688e2SHidetoshi Shimokawa } 85410d3ed64SHidetoshi Shimokawa printf("%s: not found\n", __func__); 855e9e688e2SHidetoshi Shimokawa return (CAM_PATH_INVALID); 856e9e688e2SHidetoshi Shimokawa } 857e9e688e2SHidetoshi Shimokawa 858e9e688e2SHidetoshi Shimokawa static void 859e9e688e2SHidetoshi Shimokawa sbp_targ_xfer_buf(struct orb_info *orbi, u_int offset, 86003161bbcSDoug Rabson uint16_t dst_hi, uint32_t dst_lo, u_int size, 861e9e688e2SHidetoshi Shimokawa void (*hand)(struct fw_xfer *)) 862e9e688e2SHidetoshi Shimokawa { 863e9e688e2SHidetoshi Shimokawa struct fw_xfer *xfer; 864e9e688e2SHidetoshi Shimokawa u_int len, ccb_dir, off = 0; 865e9e688e2SHidetoshi Shimokawa char *ptr; 866e9e688e2SHidetoshi Shimokawa 867a73ff510SHidetoshi Shimokawa if (debug > 1) 86810d3ed64SHidetoshi Shimokawa printf("%s: offset=%d size=%d\n", __func__, offset, size); 869e9e688e2SHidetoshi Shimokawa ccb_dir = orbi->ccb->ccb_h.flags & CAM_DIR_MASK; 870e9e688e2SHidetoshi Shimokawa ptr = (char *)orbi->ccb->csio.data_ptr + offset; 871e9e688e2SHidetoshi Shimokawa 872e9e688e2SHidetoshi Shimokawa while (size > 0) { 873e9e688e2SHidetoshi Shimokawa /* XXX assume dst_lo + off doesn't overflow */ 874e9e688e2SHidetoshi Shimokawa len = MIN(size, 2048 /* XXX */); 875e9e688e2SHidetoshi Shimokawa size -= len; 876e9e688e2SHidetoshi Shimokawa orbi->refcount ++; 877e9e688e2SHidetoshi Shimokawa if (ccb_dir == CAM_DIR_OUT) 878e9e688e2SHidetoshi Shimokawa xfer = fwmem_read_block(orbi->fwdev, 879e9e688e2SHidetoshi Shimokawa (void *)orbi, /*spd*/2, 880e9e688e2SHidetoshi Shimokawa dst_hi, dst_lo + off, len, 881e9e688e2SHidetoshi Shimokawa ptr + off, hand); 882e9e688e2SHidetoshi Shimokawa else 883e9e688e2SHidetoshi Shimokawa xfer = fwmem_write_block(orbi->fwdev, 884e9e688e2SHidetoshi Shimokawa (void *)orbi, /*spd*/2, 885e9e688e2SHidetoshi Shimokawa dst_hi, dst_lo + off, len, 886e9e688e2SHidetoshi Shimokawa ptr + off, hand); 887e9e688e2SHidetoshi Shimokawa if (xfer == NULL) { 88810d3ed64SHidetoshi Shimokawa printf("%s: xfer == NULL", __func__); 889e9e688e2SHidetoshi Shimokawa /* XXX what should we do?? */ 890e9e688e2SHidetoshi Shimokawa orbi->refcount --; 891e9e688e2SHidetoshi Shimokawa } 892e9e688e2SHidetoshi Shimokawa off += len; 893e9e688e2SHidetoshi Shimokawa } 894e9e688e2SHidetoshi Shimokawa } 895e9e688e2SHidetoshi Shimokawa 896e9e688e2SHidetoshi Shimokawa static void 897e9e688e2SHidetoshi Shimokawa sbp_targ_pt_done(struct fw_xfer *xfer) 898e9e688e2SHidetoshi Shimokawa { 899e9e688e2SHidetoshi Shimokawa struct orb_info *orbi; 900e9e688e2SHidetoshi Shimokawa union ccb *ccb; 901e9e688e2SHidetoshi Shimokawa u_int i, offset, res, len; 90203161bbcSDoug Rabson uint32_t t1, t2, *p; 903e9e688e2SHidetoshi Shimokawa 904e9e688e2SHidetoshi Shimokawa orbi = (struct orb_info *)xfer->sc; 905e9e688e2SHidetoshi Shimokawa ccb = orbi->ccb; 906e9e688e2SHidetoshi Shimokawa if (orbi->state == ORBI_STATUS_ABORTED) { 907e9e688e2SHidetoshi Shimokawa if (debug) 90810d3ed64SHidetoshi Shimokawa printf("%s: orbi aborted\n", __func__); 909a73ff510SHidetoshi Shimokawa sbp_targ_remove_orb_info(orbi->login, orbi); 910e9e688e2SHidetoshi Shimokawa free(orbi->page_table, M_SBP_TARG); 911e9e688e2SHidetoshi Shimokawa free(orbi, M_SBP_TARG); 912e9e688e2SHidetoshi Shimokawa fw_xfer_free(xfer); 913e9e688e2SHidetoshi Shimokawa return; 914e9e688e2SHidetoshi Shimokawa } 915e9e688e2SHidetoshi Shimokawa if (xfer->resp != 0) { 91610d3ed64SHidetoshi Shimokawa printf("%s: xfer->resp = %d\n", __func__, xfer->resp); 917e9e688e2SHidetoshi Shimokawa orbi->status.resp = SBP_TRANS_FAIL; 9181398a889SHidetoshi Shimokawa orbi->status.status = OBJ_PT | SBE_TIMEOUT/*XXX*/; 919e9e688e2SHidetoshi Shimokawa orbi->status.dead = 1; 920e9e688e2SHidetoshi Shimokawa orbi->status.len = 1; 9219950b741SHidetoshi Shimokawa sbp_targ_abort(orbi->sc, STAILQ_NEXT(orbi, link)); 922e9e688e2SHidetoshi Shimokawa 923e9e688e2SHidetoshi Shimokawa sbp_targ_status_FIFO(orbi, 924a73ff510SHidetoshi Shimokawa orbi->login->fifo_hi, orbi->login->fifo_lo, /*dequeue*/1); 925e9e688e2SHidetoshi Shimokawa free(orbi->page_table, M_SBP_TARG); 926e9e688e2SHidetoshi Shimokawa fw_xfer_free(xfer); 927e9e688e2SHidetoshi Shimokawa return; 928e9e688e2SHidetoshi Shimokawa } 929e9e688e2SHidetoshi Shimokawa res = ccb->csio.dxfer_len; 930e9e688e2SHidetoshi Shimokawa offset = 0; 931e9e688e2SHidetoshi Shimokawa if (debug) 93210d3ed64SHidetoshi Shimokawa printf("%s: dxfer_len=%d\n", __func__, res); 933e9e688e2SHidetoshi Shimokawa orbi->refcount ++; 934e9e688e2SHidetoshi Shimokawa for (p = orbi->page_table, i = orbi->orb4.data_size; i > 0; i --) { 935e9e688e2SHidetoshi Shimokawa t1 = ntohl(*p++); 936e9e688e2SHidetoshi Shimokawa t2 = ntohl(*p++); 937a73ff510SHidetoshi Shimokawa if (debug > 1) 938e9e688e2SHidetoshi Shimokawa printf("page_table: %04x:%08x %d\n", 939e9e688e2SHidetoshi Shimokawa t1 & 0xffff, t2, t1>>16); 940e9e688e2SHidetoshi Shimokawa len = MIN(t1 >> 16, res); 941e9e688e2SHidetoshi Shimokawa res -= len; 942e9e688e2SHidetoshi Shimokawa sbp_targ_xfer_buf(orbi, offset, t1 & 0xffff, t2, len, 943e9e688e2SHidetoshi Shimokawa sbp_targ_cam_done); 944e9e688e2SHidetoshi Shimokawa offset += len; 945e9e688e2SHidetoshi Shimokawa if (res == 0) 946e9e688e2SHidetoshi Shimokawa break; 947e9e688e2SHidetoshi Shimokawa } 948e9e688e2SHidetoshi Shimokawa orbi->refcount --; 949e9e688e2SHidetoshi Shimokawa if (orbi->refcount == 0) 95010d3ed64SHidetoshi Shimokawa printf("%s: refcount == 0\n", __func__); 951e9e688e2SHidetoshi Shimokawa if (res !=0) 952e9e688e2SHidetoshi Shimokawa /* XXX handle res != 0 case */ 95310d3ed64SHidetoshi Shimokawa printf("%s: page table is too small(%d)\n", __func__, res); 954e9e688e2SHidetoshi Shimokawa 955e9e688e2SHidetoshi Shimokawa fw_xfer_free(xfer); 956e9e688e2SHidetoshi Shimokawa return; 957e9e688e2SHidetoshi Shimokawa } 958e9e688e2SHidetoshi Shimokawa 959e9e688e2SHidetoshi Shimokawa static void 960e9e688e2SHidetoshi Shimokawa sbp_targ_fetch_pt(struct orb_info *orbi) 961e9e688e2SHidetoshi Shimokawa { 962e9e688e2SHidetoshi Shimokawa struct fw_xfer *xfer; 963e9e688e2SHidetoshi Shimokawa 964e9e688e2SHidetoshi Shimokawa if (debug) 965e9e688e2SHidetoshi Shimokawa printf("%s: page_table_size=%d\n", 96610d3ed64SHidetoshi Shimokawa __func__, orbi->orb4.data_size); 967e9e688e2SHidetoshi Shimokawa orbi->page_table = malloc(orbi->orb4.data_size*8, M_SBP_TARG, M_NOWAIT); 968e9e688e2SHidetoshi Shimokawa if (orbi->page_table == NULL) 969e9e688e2SHidetoshi Shimokawa goto error; 970e9e688e2SHidetoshi Shimokawa xfer = fwmem_read_block(orbi->fwdev, (void *)orbi, /*spd*/2, 971e9e688e2SHidetoshi Shimokawa orbi->data_hi, orbi->data_lo, orbi->orb4.data_size*8, 972e9e688e2SHidetoshi Shimokawa (void *)orbi->page_table, sbp_targ_pt_done); 973e9e688e2SHidetoshi Shimokawa if (xfer != NULL) 974e9e688e2SHidetoshi Shimokawa return; 975e9e688e2SHidetoshi Shimokawa error: 976e9e688e2SHidetoshi Shimokawa orbi->ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 977e9e688e2SHidetoshi Shimokawa xpt_done(orbi->ccb); 978e9e688e2SHidetoshi Shimokawa return; 979e9e688e2SHidetoshi Shimokawa } 980e9e688e2SHidetoshi Shimokawa 981e9e688e2SHidetoshi Shimokawa static void 982e9e688e2SHidetoshi Shimokawa sbp_targ_action1(struct cam_sim *sim, union ccb *ccb) 983e9e688e2SHidetoshi Shimokawa { 984e9e688e2SHidetoshi Shimokawa struct sbp_targ_softc *sc; 985e9e688e2SHidetoshi Shimokawa struct sbp_targ_lstate *lstate; 986e9e688e2SHidetoshi Shimokawa cam_status status; 987e9e688e2SHidetoshi Shimokawa u_int ccb_dir; 988e9e688e2SHidetoshi Shimokawa 989e9e688e2SHidetoshi Shimokawa sc = (struct sbp_targ_softc *)cam_sim_softc(sim); 990e9e688e2SHidetoshi Shimokawa 991e9e688e2SHidetoshi Shimokawa status = sbp_targ_find_devs(sc, ccb, &lstate, TRUE); 992e9e688e2SHidetoshi Shimokawa 993e9e688e2SHidetoshi Shimokawa switch (ccb->ccb_h.func_code) { 994e9e688e2SHidetoshi Shimokawa case XPT_CONT_TARGET_IO: 995e9e688e2SHidetoshi Shimokawa { 996e9e688e2SHidetoshi Shimokawa struct orb_info *orbi; 997e9e688e2SHidetoshi Shimokawa 998e9e688e2SHidetoshi Shimokawa if (debug) 9999950b741SHidetoshi Shimokawa printf("%s: XPT_CONT_TARGET_IO (0x%08x)\n", 10009950b741SHidetoshi Shimokawa __func__, ccb->csio.tag_id); 1001e9e688e2SHidetoshi Shimokawa 1002e9e688e2SHidetoshi Shimokawa if (status != CAM_REQ_CMP) { 1003e9e688e2SHidetoshi Shimokawa ccb->ccb_h.status = status; 1004e9e688e2SHidetoshi Shimokawa xpt_done(ccb); 1005e9e688e2SHidetoshi Shimokawa break; 1006e9e688e2SHidetoshi Shimokawa } 1007e9e688e2SHidetoshi Shimokawa /* XXX transfer from/to initiator */ 1008e9e688e2SHidetoshi Shimokawa orbi = sbp_targ_get_orb_info(lstate, 1009e9e688e2SHidetoshi Shimokawa ccb->csio.tag_id, ccb->csio.init_id); 1010e9e688e2SHidetoshi Shimokawa if (orbi == NULL) { 1011e9e688e2SHidetoshi Shimokawa ccb->ccb_h.status = CAM_REQ_ABORTED; /* XXX */ 1012e9e688e2SHidetoshi Shimokawa xpt_done(ccb); 1013e9e688e2SHidetoshi Shimokawa break; 1014e9e688e2SHidetoshi Shimokawa } 1015e9e688e2SHidetoshi Shimokawa if (orbi->state == ORBI_STATUS_ABORTED) { 1016e9e688e2SHidetoshi Shimokawa if (debug) 101710d3ed64SHidetoshi Shimokawa printf("%s: ctio aborted\n", __func__); 10189950b741SHidetoshi Shimokawa sbp_targ_remove_orb_info_locked(orbi->login, orbi); 1019e9e688e2SHidetoshi Shimokawa free(orbi, M_SBP_TARG); 10209950b741SHidetoshi Shimokawa ccb->ccb_h.status = CAM_REQ_ABORTED; 10219950b741SHidetoshi Shimokawa xpt_done(ccb); 1022e9e688e2SHidetoshi Shimokawa break; 1023e9e688e2SHidetoshi Shimokawa } 1024e9e688e2SHidetoshi Shimokawa orbi->state = ORBI_STATUS_CTIO; 1025e9e688e2SHidetoshi Shimokawa 1026e9e688e2SHidetoshi Shimokawa orbi->ccb = ccb; 1027e9e688e2SHidetoshi Shimokawa ccb_dir = ccb->ccb_h.flags & CAM_DIR_MASK; 1028e9e688e2SHidetoshi Shimokawa 1029e9e688e2SHidetoshi Shimokawa /* XXX */ 1030e9e688e2SHidetoshi Shimokawa if (ccb->csio.dxfer_len == 0) 1031e9e688e2SHidetoshi Shimokawa ccb_dir = CAM_DIR_NONE; 1032e9e688e2SHidetoshi Shimokawa 1033e9e688e2SHidetoshi Shimokawa /* Sanity check */ 1034e9e688e2SHidetoshi Shimokawa if (ccb_dir == CAM_DIR_IN && orbi->orb4.dir == 0) 103510d3ed64SHidetoshi Shimokawa printf("%s: direction mismatch\n", __func__); 1036e9e688e2SHidetoshi Shimokawa 1037e9e688e2SHidetoshi Shimokawa /* check page table */ 1038e9e688e2SHidetoshi Shimokawa if (ccb_dir != CAM_DIR_NONE && orbi->orb4.page_table_present) { 1039e9e688e2SHidetoshi Shimokawa if (debug) 1040e9e688e2SHidetoshi Shimokawa printf("%s: page_table_present\n", 104110d3ed64SHidetoshi Shimokawa __func__); 1042e9e688e2SHidetoshi Shimokawa if (orbi->orb4.page_size != 0) { 1043e9e688e2SHidetoshi Shimokawa printf("%s: unsupported pagesize %d != 0\n", 104410d3ed64SHidetoshi Shimokawa __func__, orbi->orb4.page_size); 1045e9e688e2SHidetoshi Shimokawa ccb->ccb_h.status = CAM_REQ_INVALID; 1046e9e688e2SHidetoshi Shimokawa xpt_done(ccb); 1047e9e688e2SHidetoshi Shimokawa break; 1048e9e688e2SHidetoshi Shimokawa } 1049e9e688e2SHidetoshi Shimokawa sbp_targ_fetch_pt(orbi); 1050e9e688e2SHidetoshi Shimokawa break; 1051e9e688e2SHidetoshi Shimokawa } 1052e9e688e2SHidetoshi Shimokawa 1053e9e688e2SHidetoshi Shimokawa /* Sanity check */ 1054e9e688e2SHidetoshi Shimokawa if (ccb_dir != CAM_DIR_NONE && 1055e9e688e2SHidetoshi Shimokawa orbi->orb4.data_size != ccb->csio.dxfer_len) 1056e9e688e2SHidetoshi Shimokawa printf("%s: data_size(%d) != dxfer_len(%d)\n", 105710d3ed64SHidetoshi Shimokawa __func__, orbi->orb4.data_size, 1058e9e688e2SHidetoshi Shimokawa ccb->csio.dxfer_len); 1059e9e688e2SHidetoshi Shimokawa 1060e9e688e2SHidetoshi Shimokawa if (ccb_dir != CAM_DIR_NONE) 1061e9e688e2SHidetoshi Shimokawa sbp_targ_xfer_buf(orbi, 0, orbi->data_hi, 1062e9e688e2SHidetoshi Shimokawa orbi->data_lo, 1063e9e688e2SHidetoshi Shimokawa MIN(orbi->orb4.data_size, ccb->csio.dxfer_len), 1064e9e688e2SHidetoshi Shimokawa sbp_targ_cam_done); 1065e9e688e2SHidetoshi Shimokawa 1066e9e688e2SHidetoshi Shimokawa if (ccb_dir == CAM_DIR_NONE) { 10679950b741SHidetoshi Shimokawa if ((ccb->ccb_h.flags & CAM_SEND_STATUS) != 0) { 10689950b741SHidetoshi Shimokawa /* XXX */ 10699950b741SHidetoshi Shimokawa SBP_UNLOCK(sc); 1070e9e688e2SHidetoshi Shimokawa sbp_targ_send_status(orbi, ccb); 10719950b741SHidetoshi Shimokawa SBP_LOCK(sc); 10729950b741SHidetoshi Shimokawa } 1073e9e688e2SHidetoshi Shimokawa ccb->ccb_h.status = CAM_REQ_CMP; 1074e9e688e2SHidetoshi Shimokawa xpt_done(ccb); 1075e9e688e2SHidetoshi Shimokawa } 1076e9e688e2SHidetoshi Shimokawa break; 1077e9e688e2SHidetoshi Shimokawa } 1078e9e688e2SHidetoshi Shimokawa case XPT_ACCEPT_TARGET_IO: /* Add Accept Target IO Resource */ 1079e9e688e2SHidetoshi Shimokawa if (status != CAM_REQ_CMP) { 1080e9e688e2SHidetoshi Shimokawa ccb->ccb_h.status = status; 1081e9e688e2SHidetoshi Shimokawa xpt_done(ccb); 1082e9e688e2SHidetoshi Shimokawa break; 1083e9e688e2SHidetoshi Shimokawa } 1084e9e688e2SHidetoshi Shimokawa SLIST_INSERT_HEAD(&lstate->accept_tios, &ccb->ccb_h, 1085e9e688e2SHidetoshi Shimokawa sim_links.sle); 1086e9e688e2SHidetoshi Shimokawa ccb->ccb_h.status = CAM_REQ_INPROG; 1087a73ff510SHidetoshi Shimokawa if ((lstate->flags & F_ATIO_STARVED) != 0) { 1088a73ff510SHidetoshi Shimokawa struct sbp_targ_login *login; 1089a73ff510SHidetoshi Shimokawa 1090e9e688e2SHidetoshi Shimokawa if (debug) 109110d3ed64SHidetoshi Shimokawa printf("%s: new atio arrived\n", __func__); 1092a73ff510SHidetoshi Shimokawa lstate->flags &= ~F_ATIO_STARVED; 1093a73ff510SHidetoshi Shimokawa STAILQ_FOREACH(login, &lstate->logins, link) 1094a73ff510SHidetoshi Shimokawa if ((login->flags & F_ATIO_STARVED) != 0) { 1095a73ff510SHidetoshi Shimokawa login->flags &= ~F_ATIO_STARVED; 1096a73ff510SHidetoshi Shimokawa sbp_targ_fetch_orb(lstate->sc, 1097a73ff510SHidetoshi Shimokawa login->fwdev, 1098a73ff510SHidetoshi Shimokawa login->last_hi, login->last_lo, 1099a73ff510SHidetoshi Shimokawa login, FETCH_CMD); 1100a73ff510SHidetoshi Shimokawa } 1101e9e688e2SHidetoshi Shimokawa } 1102e9e688e2SHidetoshi Shimokawa break; 1103e9e688e2SHidetoshi Shimokawa case XPT_NOTIFY_ACK: /* recycle notify ack */ 1104e9e688e2SHidetoshi Shimokawa case XPT_IMMED_NOTIFY: /* Add Immediate Notify Resource */ 1105e9e688e2SHidetoshi Shimokawa if (status != CAM_REQ_CMP) { 1106e9e688e2SHidetoshi Shimokawa ccb->ccb_h.status = status; 1107e9e688e2SHidetoshi Shimokawa xpt_done(ccb); 1108e9e688e2SHidetoshi Shimokawa break; 1109e9e688e2SHidetoshi Shimokawa } 1110e9e688e2SHidetoshi Shimokawa SLIST_INSERT_HEAD(&lstate->immed_notifies, &ccb->ccb_h, 1111e9e688e2SHidetoshi Shimokawa sim_links.sle); 1112e9e688e2SHidetoshi Shimokawa ccb->ccb_h.status = CAM_REQ_INPROG; 1113e9e688e2SHidetoshi Shimokawa sbp_targ_send_lstate_events(sc, lstate); 1114e9e688e2SHidetoshi Shimokawa break; 1115e9e688e2SHidetoshi Shimokawa case XPT_EN_LUN: 1116e9e688e2SHidetoshi Shimokawa sbp_targ_en_lun(sc, ccb); 1117e9e688e2SHidetoshi Shimokawa xpt_done(ccb); 1118e9e688e2SHidetoshi Shimokawa break; 1119e9e688e2SHidetoshi Shimokawa case XPT_PATH_INQ: 1120e9e688e2SHidetoshi Shimokawa { 1121e9e688e2SHidetoshi Shimokawa struct ccb_pathinq *cpi = &ccb->cpi; 1122e9e688e2SHidetoshi Shimokawa 1123e9e688e2SHidetoshi Shimokawa cpi->version_num = 1; /* XXX??? */ 1124e9e688e2SHidetoshi Shimokawa cpi->hba_inquiry = PI_TAG_ABLE; 1125e9e688e2SHidetoshi Shimokawa cpi->target_sprt = PIT_PROCESSOR 1126e9e688e2SHidetoshi Shimokawa | PIT_DISCONNECT 1127e9e688e2SHidetoshi Shimokawa | PIT_TERM_IO; 1128e9e688e2SHidetoshi Shimokawa cpi->hba_misc = PIM_NOBUSRESET | PIM_NO_6_BYTE; 1129e9e688e2SHidetoshi Shimokawa cpi->hba_eng_cnt = 0; 1130e9e688e2SHidetoshi Shimokawa cpi->max_target = 7; /* XXX */ 1131e9e688e2SHidetoshi Shimokawa cpi->max_lun = MAX_LUN - 1; 1132e9e688e2SHidetoshi Shimokawa cpi->initiator_id = 7; /* XXX */ 1133e9e688e2SHidetoshi Shimokawa cpi->bus_id = sim->bus_id; 1134e9e688e2SHidetoshi Shimokawa cpi->base_transfer_speed = 400 * 1000 / 8; 1135e9e688e2SHidetoshi Shimokawa strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 1136e9e688e2SHidetoshi Shimokawa strncpy(cpi->hba_vid, "SBP_TARG", HBA_IDLEN); 1137e9e688e2SHidetoshi Shimokawa strncpy(cpi->dev_name, sim->sim_name, DEV_IDLEN); 1138e9e688e2SHidetoshi Shimokawa cpi->unit_number = sim->unit_number; 1139e9e688e2SHidetoshi Shimokawa 1140e9e688e2SHidetoshi Shimokawa cpi->ccb_h.status = CAM_REQ_CMP; 1141e9e688e2SHidetoshi Shimokawa xpt_done(ccb); 1142e9e688e2SHidetoshi Shimokawa break; 1143e9e688e2SHidetoshi Shimokawa } 1144e9e688e2SHidetoshi Shimokawa case XPT_ABORT: 1145e9e688e2SHidetoshi Shimokawa { 1146e9e688e2SHidetoshi Shimokawa union ccb *accb = ccb->cab.abort_ccb; 1147e9e688e2SHidetoshi Shimokawa 1148e9e688e2SHidetoshi Shimokawa switch (accb->ccb_h.func_code) { 1149e9e688e2SHidetoshi Shimokawa case XPT_ACCEPT_TARGET_IO: 1150e9e688e2SHidetoshi Shimokawa case XPT_IMMED_NOTIFY: 1151e9e688e2SHidetoshi Shimokawa ccb->ccb_h.status = sbp_targ_abort_ccb(sc, ccb); 1152e9e688e2SHidetoshi Shimokawa break; 1153e9e688e2SHidetoshi Shimokawa case XPT_CONT_TARGET_IO: 1154e9e688e2SHidetoshi Shimokawa /* XXX */ 1155e9e688e2SHidetoshi Shimokawa ccb->ccb_h.status = CAM_UA_ABORT; 1156e9e688e2SHidetoshi Shimokawa break; 1157e9e688e2SHidetoshi Shimokawa default: 1158e9e688e2SHidetoshi Shimokawa printf("%s: aborting unknown function %d\n", 115910d3ed64SHidetoshi Shimokawa __func__, accb->ccb_h.func_code); 1160e9e688e2SHidetoshi Shimokawa ccb->ccb_h.status = CAM_REQ_INVALID; 1161e9e688e2SHidetoshi Shimokawa break; 1162e9e688e2SHidetoshi Shimokawa } 1163e9e688e2SHidetoshi Shimokawa xpt_done(ccb); 1164e9e688e2SHidetoshi Shimokawa break; 1165e9e688e2SHidetoshi Shimokawa } 1166e9e688e2SHidetoshi Shimokawa default: 1167e9e688e2SHidetoshi Shimokawa printf("%s: unknown function %d\n", 116810d3ed64SHidetoshi Shimokawa __func__, ccb->ccb_h.func_code); 1169e9e688e2SHidetoshi Shimokawa ccb->ccb_h.status = CAM_REQ_INVALID; 1170e9e688e2SHidetoshi Shimokawa xpt_done(ccb); 1171e9e688e2SHidetoshi Shimokawa break; 1172e9e688e2SHidetoshi Shimokawa } 1173e9e688e2SHidetoshi Shimokawa return; 1174e9e688e2SHidetoshi Shimokawa } 1175e9e688e2SHidetoshi Shimokawa 1176e9e688e2SHidetoshi Shimokawa static void 1177e9e688e2SHidetoshi Shimokawa sbp_targ_action(struct cam_sim *sim, union ccb *ccb) 1178e9e688e2SHidetoshi Shimokawa { 1179e9e688e2SHidetoshi Shimokawa int s; 1180e9e688e2SHidetoshi Shimokawa 1181e9e688e2SHidetoshi Shimokawa s = splfw(); 1182e9e688e2SHidetoshi Shimokawa sbp_targ_action1(sim, ccb); 1183e9e688e2SHidetoshi Shimokawa splx(s); 1184e9e688e2SHidetoshi Shimokawa } 1185e9e688e2SHidetoshi Shimokawa 1186e9e688e2SHidetoshi Shimokawa static void 1187e9e688e2SHidetoshi Shimokawa sbp_targ_poll(struct cam_sim *sim) 1188e9e688e2SHidetoshi Shimokawa { 1189e9e688e2SHidetoshi Shimokawa /* XXX */ 1190e9e688e2SHidetoshi Shimokawa return; 1191e9e688e2SHidetoshi Shimokawa } 1192e9e688e2SHidetoshi Shimokawa 1193e9e688e2SHidetoshi Shimokawa static void 1194e9e688e2SHidetoshi Shimokawa sbp_targ_cmd_handler(struct fw_xfer *xfer) 1195e9e688e2SHidetoshi Shimokawa { 1196e9e688e2SHidetoshi Shimokawa struct fw_pkt *fp; 119703161bbcSDoug Rabson uint32_t *orb; 1198e9e688e2SHidetoshi Shimokawa struct corb4 *orb4; 1199e9e688e2SHidetoshi Shimokawa struct orb_info *orbi; 1200e9e688e2SHidetoshi Shimokawa struct ccb_accept_tio *atio; 1201e9e688e2SHidetoshi Shimokawa u_char *bytes; 1202e9e688e2SHidetoshi Shimokawa int i; 1203e9e688e2SHidetoshi Shimokawa 1204e9e688e2SHidetoshi Shimokawa orbi = (struct orb_info *)xfer->sc; 1205e9e688e2SHidetoshi Shimokawa if (xfer->resp != 0) { 120610d3ed64SHidetoshi Shimokawa printf("%s: xfer->resp = %d\n", __func__, xfer->resp); 1207e9e688e2SHidetoshi Shimokawa orbi->status.resp = SBP_TRANS_FAIL; 12081398a889SHidetoshi Shimokawa orbi->status.status = OBJ_ORB | SBE_TIMEOUT/*XXX*/; 1209e9e688e2SHidetoshi Shimokawa orbi->status.dead = 1; 1210e9e688e2SHidetoshi Shimokawa orbi->status.len = 1; 12119950b741SHidetoshi Shimokawa sbp_targ_abort(orbi->sc, STAILQ_NEXT(orbi, link)); 1212e9e688e2SHidetoshi Shimokawa 1213e9e688e2SHidetoshi Shimokawa sbp_targ_status_FIFO(orbi, 1214a73ff510SHidetoshi Shimokawa orbi->login->fifo_hi, orbi->login->fifo_lo, /*dequeue*/1); 1215e9e688e2SHidetoshi Shimokawa fw_xfer_free(xfer); 1216e9e688e2SHidetoshi Shimokawa return; 1217e9e688e2SHidetoshi Shimokawa } 1218e9e688e2SHidetoshi Shimokawa fp = &xfer->recv.hdr; 1219e9e688e2SHidetoshi Shimokawa 12209950b741SHidetoshi Shimokawa atio = orbi->atio; 12219950b741SHidetoshi Shimokawa 1222e9e688e2SHidetoshi Shimokawa if (orbi->state == ORBI_STATUS_ABORTED) { 122310d3ed64SHidetoshi Shimokawa printf("%s: aborted\n", __func__); 1224a73ff510SHidetoshi Shimokawa sbp_targ_remove_orb_info(orbi->login, orbi); 1225e9e688e2SHidetoshi Shimokawa free(orbi, M_SBP_TARG); 12269950b741SHidetoshi Shimokawa atio->ccb_h.status = CAM_REQ_ABORTED; 12279950b741SHidetoshi Shimokawa SBP_LOCK(orbi->sc); 12289950b741SHidetoshi Shimokawa xpt_done((union ccb*)atio); 12299950b741SHidetoshi Shimokawa SBP_UNLOCK(orbi->sc); 1230e9e688e2SHidetoshi Shimokawa goto done0; 1231e9e688e2SHidetoshi Shimokawa } 1232e9e688e2SHidetoshi Shimokawa orbi->state = ORBI_STATUS_ATIO; 1233e9e688e2SHidetoshi Shimokawa 1234e9e688e2SHidetoshi Shimokawa orb = orbi->orb; 1235e9e688e2SHidetoshi Shimokawa /* swap payload except SCSI command */ 1236e9e688e2SHidetoshi Shimokawa for (i = 0; i < 5; i ++) 1237e9e688e2SHidetoshi Shimokawa orb[i] = ntohl(orb[i]); 1238e9e688e2SHidetoshi Shimokawa 1239e9e688e2SHidetoshi Shimokawa orb4 = (struct corb4 *)&orb[4]; 1240e9e688e2SHidetoshi Shimokawa if (orb4->rq_fmt != 0) { 1241e9e688e2SHidetoshi Shimokawa /* XXX */ 124210d3ed64SHidetoshi Shimokawa printf("%s: rq_fmt(%d) != 0\n", __func__, orb4->rq_fmt); 1243e9e688e2SHidetoshi Shimokawa } 1244e9e688e2SHidetoshi Shimokawa 1245e9e688e2SHidetoshi Shimokawa atio->ccb_h.target_id = 0; /* XXX */ 1246a73ff510SHidetoshi Shimokawa atio->ccb_h.target_lun = orbi->login->lstate->lun; 1247e9e688e2SHidetoshi Shimokawa atio->sense_len = 0; 1248e9e688e2SHidetoshi Shimokawa atio->tag_action = 1; /* XXX */ 1249e9e688e2SHidetoshi Shimokawa atio->tag_id = orbi->orb_lo; 1250a73ff510SHidetoshi Shimokawa atio->init_id = orbi->login->id; 1251a73ff510SHidetoshi Shimokawa 1252e9e688e2SHidetoshi Shimokawa atio->ccb_h.flags = CAM_TAG_ACTION_VALID; 12539950b741SHidetoshi Shimokawa bytes = (u_char *)&orb[5]; 1254e9e688e2SHidetoshi Shimokawa if (debug) 12559950b741SHidetoshi Shimokawa printf("%s: %p %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", 12569950b741SHidetoshi Shimokawa __func__, (void *)atio, 1257e9e688e2SHidetoshi Shimokawa bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], 1258e9e688e2SHidetoshi Shimokawa bytes[5], bytes[6], bytes[7], bytes[8], bytes[9]); 1259e9e688e2SHidetoshi Shimokawa switch (bytes[0] >> 5) { 1260e9e688e2SHidetoshi Shimokawa case 0: 1261e9e688e2SHidetoshi Shimokawa atio->cdb_len = 6; 1262e9e688e2SHidetoshi Shimokawa break; 1263e9e688e2SHidetoshi Shimokawa case 1: 1264e9e688e2SHidetoshi Shimokawa case 2: 1265e9e688e2SHidetoshi Shimokawa atio->cdb_len = 10; 1266e9e688e2SHidetoshi Shimokawa break; 1267e9e688e2SHidetoshi Shimokawa case 4: 1268e9e688e2SHidetoshi Shimokawa atio->cdb_len = 16; 1269e9e688e2SHidetoshi Shimokawa break; 1270e9e688e2SHidetoshi Shimokawa case 5: 1271e9e688e2SHidetoshi Shimokawa atio->cdb_len = 12; 1272e9e688e2SHidetoshi Shimokawa break; 1273e9e688e2SHidetoshi Shimokawa case 3: 1274e9e688e2SHidetoshi Shimokawa default: 1275e9e688e2SHidetoshi Shimokawa /* Only copy the opcode. */ 1276e9e688e2SHidetoshi Shimokawa atio->cdb_len = 1; 1277e9e688e2SHidetoshi Shimokawa printf("Reserved or VU command code type encountered\n"); 1278e9e688e2SHidetoshi Shimokawa break; 1279e9e688e2SHidetoshi Shimokawa } 1280e9e688e2SHidetoshi Shimokawa 1281e9e688e2SHidetoshi Shimokawa memcpy(atio->cdb_io.cdb_bytes, bytes, atio->cdb_len); 1282e9e688e2SHidetoshi Shimokawa 1283e9e688e2SHidetoshi Shimokawa atio->ccb_h.status |= CAM_CDB_RECVD; 1284e9e688e2SHidetoshi Shimokawa 1285e9e688e2SHidetoshi Shimokawa /* next ORB */ 1286e9e688e2SHidetoshi Shimokawa if ((orb[0] & (1<<31)) == 0) { 1287e9e688e2SHidetoshi Shimokawa if (debug) 128810d3ed64SHidetoshi Shimokawa printf("%s: fetch next orb\n", __func__); 1289e9e688e2SHidetoshi Shimokawa orbi->status.src = SRC_NEXT_EXISTS; 1290e9e688e2SHidetoshi Shimokawa sbp_targ_fetch_orb(orbi->sc, orbi->fwdev, 1291a73ff510SHidetoshi Shimokawa orb[0], orb[1], orbi->login, FETCH_CMD); 1292e9e688e2SHidetoshi Shimokawa } else { 1293e9e688e2SHidetoshi Shimokawa orbi->status.src = SRC_NO_NEXT; 1294a73ff510SHidetoshi Shimokawa orbi->login->flags &= ~F_LINK_ACTIVE; 1295e9e688e2SHidetoshi Shimokawa } 1296e9e688e2SHidetoshi Shimokawa 1297e9e688e2SHidetoshi Shimokawa orbi->data_hi = orb[2]; 1298e9e688e2SHidetoshi Shimokawa orbi->data_lo = orb[3]; 1299e9e688e2SHidetoshi Shimokawa orbi->orb4 = *orb4; 1300e9e688e2SHidetoshi Shimokawa 13019950b741SHidetoshi Shimokawa SBP_LOCK(orbi->sc); 1302e9e688e2SHidetoshi Shimokawa xpt_done((union ccb*)atio); 13039950b741SHidetoshi Shimokawa SBP_UNLOCK(orbi->sc); 1304e9e688e2SHidetoshi Shimokawa done0: 1305e9e688e2SHidetoshi Shimokawa fw_xfer_free(xfer); 1306e9e688e2SHidetoshi Shimokawa return; 1307e9e688e2SHidetoshi Shimokawa } 1308e9e688e2SHidetoshi Shimokawa 1309a73ff510SHidetoshi Shimokawa static struct sbp_targ_login * 1310a73ff510SHidetoshi Shimokawa sbp_targ_get_login(struct sbp_targ_softc *sc, struct fw_device *fwdev, int lun) 1311a73ff510SHidetoshi Shimokawa { 1312a73ff510SHidetoshi Shimokawa struct sbp_targ_lstate *lstate; 1313a73ff510SHidetoshi Shimokawa struct sbp_targ_login *login; 1314a73ff510SHidetoshi Shimokawa int i; 1315a73ff510SHidetoshi Shimokawa 1316a73ff510SHidetoshi Shimokawa lstate = sc->lstate[lun]; 1317a73ff510SHidetoshi Shimokawa 1318a73ff510SHidetoshi Shimokawa STAILQ_FOREACH(login, &lstate->logins, link) 1319a73ff510SHidetoshi Shimokawa if (login->fwdev == fwdev) 1320a73ff510SHidetoshi Shimokawa return (login); 1321a73ff510SHidetoshi Shimokawa 1322a73ff510SHidetoshi Shimokawa for (i = 0; i < MAX_LOGINS; i ++) 1323a73ff510SHidetoshi Shimokawa if (sc->logins[i] == NULL) 1324a73ff510SHidetoshi Shimokawa goto found; 1325a73ff510SHidetoshi Shimokawa 132610d3ed64SHidetoshi Shimokawa printf("%s: increase MAX_LOGIN\n", __func__); 1327a73ff510SHidetoshi Shimokawa return (NULL); 1328a73ff510SHidetoshi Shimokawa 1329a73ff510SHidetoshi Shimokawa found: 1330a73ff510SHidetoshi Shimokawa login = (struct sbp_targ_login *)malloc( 1331a73ff510SHidetoshi Shimokawa sizeof(struct sbp_targ_login), M_SBP_TARG, M_NOWAIT | M_ZERO); 1332a73ff510SHidetoshi Shimokawa 1333a73ff510SHidetoshi Shimokawa if (login == NULL) { 133410d3ed64SHidetoshi Shimokawa printf("%s: malloc failed\n", __func__); 1335a73ff510SHidetoshi Shimokawa return (NULL); 1336a73ff510SHidetoshi Shimokawa } 1337a73ff510SHidetoshi Shimokawa 1338c6cf3e20SHidetoshi Shimokawa login->id = i; 1339a73ff510SHidetoshi Shimokawa login->fwdev = fwdev; 1340a73ff510SHidetoshi Shimokawa login->lstate = lstate; 1341a73ff510SHidetoshi Shimokawa login->last_hi = 0xffff; 1342a73ff510SHidetoshi Shimokawa login->last_lo = 0xffffffff; 1343a73ff510SHidetoshi Shimokawa login->hold_sec = 1; 1344a73ff510SHidetoshi Shimokawa STAILQ_INIT(&login->orbs); 1345a73ff510SHidetoshi Shimokawa CALLOUT_INIT(&login->hold_callout); 1346a73ff510SHidetoshi Shimokawa sc->logins[i] = login; 1347a73ff510SHidetoshi Shimokawa return (login); 1348a73ff510SHidetoshi Shimokawa } 1349a73ff510SHidetoshi Shimokawa 1350e9e688e2SHidetoshi Shimokawa static void 1351e9e688e2SHidetoshi Shimokawa sbp_targ_mgm_handler(struct fw_xfer *xfer) 1352e9e688e2SHidetoshi Shimokawa { 1353e9e688e2SHidetoshi Shimokawa struct sbp_targ_lstate *lstate; 1354a73ff510SHidetoshi Shimokawa struct sbp_targ_login *login; 1355e9e688e2SHidetoshi Shimokawa struct fw_pkt *fp; 135603161bbcSDoug Rabson uint32_t *orb; 1357e9e688e2SHidetoshi Shimokawa struct morb4 *orb4; 1358e9e688e2SHidetoshi Shimokawa struct orb_info *orbi; 1359e9e688e2SHidetoshi Shimokawa int i; 1360e9e688e2SHidetoshi Shimokawa 1361e9e688e2SHidetoshi Shimokawa orbi = (struct orb_info *)xfer->sc; 1362e9e688e2SHidetoshi Shimokawa if (xfer->resp != 0) { 136310d3ed64SHidetoshi Shimokawa printf("%s: xfer->resp = %d\n", __func__, xfer->resp); 1364e9e688e2SHidetoshi Shimokawa orbi->status.resp = SBP_TRANS_FAIL; 13651398a889SHidetoshi Shimokawa orbi->status.status = OBJ_ORB | SBE_TIMEOUT/*XXX*/; 1366e9e688e2SHidetoshi Shimokawa orbi->status.dead = 1; 1367e9e688e2SHidetoshi Shimokawa orbi->status.len = 1; 13689950b741SHidetoshi Shimokawa sbp_targ_abort(orbi->sc, STAILQ_NEXT(orbi, link)); 1369e9e688e2SHidetoshi Shimokawa 1370e9e688e2SHidetoshi Shimokawa sbp_targ_status_FIFO(orbi, 1371a73ff510SHidetoshi Shimokawa orbi->login->fifo_hi, orbi->login->fifo_lo, /*dequeue*/0); 1372e9e688e2SHidetoshi Shimokawa fw_xfer_free(xfer); 1373e9e688e2SHidetoshi Shimokawa return; 1374e9e688e2SHidetoshi Shimokawa } 1375e9e688e2SHidetoshi Shimokawa fp = &xfer->recv.hdr; 1376e9e688e2SHidetoshi Shimokawa 1377e9e688e2SHidetoshi Shimokawa orb = orbi->orb; 1378e9e688e2SHidetoshi Shimokawa /* swap payload */ 1379e9e688e2SHidetoshi Shimokawa for (i = 0; i < 8; i ++) { 1380e9e688e2SHidetoshi Shimokawa orb[i] = ntohl(orb[i]); 1381e9e688e2SHidetoshi Shimokawa } 1382e9e688e2SHidetoshi Shimokawa orb4 = (struct morb4 *)&orb[4]; 1383e9e688e2SHidetoshi Shimokawa if (debug) 138410d3ed64SHidetoshi Shimokawa printf("%s: %s\n", __func__, orb_fun_name[orb4->fun]); 1385e9e688e2SHidetoshi Shimokawa 1386e9e688e2SHidetoshi Shimokawa orbi->status.src = SRC_NO_NEXT; 1387e9e688e2SHidetoshi Shimokawa 1388e9e688e2SHidetoshi Shimokawa switch (orb4->fun << 16) { 1389e9e688e2SHidetoshi Shimokawa case ORB_FUN_LGI: 1390e9e688e2SHidetoshi Shimokawa { 1391a73ff510SHidetoshi Shimokawa int exclusive = 0, lun; 1392e9e688e2SHidetoshi Shimokawa 1393a73ff510SHidetoshi Shimokawa if (orb[4] & ORB_EXV) 1394a73ff510SHidetoshi Shimokawa exclusive = 1; 1395a73ff510SHidetoshi Shimokawa 1396a73ff510SHidetoshi Shimokawa lun = orb4->id; 1397a73ff510SHidetoshi Shimokawa lstate = orbi->sc->lstate[lun]; 1398a73ff510SHidetoshi Shimokawa 1399a73ff510SHidetoshi Shimokawa if (lun >= MAX_LUN || lstate == NULL || 1400a73ff510SHidetoshi Shimokawa (exclusive && 1401a73ff510SHidetoshi Shimokawa STAILQ_FIRST(&lstate->logins) != NULL && 1402a73ff510SHidetoshi Shimokawa STAILQ_FIRST(&lstate->logins)->fwdev != orbi->fwdev) 1403a73ff510SHidetoshi Shimokawa ) { 1404e9e688e2SHidetoshi Shimokawa /* error */ 1405e9e688e2SHidetoshi Shimokawa orbi->status.dead = 1; 1406e9e688e2SHidetoshi Shimokawa orbi->status.status = STATUS_ACCESS_DENY; 1407e9e688e2SHidetoshi Shimokawa orbi->status.len = 1; 1408e9e688e2SHidetoshi Shimokawa break; 1409e9e688e2SHidetoshi Shimokawa } 1410a73ff510SHidetoshi Shimokawa 1411a73ff510SHidetoshi Shimokawa /* allocate login */ 1412a73ff510SHidetoshi Shimokawa login = sbp_targ_get_login(orbi->sc, orbi->fwdev, lun); 1413a73ff510SHidetoshi Shimokawa if (login == NULL) { 1414a73ff510SHidetoshi Shimokawa printf("%s: sbp_targ_get_login failed\n", 141510d3ed64SHidetoshi Shimokawa __func__); 1416a73ff510SHidetoshi Shimokawa orbi->status.dead = 1; 1417a73ff510SHidetoshi Shimokawa orbi->status.status = STATUS_RES_UNAVAIL; 1418a73ff510SHidetoshi Shimokawa orbi->status.len = 1; 1419a73ff510SHidetoshi Shimokawa break; 1420a73ff510SHidetoshi Shimokawa } 14219950b741SHidetoshi Shimokawa printf("%s: login id=%d\n", __func__, login->id); 1422a73ff510SHidetoshi Shimokawa 1423a73ff510SHidetoshi Shimokawa login->fifo_hi = orb[6]; 1424a73ff510SHidetoshi Shimokawa login->fifo_lo = orb[7]; 142503161bbcSDoug Rabson login->loginres.len = htons(sizeof(uint32_t) * 4); 1426a73ff510SHidetoshi Shimokawa login->loginres.id = htons(login->id); 1427a73ff510SHidetoshi Shimokawa login->loginres.cmd_hi = htons(SBP_TARG_BIND_HI); 1428a73ff510SHidetoshi Shimokawa login->loginres.cmd_lo = htonl(SBP_TARG_BIND_LO(login->id)); 1429a73ff510SHidetoshi Shimokawa login->loginres.recon_hold = htons(login->hold_sec); 1430a73ff510SHidetoshi Shimokawa 14319950b741SHidetoshi Shimokawa STAILQ_INSERT_TAIL(&lstate->logins, login, link); 1432e9e688e2SHidetoshi Shimokawa fwmem_write_block(orbi->fwdev, NULL, /*spd*/2, orb[2], orb[3], 1433a73ff510SHidetoshi Shimokawa sizeof(struct sbp_login_res), (void *)&login->loginres, 1434e9e688e2SHidetoshi Shimokawa fw_asy_callback_free); 1435c54d1fe2SHidetoshi Shimokawa /* XXX return status after loginres is successfully written */ 1436e9e688e2SHidetoshi Shimokawa break; 1437e9e688e2SHidetoshi Shimokawa } 1438e9e688e2SHidetoshi Shimokawa case ORB_FUN_RCN: 1439a73ff510SHidetoshi Shimokawa login = orbi->sc->logins[orb4->id]; 1440a73ff510SHidetoshi Shimokawa if (login != NULL && login->fwdev == orbi->fwdev) { 1441a73ff510SHidetoshi Shimokawa login->flags &= ~F_HOLD; 1442a73ff510SHidetoshi Shimokawa callout_stop(&login->hold_callout); 1443a73ff510SHidetoshi Shimokawa printf("%s: reconnected id=%d\n", 144410d3ed64SHidetoshi Shimokawa __func__, login->id); 1445a73ff510SHidetoshi Shimokawa } else { 1446e9e688e2SHidetoshi Shimokawa orbi->status.dead = 1; 1447e9e688e2SHidetoshi Shimokawa orbi->status.status = STATUS_ACCESS_DENY; 1448a73ff510SHidetoshi Shimokawa printf("%s: reconnection faild id=%d\n", 144910d3ed64SHidetoshi Shimokawa __func__, orb4->id); 1450a73ff510SHidetoshi Shimokawa } 1451a73ff510SHidetoshi Shimokawa break; 1452a73ff510SHidetoshi Shimokawa case ORB_FUN_LGO: 1453a73ff510SHidetoshi Shimokawa login = orbi->sc->logins[orb4->id]; 1454a73ff510SHidetoshi Shimokawa if (login->fwdev != orbi->fwdev) { 145510d3ed64SHidetoshi Shimokawa printf("%s: wrong initiator\n", __func__); 1456a73ff510SHidetoshi Shimokawa break; 1457a73ff510SHidetoshi Shimokawa } 1458a73ff510SHidetoshi Shimokawa sbp_targ_dealloc_login(login); 1459e9e688e2SHidetoshi Shimokawa break; 1460e9e688e2SHidetoshi Shimokawa default: 1461e9e688e2SHidetoshi Shimokawa printf("%s: %s not implemented yet\n", 146210d3ed64SHidetoshi Shimokawa __func__, orb_fun_name[orb4->fun]); 1463e9e688e2SHidetoshi Shimokawa break; 1464e9e688e2SHidetoshi Shimokawa } 1465e9e688e2SHidetoshi Shimokawa orbi->status.len = 1; 1466e9e688e2SHidetoshi Shimokawa sbp_targ_status_FIFO(orbi, orb[6], orb[7], /*dequeue*/0); 1467e9e688e2SHidetoshi Shimokawa fw_xfer_free(xfer); 1468e9e688e2SHidetoshi Shimokawa return; 1469e9e688e2SHidetoshi Shimokawa } 1470e9e688e2SHidetoshi Shimokawa 1471e9e688e2SHidetoshi Shimokawa static void 1472e9e688e2SHidetoshi Shimokawa sbp_targ_pointer_handler(struct fw_xfer *xfer) 1473e9e688e2SHidetoshi Shimokawa { 1474e9e688e2SHidetoshi Shimokawa struct orb_info *orbi; 147503161bbcSDoug Rabson uint32_t orb0, orb1; 1476e9e688e2SHidetoshi Shimokawa 1477e9e688e2SHidetoshi Shimokawa orbi = (struct orb_info *)xfer->sc; 1478e9e688e2SHidetoshi Shimokawa if (xfer->resp != 0) { 147910d3ed64SHidetoshi Shimokawa printf("%s: xfer->resp = %d\n", __func__, xfer->resp); 1480e9e688e2SHidetoshi Shimokawa goto done; 1481e9e688e2SHidetoshi Shimokawa } 1482e9e688e2SHidetoshi Shimokawa 1483e9e688e2SHidetoshi Shimokawa orb0 = ntohl(orbi->orb[0]); 1484e9e688e2SHidetoshi Shimokawa orb1 = ntohl(orbi->orb[1]); 1485e9e688e2SHidetoshi Shimokawa if ((orb0 & (1 << 31)) != 0) { 148610d3ed64SHidetoshi Shimokawa printf("%s: invalid pointer\n", __func__); 1487e9e688e2SHidetoshi Shimokawa goto done; 1488e9e688e2SHidetoshi Shimokawa } 1489a73ff510SHidetoshi Shimokawa sbp_targ_fetch_orb(orbi->login->lstate->sc, orbi->fwdev, 149003161bbcSDoug Rabson (uint16_t)orb0, orb1, orbi->login, FETCH_CMD); 1491e9e688e2SHidetoshi Shimokawa done: 1492e9e688e2SHidetoshi Shimokawa free(orbi, M_SBP_TARG); 1493e9e688e2SHidetoshi Shimokawa fw_xfer_free(xfer); 1494e9e688e2SHidetoshi Shimokawa return; 1495e9e688e2SHidetoshi Shimokawa } 1496e9e688e2SHidetoshi Shimokawa 1497e9e688e2SHidetoshi Shimokawa static void 1498e9e688e2SHidetoshi Shimokawa sbp_targ_fetch_orb(struct sbp_targ_softc *sc, struct fw_device *fwdev, 149903161bbcSDoug Rabson uint16_t orb_hi, uint32_t orb_lo, struct sbp_targ_login *login, 1500e9e688e2SHidetoshi Shimokawa int mode) 1501e9e688e2SHidetoshi Shimokawa { 1502e9e688e2SHidetoshi Shimokawa struct orb_info *orbi; 1503e9e688e2SHidetoshi Shimokawa 1504e9e688e2SHidetoshi Shimokawa if (debug) 150510d3ed64SHidetoshi Shimokawa printf("%s: fetch orb %04x:%08x\n", __func__, orb_hi, orb_lo); 1506e9e688e2SHidetoshi Shimokawa orbi = malloc(sizeof(struct orb_info), M_SBP_TARG, M_NOWAIT | M_ZERO); 1507e9e688e2SHidetoshi Shimokawa if (orbi == NULL) { 150810d3ed64SHidetoshi Shimokawa printf("%s: malloc failed\n", __func__); 1509e9e688e2SHidetoshi Shimokawa return; 1510e9e688e2SHidetoshi Shimokawa } 1511e9e688e2SHidetoshi Shimokawa orbi->sc = sc; 1512e9e688e2SHidetoshi Shimokawa orbi->fwdev = fwdev; 1513a73ff510SHidetoshi Shimokawa orbi->login = login; 1514e9e688e2SHidetoshi Shimokawa orbi->orb_hi = orb_hi; 1515e9e688e2SHidetoshi Shimokawa orbi->orb_lo = orb_lo; 1516e9e688e2SHidetoshi Shimokawa orbi->status.orb_hi = htons(orb_hi); 1517e9e688e2SHidetoshi Shimokawa orbi->status.orb_lo = htonl(orb_lo); 1518e9e688e2SHidetoshi Shimokawa 1519e9e688e2SHidetoshi Shimokawa switch (mode) { 1520e9e688e2SHidetoshi Shimokawa case FETCH_MGM: 1521e9e688e2SHidetoshi Shimokawa fwmem_read_block(fwdev, (void *)orbi, /*spd*/2, orb_hi, orb_lo, 152203161bbcSDoug Rabson sizeof(uint32_t) * 8, &orbi->orb[0], 1523e9e688e2SHidetoshi Shimokawa sbp_targ_mgm_handler); 1524e9e688e2SHidetoshi Shimokawa break; 1525e9e688e2SHidetoshi Shimokawa case FETCH_CMD: 1526e9e688e2SHidetoshi Shimokawa orbi->state = ORBI_STATUS_FETCH; 1527a73ff510SHidetoshi Shimokawa login->last_hi = orb_hi; 1528a73ff510SHidetoshi Shimokawa login->last_lo = orb_lo; 1529a73ff510SHidetoshi Shimokawa login->flags |= F_LINK_ACTIVE; 1530e9e688e2SHidetoshi Shimokawa /* dequeue */ 15319950b741SHidetoshi Shimokawa SBP_LOCK(sc); 1532e9e688e2SHidetoshi Shimokawa orbi->atio = (struct ccb_accept_tio *) 1533a73ff510SHidetoshi Shimokawa SLIST_FIRST(&login->lstate->accept_tios); 1534e9e688e2SHidetoshi Shimokawa if (orbi->atio == NULL) { 15359950b741SHidetoshi Shimokawa SBP_UNLOCK(sc); 153610d3ed64SHidetoshi Shimokawa printf("%s: no free atio\n", __func__); 1537a73ff510SHidetoshi Shimokawa login->lstate->flags |= F_ATIO_STARVED; 1538a73ff510SHidetoshi Shimokawa login->flags |= F_ATIO_STARVED; 1539a73ff510SHidetoshi Shimokawa #if 0 1540a73ff510SHidetoshi Shimokawa /* XXX ?? */ 1541a73ff510SHidetoshi Shimokawa login->fwdev = fwdev; 1542a73ff510SHidetoshi Shimokawa #endif 1543e9e688e2SHidetoshi Shimokawa break; 1544e9e688e2SHidetoshi Shimokawa } 1545a73ff510SHidetoshi Shimokawa SLIST_REMOVE_HEAD(&login->lstate->accept_tios, sim_links.sle); 15469950b741SHidetoshi Shimokawa STAILQ_INSERT_TAIL(&login->orbs, orbi, link); 15479950b741SHidetoshi Shimokawa SBP_UNLOCK(sc); 1548e9e688e2SHidetoshi Shimokawa fwmem_read_block(fwdev, (void *)orbi, /*spd*/2, orb_hi, orb_lo, 154903161bbcSDoug Rabson sizeof(uint32_t) * 8, &orbi->orb[0], 1550e9e688e2SHidetoshi Shimokawa sbp_targ_cmd_handler); 1551e9e688e2SHidetoshi Shimokawa break; 1552e9e688e2SHidetoshi Shimokawa case FETCH_POINTER: 1553e9e688e2SHidetoshi Shimokawa orbi->state = ORBI_STATUS_POINTER; 1554a73ff510SHidetoshi Shimokawa login->flags |= F_LINK_ACTIVE; 1555e9e688e2SHidetoshi Shimokawa fwmem_read_block(fwdev, (void *)orbi, /*spd*/2, orb_hi, orb_lo, 155603161bbcSDoug Rabson sizeof(uint32_t) * 2, &orbi->orb[0], 1557e9e688e2SHidetoshi Shimokawa sbp_targ_pointer_handler); 1558e9e688e2SHidetoshi Shimokawa break; 1559e9e688e2SHidetoshi Shimokawa default: 156010d3ed64SHidetoshi Shimokawa printf("%s: invalid mode %d\n", __func__, mode); 1561e9e688e2SHidetoshi Shimokawa } 1562e9e688e2SHidetoshi Shimokawa } 1563e9e688e2SHidetoshi Shimokawa 1564e9e688e2SHidetoshi Shimokawa static void 1565e9e688e2SHidetoshi Shimokawa sbp_targ_resp_callback(struct fw_xfer *xfer) 1566e9e688e2SHidetoshi Shimokawa { 1567e9e688e2SHidetoshi Shimokawa struct sbp_targ_softc *sc; 1568e9e688e2SHidetoshi Shimokawa int s; 1569e9e688e2SHidetoshi Shimokawa 1570e9e688e2SHidetoshi Shimokawa if (debug) 157110d3ed64SHidetoshi Shimokawa printf("%s: xfer=%p\n", __func__, xfer); 1572e9e688e2SHidetoshi Shimokawa sc = (struct sbp_targ_softc *)xfer->sc; 1573e9e688e2SHidetoshi Shimokawa fw_xfer_unload(xfer); 1574e9e688e2SHidetoshi Shimokawa xfer->recv.pay_len = SBP_TARG_RECV_LEN; 1575801167a8SHidetoshi Shimokawa xfer->hand = sbp_targ_recv; 1576e9e688e2SHidetoshi Shimokawa s = splfw(); 1577e9e688e2SHidetoshi Shimokawa STAILQ_INSERT_TAIL(&sc->fwb.xferlist, xfer, link); 1578e9e688e2SHidetoshi Shimokawa splx(s); 1579e9e688e2SHidetoshi Shimokawa } 1580e9e688e2SHidetoshi Shimokawa 1581e9e688e2SHidetoshi Shimokawa static int 1582a73ff510SHidetoshi Shimokawa sbp_targ_cmd(struct fw_xfer *xfer, struct fw_device *fwdev, int login_id, 1583a73ff510SHidetoshi Shimokawa int reg) 1584e9e688e2SHidetoshi Shimokawa { 1585a73ff510SHidetoshi Shimokawa struct sbp_targ_login *login; 1586e9e688e2SHidetoshi Shimokawa struct sbp_targ_softc *sc; 1587e9e688e2SHidetoshi Shimokawa int rtcode = 0; 1588e9e688e2SHidetoshi Shimokawa 1589a73ff510SHidetoshi Shimokawa if (login_id < 0 || login_id >= MAX_LOGINS) 1590e9e688e2SHidetoshi Shimokawa return(RESP_ADDRESS_ERROR); 1591e9e688e2SHidetoshi Shimokawa 1592e9e688e2SHidetoshi Shimokawa sc = (struct sbp_targ_softc *)xfer->sc; 1593a73ff510SHidetoshi Shimokawa login = sc->logins[login_id]; 1594a73ff510SHidetoshi Shimokawa if (login == NULL) 1595e9e688e2SHidetoshi Shimokawa return(RESP_ADDRESS_ERROR); 1596e9e688e2SHidetoshi Shimokawa 1597a73ff510SHidetoshi Shimokawa if (login->fwdev != fwdev) { 1598a73ff510SHidetoshi Shimokawa /* XXX */ 1599a73ff510SHidetoshi Shimokawa return(RESP_ADDRESS_ERROR); 1600a73ff510SHidetoshi Shimokawa } 1601a73ff510SHidetoshi Shimokawa 1602e9e688e2SHidetoshi Shimokawa switch (reg) { 1603e9e688e2SHidetoshi Shimokawa case 0x08: /* ORB_POINTER */ 1604e9e688e2SHidetoshi Shimokawa if (debug) 16059950b741SHidetoshi Shimokawa printf("%s: ORB_POINTER(%d)\n", __func__, login_id); 1606a73ff510SHidetoshi Shimokawa if ((login->flags & F_LINK_ACTIVE) != 0) { 1607a73ff510SHidetoshi Shimokawa if (debug) 1608a73ff510SHidetoshi Shimokawa printf("link active (ORB_POINTER)\n"); 1609a73ff510SHidetoshi Shimokawa break; 1610a73ff510SHidetoshi Shimokawa } 1611a73ff510SHidetoshi Shimokawa sbp_targ_fetch_orb(sc, fwdev, 1612e9e688e2SHidetoshi Shimokawa ntohl(xfer->recv.payload[0]), 1613e9e688e2SHidetoshi Shimokawa ntohl(xfer->recv.payload[1]), 1614a73ff510SHidetoshi Shimokawa login, FETCH_CMD); 1615e9e688e2SHidetoshi Shimokawa break; 1616e9e688e2SHidetoshi Shimokawa case 0x04: /* AGENT_RESET */ 1617e9e688e2SHidetoshi Shimokawa if (debug) 16189950b741SHidetoshi Shimokawa printf("%s: AGENT RESET(%d)\n", __func__, login_id); 1619a73ff510SHidetoshi Shimokawa login->last_hi = 0xffff; 1620a73ff510SHidetoshi Shimokawa login->last_lo = 0xffffffff; 16219950b741SHidetoshi Shimokawa sbp_targ_abort(sc, STAILQ_FIRST(&login->orbs)); 1622e9e688e2SHidetoshi Shimokawa break; 1623e9e688e2SHidetoshi Shimokawa case 0x10: /* DOORBELL */ 1624e9e688e2SHidetoshi Shimokawa if (debug) 16259950b741SHidetoshi Shimokawa printf("%s: DOORBELL(%d)\n", __func__, login_id); 1626a73ff510SHidetoshi Shimokawa if (login->last_hi == 0xffff && 1627a73ff510SHidetoshi Shimokawa login->last_lo == 0xffffffff) { 1628e9e688e2SHidetoshi Shimokawa printf("%s: no previous pointer(DOORBELL)\n", 162910d3ed64SHidetoshi Shimokawa __func__); 1630e9e688e2SHidetoshi Shimokawa break; 1631e9e688e2SHidetoshi Shimokawa } 1632a73ff510SHidetoshi Shimokawa if ((login->flags & F_LINK_ACTIVE) != 0) { 1633e9e688e2SHidetoshi Shimokawa if (debug) 1634e9e688e2SHidetoshi Shimokawa printf("link active (DOORBELL)\n"); 1635e9e688e2SHidetoshi Shimokawa break; 1636e9e688e2SHidetoshi Shimokawa } 1637a73ff510SHidetoshi Shimokawa sbp_targ_fetch_orb(sc, fwdev, 1638a73ff510SHidetoshi Shimokawa login->last_hi, login->last_lo, 1639a73ff510SHidetoshi Shimokawa login, FETCH_POINTER); 1640e9e688e2SHidetoshi Shimokawa break; 1641e9e688e2SHidetoshi Shimokawa case 0x00: /* AGENT_STATE */ 16429950b741SHidetoshi Shimokawa printf("%s: AGENT_STATE (%d:ignore)\n", __func__, login_id); 1643e9e688e2SHidetoshi Shimokawa break; 1644e9e688e2SHidetoshi Shimokawa case 0x14: /* UNSOLICITED_STATE_ENABLE */ 16459950b741SHidetoshi Shimokawa printf("%s: UNSOLICITED_STATE_ENABLE (%d:ignore)\n", 16469950b741SHidetoshi Shimokawa __func__, login_id); 1647e9e688e2SHidetoshi Shimokawa break; 1648e9e688e2SHidetoshi Shimokawa default: 16499950b741SHidetoshi Shimokawa printf("%s: invalid register %d(%d)\n", 16509950b741SHidetoshi Shimokawa __func__, reg, login_id); 1651e9e688e2SHidetoshi Shimokawa rtcode = RESP_ADDRESS_ERROR; 1652e9e688e2SHidetoshi Shimokawa } 1653e9e688e2SHidetoshi Shimokawa 1654e9e688e2SHidetoshi Shimokawa return (rtcode); 1655e9e688e2SHidetoshi Shimokawa } 1656e9e688e2SHidetoshi Shimokawa 1657e9e688e2SHidetoshi Shimokawa static int 1658e9e688e2SHidetoshi Shimokawa sbp_targ_mgm(struct fw_xfer *xfer, struct fw_device *fwdev) 1659e9e688e2SHidetoshi Shimokawa { 1660e9e688e2SHidetoshi Shimokawa struct sbp_targ_softc *sc; 1661e9e688e2SHidetoshi Shimokawa struct fw_pkt *fp; 1662e9e688e2SHidetoshi Shimokawa 1663e9e688e2SHidetoshi Shimokawa sc = (struct sbp_targ_softc *)xfer->sc; 1664e9e688e2SHidetoshi Shimokawa 1665e9e688e2SHidetoshi Shimokawa fp = &xfer->recv.hdr; 1666e9e688e2SHidetoshi Shimokawa if (fp->mode.wreqb.tcode != FWTCODE_WREQB){ 166710d3ed64SHidetoshi Shimokawa printf("%s: tcode = %d\n", __func__, fp->mode.wreqb.tcode); 1668e9e688e2SHidetoshi Shimokawa return(RESP_TYPE_ERROR); 1669e9e688e2SHidetoshi Shimokawa } 1670e9e688e2SHidetoshi Shimokawa 1671e9e688e2SHidetoshi Shimokawa sbp_targ_fetch_orb(sc, fwdev, 1672e9e688e2SHidetoshi Shimokawa ntohl(xfer->recv.payload[0]), 1673e9e688e2SHidetoshi Shimokawa ntohl(xfer->recv.payload[1]), 1674e9e688e2SHidetoshi Shimokawa NULL, FETCH_MGM); 1675e9e688e2SHidetoshi Shimokawa 1676e9e688e2SHidetoshi Shimokawa return(0); 1677e9e688e2SHidetoshi Shimokawa } 1678e9e688e2SHidetoshi Shimokawa 1679e9e688e2SHidetoshi Shimokawa static void 1680e9e688e2SHidetoshi Shimokawa sbp_targ_recv(struct fw_xfer *xfer) 1681e9e688e2SHidetoshi Shimokawa { 1682e9e688e2SHidetoshi Shimokawa struct fw_pkt *fp, *sfp; 1683e9e688e2SHidetoshi Shimokawa struct fw_device *fwdev; 168403161bbcSDoug Rabson uint32_t lo; 1685e9e688e2SHidetoshi Shimokawa int s, rtcode; 1686e9e688e2SHidetoshi Shimokawa struct sbp_targ_softc *sc; 1687e9e688e2SHidetoshi Shimokawa 1688e9e688e2SHidetoshi Shimokawa s = splfw(); 1689e9e688e2SHidetoshi Shimokawa sc = (struct sbp_targ_softc *)xfer->sc; 1690e9e688e2SHidetoshi Shimokawa fp = &xfer->recv.hdr; 1691e9e688e2SHidetoshi Shimokawa fwdev = fw_noderesolve_nodeid(sc->fd.fc, fp->mode.wreqb.src & 0x3f); 1692e9e688e2SHidetoshi Shimokawa if (fwdev == NULL) { 1693e9e688e2SHidetoshi Shimokawa printf("%s: cannot resolve nodeid=%d\n", 169410d3ed64SHidetoshi Shimokawa __func__, fp->mode.wreqb.src & 0x3f); 1695e9e688e2SHidetoshi Shimokawa rtcode = RESP_TYPE_ERROR; /* XXX */ 1696e9e688e2SHidetoshi Shimokawa goto done; 1697e9e688e2SHidetoshi Shimokawa } 1698e9e688e2SHidetoshi Shimokawa lo = fp->mode.wreqb.dest_lo; 16999950b741SHidetoshi Shimokawa 1700e9e688e2SHidetoshi Shimokawa if (lo == SBP_TARG_BIND_LO(-1)) 1701e9e688e2SHidetoshi Shimokawa rtcode = sbp_targ_mgm(xfer, fwdev); 1702e9e688e2SHidetoshi Shimokawa else if (lo >= SBP_TARG_BIND_LO(0)) 1703a73ff510SHidetoshi Shimokawa rtcode = sbp_targ_cmd(xfer, fwdev, SBP_TARG_LOGIN_ID(lo), 1704a73ff510SHidetoshi Shimokawa lo % 0x20); 1705e9e688e2SHidetoshi Shimokawa else 1706e9e688e2SHidetoshi Shimokawa rtcode = RESP_ADDRESS_ERROR; 1707e9e688e2SHidetoshi Shimokawa 1708e9e688e2SHidetoshi Shimokawa done: 1709e9e688e2SHidetoshi Shimokawa if (rtcode != 0) 171010d3ed64SHidetoshi Shimokawa printf("%s: rtcode = %d\n", __func__, rtcode); 1711e9e688e2SHidetoshi Shimokawa sfp = &xfer->send.hdr; 1712e9e688e2SHidetoshi Shimokawa xfer->send.spd = 2; /* XXX */ 1713801167a8SHidetoshi Shimokawa xfer->hand = sbp_targ_resp_callback; 1714e9e688e2SHidetoshi Shimokawa sfp->mode.wres.dst = fp->mode.wreqb.src; 1715e9e688e2SHidetoshi Shimokawa sfp->mode.wres.tlrt = fp->mode.wreqb.tlrt; 1716e9e688e2SHidetoshi Shimokawa sfp->mode.wres.tcode = FWTCODE_WRES; 1717e9e688e2SHidetoshi Shimokawa sfp->mode.wres.rtcode = rtcode; 1718e9e688e2SHidetoshi Shimokawa sfp->mode.wres.pri = 0; 1719e9e688e2SHidetoshi Shimokawa 1720e9e688e2SHidetoshi Shimokawa fw_asyreq(xfer->fc, -1, xfer); 1721e9e688e2SHidetoshi Shimokawa splx(s); 1722e9e688e2SHidetoshi Shimokawa } 1723e9e688e2SHidetoshi Shimokawa 1724e9e688e2SHidetoshi Shimokawa static int 1725e9e688e2SHidetoshi Shimokawa sbp_targ_attach(device_t dev) 1726e9e688e2SHidetoshi Shimokawa { 1727e9e688e2SHidetoshi Shimokawa struct sbp_targ_softc *sc; 1728e9e688e2SHidetoshi Shimokawa struct cam_devq *devq; 17299950b741SHidetoshi Shimokawa struct firewire_comm *fc; 1730e9e688e2SHidetoshi Shimokawa 1731e9e688e2SHidetoshi Shimokawa sc = (struct sbp_targ_softc *) device_get_softc(dev); 1732e9e688e2SHidetoshi Shimokawa bzero((void *)sc, sizeof(struct sbp_targ_softc)); 1733e9e688e2SHidetoshi Shimokawa 17349950b741SHidetoshi Shimokawa mtx_init(&sc->mtx, "sbp_targ", NULL, MTX_DEF); 17359950b741SHidetoshi Shimokawa sc->fd.fc = fc = device_get_ivars(dev); 1736e9e688e2SHidetoshi Shimokawa sc->fd.dev = dev; 1737a73ff510SHidetoshi Shimokawa sc->fd.post_explore = (void *) sbp_targ_post_explore; 1738e9e688e2SHidetoshi Shimokawa sc->fd.post_busreset = (void *) sbp_targ_post_busreset; 1739e9e688e2SHidetoshi Shimokawa 1740c6cf3e20SHidetoshi Shimokawa devq = cam_simq_alloc(/*maxopenings*/MAX_LUN*MAX_INITIATORS); 1741e9e688e2SHidetoshi Shimokawa if (devq == NULL) 1742e9e688e2SHidetoshi Shimokawa return (ENXIO); 1743e9e688e2SHidetoshi Shimokawa 1744e9e688e2SHidetoshi Shimokawa sc->sim = cam_sim_alloc(sbp_targ_action, sbp_targ_poll, 17459950b741SHidetoshi Shimokawa "sbp_targ", sc, device_get_unit(dev), &sc->mtx, 1746e9e688e2SHidetoshi Shimokawa /*untagged*/ 1, /*tagged*/ 1, devq); 1747e9e688e2SHidetoshi Shimokawa if (sc->sim == NULL) { 1748e9e688e2SHidetoshi Shimokawa cam_simq_free(devq); 1749e9e688e2SHidetoshi Shimokawa return (ENXIO); 1750e9e688e2SHidetoshi Shimokawa } 1751e9e688e2SHidetoshi Shimokawa 17529950b741SHidetoshi Shimokawa SBP_LOCK(sc); 1753b50569b7SScott Long if (xpt_bus_register(sc->sim, dev, /*bus*/0) != CAM_SUCCESS) 1754e9e688e2SHidetoshi Shimokawa goto fail; 1755e9e688e2SHidetoshi Shimokawa 1756e9e688e2SHidetoshi Shimokawa if (xpt_create_path(&sc->path, /*periph*/ NULL, cam_sim_path(sc->sim), 1757e9e688e2SHidetoshi Shimokawa CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 1758e9e688e2SHidetoshi Shimokawa xpt_bus_deregister(cam_sim_path(sc->sim)); 1759e9e688e2SHidetoshi Shimokawa goto fail; 1760e9e688e2SHidetoshi Shimokawa } 17619950b741SHidetoshi Shimokawa SBP_UNLOCK(sc); 1762e9e688e2SHidetoshi Shimokawa 1763e9e688e2SHidetoshi Shimokawa sc->fwb.start = SBP_TARG_BIND_START; 1764e9e688e2SHidetoshi Shimokawa sc->fwb.end = SBP_TARG_BIND_END; 1765e9e688e2SHidetoshi Shimokawa 1766e9e688e2SHidetoshi Shimokawa /* pre-allocate xfer */ 1767e9e688e2SHidetoshi Shimokawa STAILQ_INIT(&sc->fwb.xferlist); 17680892f4c5SHidetoshi Shimokawa fw_xferlist_add(&sc->fwb.xferlist, M_SBP_TARG, 17690892f4c5SHidetoshi Shimokawa /*send*/ 0, /*recv*/ SBP_TARG_RECV_LEN, MAX_LUN /* XXX */, 17709950b741SHidetoshi Shimokawa fc, (void *)sc, sbp_targ_recv); 17719950b741SHidetoshi Shimokawa fw_bindadd(fc, &sc->fwb); 1772e9e688e2SHidetoshi Shimokawa return 0; 1773e9e688e2SHidetoshi Shimokawa 1774e9e688e2SHidetoshi Shimokawa fail: 17759950b741SHidetoshi Shimokawa SBP_UNLOCK(sc); 1776e9e688e2SHidetoshi Shimokawa cam_sim_free(sc->sim, /*free_devq*/TRUE); 1777e9e688e2SHidetoshi Shimokawa return (ENXIO); 1778e9e688e2SHidetoshi Shimokawa } 1779e9e688e2SHidetoshi Shimokawa 1780e9e688e2SHidetoshi Shimokawa static int 1781e9e688e2SHidetoshi Shimokawa sbp_targ_detach(device_t dev) 1782e9e688e2SHidetoshi Shimokawa { 1783e9e688e2SHidetoshi Shimokawa struct sbp_targ_softc *sc; 1784e9e688e2SHidetoshi Shimokawa struct sbp_targ_lstate *lstate; 1785e9e688e2SHidetoshi Shimokawa int i; 1786e9e688e2SHidetoshi Shimokawa 1787e9e688e2SHidetoshi Shimokawa sc = (struct sbp_targ_softc *)device_get_softc(dev); 1788e9e688e2SHidetoshi Shimokawa sc->fd.post_busreset = NULL; 1789e9e688e2SHidetoshi Shimokawa 17909950b741SHidetoshi Shimokawa SBP_LOCK(sc); 1791e9e688e2SHidetoshi Shimokawa xpt_free_path(sc->path); 1792e9e688e2SHidetoshi Shimokawa xpt_bus_deregister(cam_sim_path(sc->sim)); 17939950b741SHidetoshi Shimokawa SBP_UNLOCK(sc); 1794e9e688e2SHidetoshi Shimokawa cam_sim_free(sc->sim, /*free_devq*/TRUE); 1795e9e688e2SHidetoshi Shimokawa 1796e9e688e2SHidetoshi Shimokawa for (i = 0; i < MAX_LUN; i ++) { 1797e9e688e2SHidetoshi Shimokawa lstate = sc->lstate[i]; 1798e9e688e2SHidetoshi Shimokawa if (lstate != NULL) { 1799e9e688e2SHidetoshi Shimokawa xpt_free_path(lstate->path); 1800e9e688e2SHidetoshi Shimokawa free(lstate, M_SBP_TARG); 1801e9e688e2SHidetoshi Shimokawa } 1802e9e688e2SHidetoshi Shimokawa } 1803e9e688e2SHidetoshi Shimokawa if (sc->black_hole != NULL) { 1804e9e688e2SHidetoshi Shimokawa xpt_free_path(sc->black_hole->path); 1805e9e688e2SHidetoshi Shimokawa free(sc->black_hole, M_SBP_TARG); 1806e9e688e2SHidetoshi Shimokawa } 1807e9e688e2SHidetoshi Shimokawa 1808e9e688e2SHidetoshi Shimokawa fw_bindremove(sc->fd.fc, &sc->fwb); 18090892f4c5SHidetoshi Shimokawa fw_xferlist_remove(&sc->fwb.xferlist); 1810e9e688e2SHidetoshi Shimokawa 18119950b741SHidetoshi Shimokawa mtx_destroy(&sc->mtx); 18129950b741SHidetoshi Shimokawa 1813e9e688e2SHidetoshi Shimokawa return 0; 1814e9e688e2SHidetoshi Shimokawa } 1815e9e688e2SHidetoshi Shimokawa 1816e9e688e2SHidetoshi Shimokawa static devclass_t sbp_targ_devclass; 1817e9e688e2SHidetoshi Shimokawa 1818e9e688e2SHidetoshi Shimokawa static device_method_t sbp_targ_methods[] = { 1819e9e688e2SHidetoshi Shimokawa /* device interface */ 1820e9e688e2SHidetoshi Shimokawa DEVMETHOD(device_identify, sbp_targ_identify), 1821e9e688e2SHidetoshi Shimokawa DEVMETHOD(device_probe, sbp_targ_probe), 1822e9e688e2SHidetoshi Shimokawa DEVMETHOD(device_attach, sbp_targ_attach), 1823e9e688e2SHidetoshi Shimokawa DEVMETHOD(device_detach, sbp_targ_detach), 1824e9e688e2SHidetoshi Shimokawa { 0, 0 } 1825e9e688e2SHidetoshi Shimokawa }; 1826e9e688e2SHidetoshi Shimokawa 1827e9e688e2SHidetoshi Shimokawa static driver_t sbp_targ_driver = { 1828e9e688e2SHidetoshi Shimokawa "sbp_targ", 1829e9e688e2SHidetoshi Shimokawa sbp_targ_methods, 1830e9e688e2SHidetoshi Shimokawa sizeof(struct sbp_targ_softc), 1831e9e688e2SHidetoshi Shimokawa }; 1832e9e688e2SHidetoshi Shimokawa 1833e9e688e2SHidetoshi Shimokawa DRIVER_MODULE(sbp_targ, firewire, sbp_targ_driver, sbp_targ_devclass, 0, 0); 1834e9e688e2SHidetoshi Shimokawa MODULE_VERSION(sbp_targ, 1); 1835e9e688e2SHidetoshi Shimokawa MODULE_DEPEND(sbp_targ, firewire, 1, 1, 1); 1836e9e688e2SHidetoshi Shimokawa MODULE_DEPEND(sbp_targ, cam, 1, 1, 1); 1837