1139749Simp/*- 2121186Ssimokawa * Copyright (C) 2003 3121186Ssimokawa * Hidetoshi Shimokawa. All rights reserved. 4121186Ssimokawa * 5121186Ssimokawa * Redistribution and use in source and binary forms, with or without 6121186Ssimokawa * modification, are permitted provided that the following conditions 7121186Ssimokawa * are met: 8121186Ssimokawa * 1. Redistributions of source code must retain the above copyright 9121186Ssimokawa * notice, this list of conditions and the following disclaimer. 10121186Ssimokawa * 2. Redistributions in binary form must reproduce the above copyright 11121186Ssimokawa * notice, this list of conditions and the following disclaimer in the 12121186Ssimokawa * documentation and/or other materials provided with the distribution. 13121186Ssimokawa * 3. All advertising materials mentioning features or use of this software 14121186Ssimokawa * must display the following acknowledgement: 15121186Ssimokawa * 16121186Ssimokawa * This product includes software developed by Hidetoshi Shimokawa. 17121186Ssimokawa * 18121186Ssimokawa * 4. Neither the name of the author nor the names of its contributors 19121186Ssimokawa * may be used to endorse or promote products derived from this software 20121186Ssimokawa * without specific prior written permission. 21121186Ssimokawa * 22121186Ssimokawa * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23121186Ssimokawa * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24121186Ssimokawa * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25121186Ssimokawa * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26121186Ssimokawa * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27121186Ssimokawa * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28121186Ssimokawa * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29121186Ssimokawa * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30121186Ssimokawa * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31121186Ssimokawa * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32121186Ssimokawa * SUCH DAMAGE. 33121186Ssimokawa * 34121186Ssimokawa * $FreeBSD$ 35121186Ssimokawa */ 36121186Ssimokawa 37121186Ssimokawa#include <sys/param.h> 38121186Ssimokawa#include <sys/kernel.h> 39121186Ssimokawa#include <sys/systm.h> 40121186Ssimokawa#include <sys/sysctl.h> 41121186Ssimokawa#include <sys/types.h> 42121186Ssimokawa#include <sys/conf.h> 43121186Ssimokawa#include <sys/malloc.h> 44226067Sken#include <sys/endian.h> 45121186Ssimokawa#if __FreeBSD_version < 500000 46121186Ssimokawa#include <sys/devicestat.h> 47121186Ssimokawa#endif 48121186Ssimokawa 49121186Ssimokawa#include <sys/bus.h> 50121186Ssimokawa#include <machine/bus.h> 51121186Ssimokawa 52121186Ssimokawa#include <dev/firewire/firewire.h> 53121186Ssimokawa#include <dev/firewire/firewirereg.h> 54121186Ssimokawa#include <dev/firewire/iec13213.h> 55121186Ssimokawa#include <dev/firewire/sbp.h> 56121186Ssimokawa#include <dev/firewire/fwmem.h> 57121186Ssimokawa 58121186Ssimokawa#include <cam/cam.h> 59121186Ssimokawa#include <cam/cam_ccb.h> 60121186Ssimokawa#include <cam/cam_sim.h> 61121186Ssimokawa#include <cam/cam_xpt_sim.h> 62121186Ssimokawa#include <cam/cam_debug.h> 63121186Ssimokawa#include <cam/cam_periph.h> 64121186Ssimokawa#include <cam/scsi/scsi_all.h> 65121186Ssimokawa 66123430Ssimokawa#define SBP_TARG_RECV_LEN 8 67123430Ssimokawa#define MAX_INITIATORS 8 68123430Ssimokawa#define MAX_LUN 63 69123430Ssimokawa#define MAX_LOGINS 63 70123430Ssimokawa#define MAX_NODES 63 71121186Ssimokawa/* 72121186Ssimokawa * management/command block agent registers 73121186Ssimokawa * 74121186Ssimokawa * BASE 0xffff f001 0000 management port 75123430Ssimokawa * BASE 0xffff f001 0020 command port for login id 0 76123430Ssimokawa * BASE 0xffff f001 0040 command port for login id 1 77121186Ssimokawa * 78121186Ssimokawa */ 79121186Ssimokawa#define SBP_TARG_MGM 0x10000 /* offset from 0xffff f000 000 */ 80121186Ssimokawa#define SBP_TARG_BIND_HI 0xffff 81121186Ssimokawa#define SBP_TARG_BIND_LO(l) (0xf0000000 + SBP_TARG_MGM + 0x20 * ((l) + 1)) 82121186Ssimokawa#define SBP_TARG_BIND_START (((u_int64_t)SBP_TARG_BIND_HI << 32) | \ 83121186Ssimokawa SBP_TARG_BIND_LO(-1)) 84121186Ssimokawa#define SBP_TARG_BIND_END (((u_int64_t)SBP_TARG_BIND_HI << 32) | \ 85123430Ssimokawa SBP_TARG_BIND_LO(MAX_LOGINS)) 86123430Ssimokawa#define SBP_TARG_LOGIN_ID(lo) (((lo) - SBP_TARG_BIND_LO(0))/0x20) 87121186Ssimokawa 88121186Ssimokawa#define FETCH_MGM 0 89121186Ssimokawa#define FETCH_CMD 1 90121186Ssimokawa#define FETCH_POINTER 2 91121186Ssimokawa 92123430Ssimokawa#define F_LINK_ACTIVE (1 << 0) 93123430Ssimokawa#define F_ATIO_STARVED (1 << 1) 94123430Ssimokawa#define F_LOGIN (1 << 2) 95123430Ssimokawa#define F_HOLD (1 << 3) 96123430Ssimokawa#define F_FREEZED (1 << 4) 97123430Ssimokawa 98249132Smavstatic MALLOC_DEFINE(M_SBP_TARG, "sbp_targ", "SBP-II/FireWire target mode"); 99121186Ssimokawa 100121186Ssimokawastatic int debug = 0; 101121186Ssimokawa 102121186SsimokawaSYSCTL_INT(_debug, OID_AUTO, sbp_targ_debug, CTLFLAG_RW, &debug, 0, 103121186Ssimokawa "SBP target mode debug flag"); 104121186Ssimokawa 105123430Ssimokawastruct sbp_targ_login { 106123430Ssimokawa struct sbp_targ_lstate *lstate; 107123430Ssimokawa struct fw_device *fwdev; 108123430Ssimokawa struct sbp_login_res loginres; 109129585Sdfr uint16_t fifo_hi; 110129585Sdfr uint16_t last_hi; 111129585Sdfr uint32_t fifo_lo; 112129585Sdfr uint32_t last_lo; 113123430Ssimokawa STAILQ_HEAD(, orb_info) orbs; 114124877Ssimokawa STAILQ_ENTRY(sbp_targ_login) link; 115129585Sdfr uint16_t hold_sec; 116129585Sdfr uint16_t id; 117129585Sdfr uint8_t flags; 118129585Sdfr uint8_t spd; 119123430Ssimokawa struct callout hold_callout; 120123430Ssimokawa}; 121123430Ssimokawa 122123430Ssimokawastruct sbp_targ_lstate { 123129585Sdfr uint16_t lun; 124123430Ssimokawa struct sbp_targ_softc *sc; 125123430Ssimokawa struct cam_path *path; 126123430Ssimokawa struct ccb_hdr_slist accept_tios; 127123430Ssimokawa struct ccb_hdr_slist immed_notifies; 128123430Ssimokawa struct crom_chunk model; 129129585Sdfr uint32_t flags; 130123430Ssimokawa STAILQ_HEAD(, sbp_targ_login) logins; 131123430Ssimokawa}; 132123430Ssimokawa 133121186Ssimokawastruct sbp_targ_softc { 134121186Ssimokawa struct firewire_dev_comm fd; 135121186Ssimokawa struct cam_sim *sim; 136121186Ssimokawa struct cam_path *path; 137121186Ssimokawa struct fw_bind fwb; 138121186Ssimokawa int ndevs; 139123430Ssimokawa int flags; 140121186Ssimokawa struct crom_chunk unit; 141121186Ssimokawa struct sbp_targ_lstate *lstate[MAX_LUN]; 142121186Ssimokawa struct sbp_targ_lstate *black_hole; 143123430Ssimokawa struct sbp_targ_login *logins[MAX_LOGINS]; 144170374Ssimokawa struct mtx mtx; 145121186Ssimokawa}; 146170374Ssimokawa#define SBP_LOCK(sc) mtx_lock(&(sc)->mtx) 147170374Ssimokawa#define SBP_UNLOCK(sc) mtx_unlock(&(sc)->mtx) 148121186Ssimokawa 149121186Ssimokawastruct corb4 { 150121186Ssimokawa#if BYTE_ORDER == BIG_ENDIAN 151129585Sdfr uint32_t n:1, 152121186Ssimokawa rq_fmt:2, 153121186Ssimokawa :1, 154121186Ssimokawa dir:1, 155121186Ssimokawa spd:3, 156121186Ssimokawa max_payload:4, 157121186Ssimokawa page_table_present:1, 158121186Ssimokawa page_size:3, 159121186Ssimokawa data_size:16; 160121186Ssimokawa#else 161129585Sdfr uint32_t data_size:16, 162121186Ssimokawa page_size:3, 163121186Ssimokawa page_table_present:1, 164121186Ssimokawa max_payload:4, 165121186Ssimokawa spd:3, 166121186Ssimokawa dir:1, 167121186Ssimokawa :1, 168121186Ssimokawa rq_fmt:2, 169121186Ssimokawa n:1; 170121186Ssimokawa#endif 171121186Ssimokawa}; 172121186Ssimokawa 173121186Ssimokawastruct morb4 { 174121186Ssimokawa#if BYTE_ORDER == BIG_ENDIAN 175129585Sdfr uint32_t n:1, 176121186Ssimokawa rq_fmt:2, 177121186Ssimokawa :9, 178121186Ssimokawa fun:4, 179121186Ssimokawa id:16; 180121186Ssimokawa#else 181129585Sdfr uint32_t id:16, 182121186Ssimokawa fun:4, 183121186Ssimokawa :9, 184121186Ssimokawa rq_fmt:2, 185121186Ssimokawa n:1; 186121186Ssimokawa#endif 187121186Ssimokawa}; 188121186Ssimokawa 189121186Ssimokawastruct orb_info { 190121186Ssimokawa struct sbp_targ_softc *sc; 191121186Ssimokawa struct fw_device *fwdev; 192123430Ssimokawa struct sbp_targ_login *login; 193121186Ssimokawa union ccb *ccb; 194121186Ssimokawa struct ccb_accept_tio *atio; 195129585Sdfr uint8_t state; 196121186Ssimokawa#define ORBI_STATUS_NONE 0 197121186Ssimokawa#define ORBI_STATUS_FETCH 1 198121186Ssimokawa#define ORBI_STATUS_ATIO 2 199121186Ssimokawa#define ORBI_STATUS_CTIO 3 200121186Ssimokawa#define ORBI_STATUS_STATUS 4 201121186Ssimokawa#define ORBI_STATUS_POINTER 5 202121186Ssimokawa#define ORBI_STATUS_ABORTED 7 203129585Sdfr uint8_t refcount; 204129585Sdfr uint16_t orb_hi; 205129585Sdfr uint32_t orb_lo; 206129585Sdfr uint32_t data_hi; 207129585Sdfr uint32_t data_lo; 208121186Ssimokawa struct corb4 orb4; 209121186Ssimokawa STAILQ_ENTRY(orb_info) link; 210129585Sdfr uint32_t orb[8]; 211129585Sdfr uint32_t *page_table; 212121186Ssimokawa struct sbp_status status; 213121186Ssimokawa}; 214121186Ssimokawa 215121186Ssimokawastatic char *orb_fun_name[] = { 216121186Ssimokawa ORB_FUN_NAMES 217121186Ssimokawa}; 218121186Ssimokawa 219121186Ssimokawastatic void sbp_targ_recv(struct fw_xfer *); 220121186Ssimokawastatic void sbp_targ_fetch_orb(struct sbp_targ_softc *, struct fw_device *, 221129585Sdfr uint16_t, uint32_t, struct sbp_targ_login *, int); 222170374Ssimokawastatic void sbp_targ_abort(struct sbp_targ_softc *, struct orb_info *); 223121186Ssimokawa 224121186Ssimokawastatic void 225121186Ssimokawasbp_targ_identify(driver_t *driver, device_t parent) 226121186Ssimokawa{ 227121186Ssimokawa BUS_ADD_CHILD(parent, 0, "sbp_targ", device_get_unit(parent)); 228121186Ssimokawa} 229121186Ssimokawa 230121186Ssimokawastatic int 231121186Ssimokawasbp_targ_probe(device_t dev) 232121186Ssimokawa{ 233121186Ssimokawa device_t pa; 234121186Ssimokawa 235121186Ssimokawa pa = device_get_parent(dev); 236121186Ssimokawa if(device_get_unit(dev) != device_get_unit(pa)){ 237121186Ssimokawa return(ENXIO); 238121186Ssimokawa } 239121186Ssimokawa 240121186Ssimokawa device_set_desc(dev, "SBP-2/SCSI over FireWire target mode"); 241121186Ssimokawa return (0); 242121186Ssimokawa} 243121186Ssimokawa 244121186Ssimokawastatic void 245123430Ssimokawasbp_targ_dealloc_login(struct sbp_targ_login *login) 246123430Ssimokawa{ 247123430Ssimokawa struct orb_info *orbi, *next; 248123430Ssimokawa 249123430Ssimokawa if (login == NULL) { 250127468Ssimokawa printf("%s: login = NULL\n", __func__); 251123430Ssimokawa return; 252123430Ssimokawa } 253123430Ssimokawa for (orbi = STAILQ_FIRST(&login->orbs); orbi != NULL; orbi = next) { 254123430Ssimokawa next = STAILQ_NEXT(orbi, link); 255123430Ssimokawa free(orbi, M_SBP_TARG); 256123430Ssimokawa } 257123430Ssimokawa callout_stop(&login->hold_callout); 258123430Ssimokawa 259123430Ssimokawa STAILQ_REMOVE(&login->lstate->logins, login, sbp_targ_login, link); 260123430Ssimokawa login->lstate->sc->logins[login->id] = NULL; 261123430Ssimokawa free((void *)login, M_SBP_TARG); 262123430Ssimokawa} 263123430Ssimokawa 264123430Ssimokawastatic void 265123430Ssimokawasbp_targ_hold_expire(void *arg) 266123430Ssimokawa{ 267123430Ssimokawa struct sbp_targ_login *login; 268123430Ssimokawa 269123430Ssimokawa login = (struct sbp_targ_login *)arg; 270123430Ssimokawa 271123430Ssimokawa if (login->flags & F_HOLD) { 272127468Ssimokawa printf("%s: login_id=%d expired\n", __func__, login->id); 273123430Ssimokawa sbp_targ_dealloc_login(login); 274123430Ssimokawa } else { 275127468Ssimokawa printf("%s: login_id=%d not hold\n", __func__, login->id); 276123430Ssimokawa } 277123430Ssimokawa} 278123430Ssimokawa 279123430Ssimokawastatic void 280121186Ssimokawasbp_targ_post_busreset(void *arg) 281121186Ssimokawa{ 282121186Ssimokawa struct sbp_targ_softc *sc; 283121186Ssimokawa struct crom_src *src; 284121186Ssimokawa struct crom_chunk *root; 285121186Ssimokawa struct crom_chunk *unit; 286121186Ssimokawa struct sbp_targ_lstate *lstate; 287123430Ssimokawa struct sbp_targ_login *login; 288121186Ssimokawa int i; 289121186Ssimokawa 290123430Ssimokawa sc = (struct sbp_targ_softc *)arg; 291121186Ssimokawa src = sc->fd.fc->crom_src; 292121186Ssimokawa root = sc->fd.fc->crom_root; 293121186Ssimokawa 294121186Ssimokawa unit = &sc->unit; 295121186Ssimokawa 296123430Ssimokawa if ((sc->flags & F_FREEZED) == 0) { 297170374Ssimokawa SBP_LOCK(sc); 298123430Ssimokawa sc->flags |= F_FREEZED; 299123430Ssimokawa xpt_freeze_simq(sc->sim, /*count*/1); 300170374Ssimokawa SBP_UNLOCK(sc); 301123430Ssimokawa } else { 302127468Ssimokawa printf("%s: already freezed\n", __func__); 303123430Ssimokawa } 304123430Ssimokawa 305121186Ssimokawa bzero(unit, sizeof(struct crom_chunk)); 306121186Ssimokawa 307121186Ssimokawa crom_add_chunk(src, root, unit, CROM_UDIR); 308121186Ssimokawa crom_add_entry(unit, CSRKEY_SPEC, CSRVAL_ANSIT10); 309121186Ssimokawa crom_add_entry(unit, CSRKEY_VER, CSRVAL_T10SBP2); 310121186Ssimokawa crom_add_entry(unit, CSRKEY_COM_SPEC, CSRVAL_ANSIT10); 311121186Ssimokawa crom_add_entry(unit, CSRKEY_COM_SET, CSRVAL_SCSI); 312121186Ssimokawa 313121186Ssimokawa crom_add_entry(unit, CROM_MGM, SBP_TARG_MGM >> 2); 314121186Ssimokawa crom_add_entry(unit, CSRKEY_UNIT_CH, (10<<8) | 8); 315121186Ssimokawa 316121186Ssimokawa for (i = 0; i < MAX_LUN; i ++) { 317121186Ssimokawa lstate = sc->lstate[i]; 318121186Ssimokawa if (lstate == NULL) 319121186Ssimokawa continue; 320121186Ssimokawa crom_add_entry(unit, CSRKEY_FIRM_VER, 1); 321121186Ssimokawa crom_add_entry(unit, CROM_LUN, i); 322121186Ssimokawa crom_add_entry(unit, CSRKEY_MODEL, 1); 323121186Ssimokawa crom_add_simple_text(src, unit, &lstate->model, "TargetMode"); 324121186Ssimokawa } 325123430Ssimokawa 326123430Ssimokawa /* Process for reconnection hold time */ 327123430Ssimokawa for (i = 0; i < MAX_LOGINS; i ++) { 328123430Ssimokawa login = sc->logins[i]; 329123430Ssimokawa if (login == NULL) 330123430Ssimokawa continue; 331170374Ssimokawa sbp_targ_abort(sc, STAILQ_FIRST(&login->orbs)); 332123430Ssimokawa if (login->flags & F_LOGIN) { 333123430Ssimokawa login->flags |= F_HOLD; 334123430Ssimokawa callout_reset(&login->hold_callout, 335123430Ssimokawa hz * login->hold_sec, 336123430Ssimokawa sbp_targ_hold_expire, (void *)login); 337123430Ssimokawa } 338123430Ssimokawa } 339121186Ssimokawa} 340121186Ssimokawa 341123430Ssimokawastatic void 342123430Ssimokawasbp_targ_post_explore(void *arg) 343123430Ssimokawa{ 344123430Ssimokawa struct sbp_targ_softc *sc; 345123430Ssimokawa 346123430Ssimokawa sc = (struct sbp_targ_softc *)arg; 347170374Ssimokawa SBP_LOCK(sc); 348123430Ssimokawa sc->flags &= ~F_FREEZED; 349123430Ssimokawa xpt_release_simq(sc->sim, /*run queue*/TRUE); 350170374Ssimokawa SBP_UNLOCK(sc); 351123430Ssimokawa return; 352123430Ssimokawa} 353123430Ssimokawa 354121186Ssimokawastatic cam_status 355121186Ssimokawasbp_targ_find_devs(struct sbp_targ_softc *sc, union ccb *ccb, 356121186Ssimokawa struct sbp_targ_lstate **lstate, int notfound_failure) 357121186Ssimokawa{ 358121186Ssimokawa u_int lun; 359121186Ssimokawa 360121186Ssimokawa /* XXX 0 is the only vaild target_id */ 361121186Ssimokawa if (ccb->ccb_h.target_id == CAM_TARGET_WILDCARD && 362121186Ssimokawa ccb->ccb_h.target_lun == CAM_LUN_WILDCARD) { 363121186Ssimokawa *lstate = sc->black_hole; 364121186Ssimokawa return (CAM_REQ_CMP); 365121186Ssimokawa } 366121186Ssimokawa 367121186Ssimokawa if (ccb->ccb_h.target_id != 0) 368121186Ssimokawa return (CAM_TID_INVALID); 369121186Ssimokawa 370121186Ssimokawa lun = ccb->ccb_h.target_lun; 371121186Ssimokawa if (lun >= MAX_LUN) 372121186Ssimokawa return (CAM_LUN_INVALID); 373121186Ssimokawa 374121186Ssimokawa *lstate = sc->lstate[lun]; 375121186Ssimokawa 376121186Ssimokawa if (notfound_failure != 0 && *lstate == NULL) 377121186Ssimokawa return (CAM_PATH_INVALID); 378121186Ssimokawa 379121186Ssimokawa return (CAM_REQ_CMP); 380121186Ssimokawa} 381121186Ssimokawa 382121186Ssimokawastatic void 383121186Ssimokawasbp_targ_en_lun(struct sbp_targ_softc *sc, union ccb *ccb) 384121186Ssimokawa{ 385121186Ssimokawa struct ccb_en_lun *cel = &ccb->cel; 386121186Ssimokawa struct sbp_targ_lstate *lstate; 387121186Ssimokawa cam_status status; 388121186Ssimokawa 389121186Ssimokawa status = sbp_targ_find_devs(sc, ccb, &lstate, 0); 390121186Ssimokawa if (status != CAM_REQ_CMP) { 391121186Ssimokawa ccb->ccb_h.status = status; 392121186Ssimokawa return; 393121186Ssimokawa } 394121186Ssimokawa 395121186Ssimokawa if (cel->enable != 0) { 396121186Ssimokawa if (lstate != NULL) { 397121186Ssimokawa xpt_print_path(ccb->ccb_h.path); 398121186Ssimokawa printf("Lun already enabled\n"); 399121186Ssimokawa ccb->ccb_h.status = CAM_LUN_ALRDY_ENA; 400121186Ssimokawa return; 401121186Ssimokawa } 402121186Ssimokawa if (cel->grp6_len != 0 || cel->grp7_len != 0) { 403121186Ssimokawa ccb->ccb_h.status = CAM_REQ_INVALID; 404121186Ssimokawa printf("Non-zero Group Codes\n"); 405121186Ssimokawa return; 406121186Ssimokawa } 407121186Ssimokawa lstate = (struct sbp_targ_lstate *) 408121186Ssimokawa malloc(sizeof(*lstate), M_SBP_TARG, M_NOWAIT | M_ZERO); 409121186Ssimokawa if (lstate == NULL) { 410121186Ssimokawa xpt_print_path(ccb->ccb_h.path); 411121186Ssimokawa printf("Couldn't allocate lstate\n"); 412121186Ssimokawa ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 413121186Ssimokawa return; 414121186Ssimokawa } 415121186Ssimokawa if (ccb->ccb_h.target_id == CAM_TARGET_WILDCARD) 416121186Ssimokawa sc->black_hole = lstate; 417121186Ssimokawa else 418121186Ssimokawa sc->lstate[ccb->ccb_h.target_lun] = lstate; 419121186Ssimokawa memset(lstate, 0, sizeof(*lstate)); 420121186Ssimokawa lstate->sc = sc; 421121186Ssimokawa status = xpt_create_path(&lstate->path, /*periph*/NULL, 422121186Ssimokawa xpt_path_path_id(ccb->ccb_h.path), 423121186Ssimokawa xpt_path_target_id(ccb->ccb_h.path), 424121186Ssimokawa xpt_path_lun_id(ccb->ccb_h.path)); 425121186Ssimokawa if (status != CAM_REQ_CMP) { 426121186Ssimokawa free(lstate, M_SBP_TARG); 427121186Ssimokawa xpt_print_path(ccb->ccb_h.path); 428121186Ssimokawa printf("Couldn't allocate path\n"); 429121186Ssimokawa ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 430121186Ssimokawa return; 431121186Ssimokawa } 432121186Ssimokawa SLIST_INIT(&lstate->accept_tios); 433121186Ssimokawa SLIST_INIT(&lstate->immed_notifies); 434123430Ssimokawa STAILQ_INIT(&lstate->logins); 435121186Ssimokawa 436121186Ssimokawa ccb->ccb_h.status = CAM_REQ_CMP; 437121186Ssimokawa xpt_print_path(ccb->ccb_h.path); 438121186Ssimokawa printf("Lun now enabled for target mode\n"); 439121186Ssimokawa /* bus reset */ 440121186Ssimokawa sc->fd.fc->ibr(sc->fd.fc); 441121186Ssimokawa } else { 442123430Ssimokawa struct sbp_targ_login *login, *next; 443123430Ssimokawa 444121186Ssimokawa if (lstate == NULL) { 445121186Ssimokawa ccb->ccb_h.status = CAM_LUN_INVALID; 446121186Ssimokawa return; 447121186Ssimokawa } 448121186Ssimokawa ccb->ccb_h.status = CAM_REQ_CMP; 449121186Ssimokawa 450121186Ssimokawa if (SLIST_FIRST(&lstate->accept_tios) != NULL) { 451121186Ssimokawa printf("ATIOs pending\n"); 452121186Ssimokawa ccb->ccb_h.status = CAM_REQ_INVALID; 453121186Ssimokawa } 454121186Ssimokawa 455121186Ssimokawa if (SLIST_FIRST(&lstate->immed_notifies) != NULL) { 456121186Ssimokawa printf("INOTs pending\n"); 457121186Ssimokawa ccb->ccb_h.status = CAM_REQ_INVALID; 458121186Ssimokawa } 459121186Ssimokawa 460121186Ssimokawa if (ccb->ccb_h.status != CAM_REQ_CMP) { 461121186Ssimokawa return; 462121186Ssimokawa } 463121186Ssimokawa 464121186Ssimokawa xpt_print_path(ccb->ccb_h.path); 465121186Ssimokawa printf("Target mode disabled\n"); 466121186Ssimokawa xpt_free_path(lstate->path); 467121186Ssimokawa 468123430Ssimokawa for (login = STAILQ_FIRST(&lstate->logins); login != NULL; 469123430Ssimokawa login = next) { 470123430Ssimokawa next = STAILQ_NEXT(login, link); 471123430Ssimokawa sbp_targ_dealloc_login(login); 472121186Ssimokawa } 473121186Ssimokawa 474121186Ssimokawa if (ccb->ccb_h.target_id == CAM_TARGET_WILDCARD) 475121186Ssimokawa sc->black_hole = NULL; 476121186Ssimokawa else 477121186Ssimokawa sc->lstate[ccb->ccb_h.target_lun] = NULL; 478121186Ssimokawa free(lstate, M_SBP_TARG); 479121186Ssimokawa 480121186Ssimokawa /* bus reset */ 481121186Ssimokawa sc->fd.fc->ibr(sc->fd.fc); 482121186Ssimokawa } 483121186Ssimokawa} 484121186Ssimokawa 485121186Ssimokawastatic void 486121186Ssimokawasbp_targ_send_lstate_events(struct sbp_targ_softc *sc, 487121186Ssimokawa struct sbp_targ_lstate *lstate) 488121186Ssimokawa{ 489121186Ssimokawa#if 0 490121186Ssimokawa struct ccb_hdr *ccbh; 491237825Sken struct ccb_immediate_notify *inot; 492121186Ssimokawa 493127468Ssimokawa printf("%s: not implemented yet\n", __func__); 494121186Ssimokawa#endif 495121186Ssimokawa} 496121186Ssimokawa 497170374Ssimokawa 498121186Ssimokawastatic __inline void 499170374Ssimokawasbp_targ_remove_orb_info_locked(struct sbp_targ_login *login, struct orb_info *orbi) 500170374Ssimokawa{ 501170374Ssimokawa STAILQ_REMOVE(&login->orbs, orbi, orb_info, link); 502170374Ssimokawa} 503170374Ssimokawa 504170374Ssimokawastatic __inline void 505123430Ssimokawasbp_targ_remove_orb_info(struct sbp_targ_login *login, struct orb_info *orbi) 506121186Ssimokawa{ 507170374Ssimokawa SBP_LOCK(orbi->sc); 508123430Ssimokawa STAILQ_REMOVE(&login->orbs, orbi, orb_info, link); 509170374Ssimokawa SBP_UNLOCK(orbi->sc); 510121186Ssimokawa} 511121186Ssimokawa 512121186Ssimokawa/* 513121186Ssimokawa * tag_id/init_id encoding 514121186Ssimokawa * 515121186Ssimokawa * tag_id and init_id has only 32bit for each. 516121186Ssimokawa * scsi_target can handle very limited number(up to 15) of init_id. 517121186Ssimokawa * we have to encode 48bit orb and 64bit EUI64 into these 518121186Ssimokawa * variables. 519121186Ssimokawa * 520121186Ssimokawa * tag_id represents lower 32bit of ORB address. 521123430Ssimokawa * init_id represents login_id. 522121186Ssimokawa * 523121186Ssimokawa */ 524121186Ssimokawa 525121186Ssimokawastatic struct orb_info * 526121186Ssimokawasbp_targ_get_orb_info(struct sbp_targ_lstate *lstate, 527121186Ssimokawa u_int tag_id, u_int init_id) 528121186Ssimokawa{ 529123430Ssimokawa struct sbp_targ_login *login; 530121186Ssimokawa struct orb_info *orbi; 531121186Ssimokawa 532123430Ssimokawa login = lstate->sc->logins[init_id]; 533123430Ssimokawa if (login == NULL) { 534127468Ssimokawa printf("%s: no such login\n", __func__); 535123430Ssimokawa return (NULL); 536123430Ssimokawa } 537123430Ssimokawa STAILQ_FOREACH(orbi, &login->orbs, link) 538123430Ssimokawa if (orbi->orb_lo == tag_id) 539121186Ssimokawa goto found; 540170374Ssimokawa printf("%s: orb not found tag_id=0x%08x init_id=%d\n", 541170374Ssimokawa __func__, tag_id, init_id); 542121186Ssimokawa return (NULL); 543121186Ssimokawafound: 544121186Ssimokawa return (orbi); 545121186Ssimokawa} 546121186Ssimokawa 547121186Ssimokawastatic void 548170374Ssimokawasbp_targ_abort(struct sbp_targ_softc *sc, struct orb_info *orbi) 549121186Ssimokawa{ 550121186Ssimokawa struct orb_info *norbi; 551121186Ssimokawa 552170374Ssimokawa SBP_LOCK(sc); 553121186Ssimokawa for (; orbi != NULL; orbi = norbi) { 554170374Ssimokawa printf("%s: status=%d ccb=%p\n", __func__, orbi->state, orbi->ccb); 555121186Ssimokawa norbi = STAILQ_NEXT(orbi, link); 556121186Ssimokawa if (orbi->state != ORBI_STATUS_ABORTED) { 557121186Ssimokawa if (orbi->ccb != NULL) { 558121186Ssimokawa orbi->ccb->ccb_h.status = CAM_REQ_ABORTED; 559121186Ssimokawa xpt_done(orbi->ccb); 560121186Ssimokawa orbi->ccb = NULL; 561121186Ssimokawa } 562170374Ssimokawa#if 0 563121186Ssimokawa if (orbi->state <= ORBI_STATUS_ATIO) { 564170374Ssimokawa sbp_targ_remove_orb_info_locked(orbi->login, orbi); 565121186Ssimokawa free(orbi, M_SBP_TARG); 566121186Ssimokawa } else 567170374Ssimokawa#endif 568121186Ssimokawa orbi->state = ORBI_STATUS_ABORTED; 569121186Ssimokawa } 570121186Ssimokawa } 571170374Ssimokawa SBP_UNLOCK(sc); 572121186Ssimokawa} 573121186Ssimokawa 574121186Ssimokawastatic void 575121186Ssimokawasbp_targ_free_orbi(struct fw_xfer *xfer) 576121186Ssimokawa{ 577121186Ssimokawa struct orb_info *orbi; 578121186Ssimokawa 579121186Ssimokawa orbi = (struct orb_info *)xfer->sc; 580121186Ssimokawa if (xfer->resp != 0) { 581121186Ssimokawa /* XXX */ 582127468Ssimokawa printf("%s: xfer->resp = %d\n", __func__, xfer->resp); 583121186Ssimokawa } 584121186Ssimokawa free(orbi, M_SBP_TARG); 585121186Ssimokawa fw_xfer_free(xfer); 586121186Ssimokawa} 587121186Ssimokawa 588121186Ssimokawastatic void 589121186Ssimokawasbp_targ_status_FIFO(struct orb_info *orbi, 590129585Sdfr uint32_t fifo_hi, uint32_t fifo_lo, int dequeue) 591121186Ssimokawa{ 592121186Ssimokawa struct fw_xfer *xfer; 593121186Ssimokawa 594121186Ssimokawa if (dequeue) 595123430Ssimokawa sbp_targ_remove_orb_info(orbi->login, orbi); 596121186Ssimokawa 597121186Ssimokawa xfer = fwmem_write_block(orbi->fwdev, (void *)orbi, 598121186Ssimokawa /*spd*/2, fifo_hi, fifo_lo, 599129585Sdfr sizeof(uint32_t) * (orbi->status.len + 1), (char *)&orbi->status, 600121186Ssimokawa sbp_targ_free_orbi); 601121186Ssimokawa 602121186Ssimokawa if (xfer == NULL) { 603121186Ssimokawa /* XXX */ 604127468Ssimokawa printf("%s: xfer == NULL\n", __func__); 605121186Ssimokawa } 606121186Ssimokawa} 607121186Ssimokawa 608121186Ssimokawastatic void 609121186Ssimokawasbp_targ_send_status(struct orb_info *orbi, union ccb *ccb) 610121186Ssimokawa{ 611121186Ssimokawa struct sbp_status *sbp_status; 612170410Smjacob#if 0 613170374Ssimokawa struct orb_info *norbi; 614170410Smjacob#endif 615121186Ssimokawa 616121186Ssimokawa sbp_status = &orbi->status; 617121186Ssimokawa 618121186Ssimokawa orbi->state = ORBI_STATUS_STATUS; 619121186Ssimokawa 620121186Ssimokawa sbp_status->resp = 0; /* XXX */ 621121186Ssimokawa sbp_status->status = 0; /* XXX */ 622121186Ssimokawa sbp_status->dead = 0; /* XXX */ 623121186Ssimokawa 624121186Ssimokawa switch (ccb->csio.scsi_status) { 625121186Ssimokawa case SCSI_STATUS_OK: 626121186Ssimokawa if (debug) 627127468Ssimokawa printf("%s: STATUS_OK\n", __func__); 628121186Ssimokawa sbp_status->len = 1; 629121186Ssimokawa break; 630121186Ssimokawa case SCSI_STATUS_CHECK_COND: 631121186Ssimokawa case SCSI_STATUS_BUSY: 632121186Ssimokawa case SCSI_STATUS_CMD_TERMINATED: 633121186Ssimokawa { 634121186Ssimokawa struct sbp_cmd_status *sbp_cmd_status; 635121186Ssimokawa struct scsi_sense_data *sense; 636226067Sken int error_code, sense_key, asc, ascq; 637226067Sken uint8_t stream_bits; 638226067Sken uint8_t sks[3]; 639226067Sken uint64_t info; 640226067Sken int64_t sinfo; 641226067Sken int sense_len; 642121186Ssimokawa 643121186Ssimokawa if (debug) 644127468Ssimokawa printf("%s: STATUS %d\n", __func__, 645121186Ssimokawa ccb->csio.scsi_status); 646121186Ssimokawa sbp_cmd_status = (struct sbp_cmd_status *)&sbp_status->data[0]; 647121186Ssimokawa sbp_cmd_status->status = ccb->csio.scsi_status; 648121186Ssimokawa sense = &ccb->csio.sense_data; 649121186Ssimokawa 650170374Ssimokawa#if 0 /* XXX What we should do? */ 651170374Ssimokawa#if 0 652170374Ssimokawa sbp_targ_abort(orbi->sc, STAILQ_NEXT(orbi, link)); 653170374Ssimokawa#else 654170374Ssimokawa norbi = STAILQ_NEXT(orbi, link); 655170374Ssimokawa while (norbi) { 656170374Ssimokawa printf("%s: status=%d\n", __func__, norbi->state); 657170374Ssimokawa if (norbi->ccb != NULL) { 658170374Ssimokawa norbi->ccb->ccb_h.status = CAM_REQ_ABORTED; 659170374Ssimokawa xpt_done(norbi->ccb); 660170374Ssimokawa norbi->ccb = NULL; 661170374Ssimokawa } 662170374Ssimokawa sbp_targ_remove_orb_info_locked(orbi->login, norbi); 663170374Ssimokawa norbi = STAILQ_NEXT(norbi, link); 664170374Ssimokawa free(norbi, M_SBP_TARG); 665170374Ssimokawa } 666170374Ssimokawa#endif 667170374Ssimokawa#endif 668121186Ssimokawa 669226067Sken sense_len = ccb->csio.sense_len - ccb->csio.sense_resid; 670226067Sken scsi_extract_sense_len(sense, sense_len, &error_code, 671226067Sken &sense_key, &asc, &ascq, /*show_errors*/ 0); 672226067Sken 673226067Sken switch (error_code) { 674226067Sken case SSD_CURRENT_ERROR: 675226067Sken case SSD_DESC_CURRENT_ERROR: 676121186Ssimokawa sbp_cmd_status->sfmt = SBP_SFMT_CURR; 677226067Sken break; 678226067Sken default: 679121186Ssimokawa sbp_cmd_status->sfmt = SBP_SFMT_DEFER; 680226067Sken break; 681226067Sken } 682121186Ssimokawa 683226067Sken if (scsi_get_sense_info(sense, sense_len, SSD_DESC_INFO, &info, 684226067Sken &sinfo) == 0) { 685226067Sken uint32_t info_trunc; 686226067Sken sbp_cmd_status->valid = 1; 687226067Sken info_trunc = info; 688121186Ssimokawa 689226067Sken sbp_cmd_status->info = htobe32(info_trunc); 690226067Sken } else { 691226067Sken sbp_cmd_status->valid = 0; 692226067Sken } 693121186Ssimokawa 694226067Sken sbp_cmd_status->s_key = sense_key; 695226067Sken 696226067Sken if (scsi_get_stream_info(sense, sense_len, NULL, 697226067Sken &stream_bits) == 0) { 698226067Sken sbp_cmd_status->mark = 699226067Sken (stream_bits & SSD_FILEMARK) ? 1 : 0; 700226067Sken sbp_cmd_status->eom = 701226067Sken (stream_bits & SSD_EOM) ? 1 : 0; 702226067Sken sbp_cmd_status->ill_len = 703226067Sken (stream_bits & SSD_ILI) ? 1 : 0; 704226067Sken } else { 705226067Sken sbp_cmd_status->mark = 0; 706226067Sken sbp_cmd_status->eom = 0; 707226067Sken sbp_cmd_status->ill_len = 0; 708226067Sken } 709226067Sken 710226067Sken 711226067Sken /* add_sense_code(_qual), info, cmd_spec_info */ 712226067Sken sbp_status->len = 4; 713226067Sken 714226067Sken if (scsi_get_sense_info(sense, sense_len, SSD_DESC_COMMAND, 715226067Sken &info, &sinfo) == 0) { 716226067Sken uint32_t cmdspec_trunc; 717226067Sken 718226067Sken cmdspec_trunc = info; 719226067Sken 720226067Sken sbp_cmd_status->cdb = htobe32(cmdspec_trunc); 721226067Sken } 722226067Sken 723226067Sken sbp_cmd_status->s_code = asc; 724226067Sken sbp_cmd_status->s_qlfr = ascq; 725226067Sken 726226067Sken if (scsi_get_sense_info(sense, sense_len, SSD_DESC_FRU, &info, 727226067Sken &sinfo) == 0) { 728226067Sken sbp_cmd_status->fru = (uint8_t)info; 729121186Ssimokawa sbp_status->len = 5; 730226067Sken } else { 731226067Sken sbp_cmd_status->fru = 0; 732226067Sken } 733121186Ssimokawa 734226067Sken if (scsi_get_sks(sense, sense_len, sks) == 0) { 735226067Sken bcopy(sks, &sbp_cmd_status->s_keydep[0], sizeof(sks)); 736226067Sken sbp_status->len = 5; 737226067Sken } 738121186Ssimokawa 739121186Ssimokawa break; 740121186Ssimokawa } 741121186Ssimokawa default: 742127468Ssimokawa printf("%s: unknown scsi status 0x%x\n", __func__, 743121186Ssimokawa sbp_status->status); 744121186Ssimokawa } 745121186Ssimokawa 746170374Ssimokawa if (orbi->page_table != NULL) 747170374Ssimokawa free(orbi->page_table, M_SBP_TARG); 748170374Ssimokawa 749121186Ssimokawa sbp_targ_status_FIFO(orbi, 750123430Ssimokawa orbi->login->fifo_hi, orbi->login->fifo_lo, /*dequeue*/1); 751121186Ssimokawa} 752121186Ssimokawa 753121186Ssimokawastatic void 754121186Ssimokawasbp_targ_cam_done(struct fw_xfer *xfer) 755121186Ssimokawa{ 756121186Ssimokawa struct orb_info *orbi; 757121186Ssimokawa union ccb *ccb; 758121186Ssimokawa 759121186Ssimokawa orbi = (struct orb_info *)xfer->sc; 760121186Ssimokawa 761123430Ssimokawa if (debug > 1) 762127468Ssimokawa printf("%s: resp=%d refcount=%d\n", __func__, 763121186Ssimokawa xfer->resp, orbi->refcount); 764121186Ssimokawa 765121186Ssimokawa if (xfer->resp != 0) { 766127468Ssimokawa printf("%s: xfer->resp = %d\n", __func__, xfer->resp); 767121186Ssimokawa orbi->status.resp = SBP_TRANS_FAIL; 768124877Ssimokawa orbi->status.status = OBJ_DATA | SBE_TIMEOUT/*XXX*/; 769121186Ssimokawa orbi->status.dead = 1; 770170374Ssimokawa sbp_targ_abort(orbi->sc, STAILQ_NEXT(orbi, link)); 771121186Ssimokawa } 772121186Ssimokawa 773121186Ssimokawa orbi->refcount --; 774121186Ssimokawa 775121186Ssimokawa ccb = orbi->ccb; 776121186Ssimokawa if (orbi->refcount == 0) { 777170374Ssimokawa orbi->ccb = NULL; 778121186Ssimokawa if (orbi->state == ORBI_STATUS_ABORTED) { 779121186Ssimokawa if (debug) 780127468Ssimokawa printf("%s: orbi aborted\n", __func__); 781123430Ssimokawa sbp_targ_remove_orb_info(orbi->login, orbi); 782121186Ssimokawa if (orbi->page_table != NULL) 783121186Ssimokawa free(orbi->page_table, M_SBP_TARG); 784121186Ssimokawa free(orbi, M_SBP_TARG); 785121186Ssimokawa } else if (orbi->status.resp == 0) { 786121186Ssimokawa if ((ccb->ccb_h.flags & CAM_SEND_STATUS) != 0) 787121186Ssimokawa sbp_targ_send_status(orbi, ccb); 788121186Ssimokawa ccb->ccb_h.status = CAM_REQ_CMP; 789170374Ssimokawa SBP_LOCK(orbi->sc); 790121186Ssimokawa xpt_done(ccb); 791170374Ssimokawa SBP_UNLOCK(orbi->sc); 792121186Ssimokawa } else { 793121186Ssimokawa orbi->status.len = 1; 794121186Ssimokawa sbp_targ_status_FIFO(orbi, 795123430Ssimokawa orbi->login->fifo_hi, orbi->login->fifo_lo, 796121186Ssimokawa /*dequeue*/1); 797121186Ssimokawa ccb->ccb_h.status = CAM_REQ_ABORTED; 798170374Ssimokawa SBP_LOCK(orbi->sc); 799121186Ssimokawa xpt_done(ccb); 800170374Ssimokawa SBP_UNLOCK(orbi->sc); 801121186Ssimokawa } 802121186Ssimokawa } 803121186Ssimokawa 804121186Ssimokawa fw_xfer_free(xfer); 805121186Ssimokawa} 806121186Ssimokawa 807121186Ssimokawastatic cam_status 808121186Ssimokawasbp_targ_abort_ccb(struct sbp_targ_softc *sc, union ccb *ccb) 809121186Ssimokawa{ 810121186Ssimokawa union ccb *accb; 811121186Ssimokawa struct sbp_targ_lstate *lstate; 812121186Ssimokawa struct ccb_hdr_slist *list; 813121186Ssimokawa struct ccb_hdr *curelm; 814121186Ssimokawa int found; 815121186Ssimokawa cam_status status; 816121186Ssimokawa 817121186Ssimokawa status = sbp_targ_find_devs(sc, ccb, &lstate, 0); 818121186Ssimokawa if (status != CAM_REQ_CMP) 819121186Ssimokawa return (status); 820121186Ssimokawa 821121186Ssimokawa accb = ccb->cab.abort_ccb; 822121186Ssimokawa 823121186Ssimokawa if (accb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO) 824121186Ssimokawa list = &lstate->accept_tios; 825237825Sken else if (accb->ccb_h.func_code == XPT_IMMEDIATE_NOTIFY) 826121186Ssimokawa list = &lstate->immed_notifies; 827121186Ssimokawa else 828121186Ssimokawa return (CAM_UA_ABORT); 829121186Ssimokawa 830121186Ssimokawa curelm = SLIST_FIRST(list); 831121186Ssimokawa found = 0; 832121186Ssimokawa if (curelm == &accb->ccb_h) { 833121186Ssimokawa found = 1; 834121186Ssimokawa SLIST_REMOVE_HEAD(list, sim_links.sle); 835121186Ssimokawa } else { 836121186Ssimokawa while(curelm != NULL) { 837121186Ssimokawa struct ccb_hdr *nextelm; 838121186Ssimokawa 839121186Ssimokawa nextelm = SLIST_NEXT(curelm, sim_links.sle); 840121186Ssimokawa if (nextelm == &accb->ccb_h) { 841121186Ssimokawa found = 1; 842121186Ssimokawa SLIST_NEXT(curelm, sim_links.sle) = 843121186Ssimokawa SLIST_NEXT(nextelm, sim_links.sle); 844121186Ssimokawa break; 845121186Ssimokawa } 846121186Ssimokawa curelm = nextelm; 847121186Ssimokawa } 848121186Ssimokawa } 849121186Ssimokawa if (found) { 850121186Ssimokawa accb->ccb_h.status = CAM_REQ_ABORTED; 851121186Ssimokawa xpt_done(accb); 852121186Ssimokawa return (CAM_REQ_CMP); 853121186Ssimokawa } 854127468Ssimokawa printf("%s: not found\n", __func__); 855121186Ssimokawa return (CAM_PATH_INVALID); 856121186Ssimokawa} 857121186Ssimokawa 858121186Ssimokawastatic void 859121186Ssimokawasbp_targ_xfer_buf(struct orb_info *orbi, u_int offset, 860129585Sdfr uint16_t dst_hi, uint32_t dst_lo, u_int size, 861121186Ssimokawa void (*hand)(struct fw_xfer *)) 862121186Ssimokawa{ 863121186Ssimokawa struct fw_xfer *xfer; 864121186Ssimokawa u_int len, ccb_dir, off = 0; 865121186Ssimokawa char *ptr; 866121186Ssimokawa 867123430Ssimokawa if (debug > 1) 868127468Ssimokawa printf("%s: offset=%d size=%d\n", __func__, offset, size); 869121186Ssimokawa ccb_dir = orbi->ccb->ccb_h.flags & CAM_DIR_MASK; 870121186Ssimokawa ptr = (char *)orbi->ccb->csio.data_ptr + offset; 871121186Ssimokawa 872121186Ssimokawa while (size > 0) { 873121186Ssimokawa /* XXX assume dst_lo + off doesn't overflow */ 874121186Ssimokawa len = MIN(size, 2048 /* XXX */); 875121186Ssimokawa size -= len; 876121186Ssimokawa orbi->refcount ++; 877121186Ssimokawa if (ccb_dir == CAM_DIR_OUT) 878121186Ssimokawa xfer = fwmem_read_block(orbi->fwdev, 879121186Ssimokawa (void *)orbi, /*spd*/2, 880121186Ssimokawa dst_hi, dst_lo + off, len, 881121186Ssimokawa ptr + off, hand); 882121186Ssimokawa else 883121186Ssimokawa xfer = fwmem_write_block(orbi->fwdev, 884121186Ssimokawa (void *)orbi, /*spd*/2, 885121186Ssimokawa dst_hi, dst_lo + off, len, 886121186Ssimokawa ptr + off, hand); 887121186Ssimokawa if (xfer == NULL) { 888127468Ssimokawa printf("%s: xfer == NULL", __func__); 889121186Ssimokawa /* XXX what should we do?? */ 890121186Ssimokawa orbi->refcount --; 891121186Ssimokawa } 892121186Ssimokawa off += len; 893121186Ssimokawa } 894121186Ssimokawa} 895121186Ssimokawa 896121186Ssimokawastatic void 897121186Ssimokawasbp_targ_pt_done(struct fw_xfer *xfer) 898121186Ssimokawa{ 899121186Ssimokawa struct orb_info *orbi; 900121186Ssimokawa union ccb *ccb; 901121186Ssimokawa u_int i, offset, res, len; 902129585Sdfr uint32_t t1, t2, *p; 903121186Ssimokawa 904121186Ssimokawa orbi = (struct orb_info *)xfer->sc; 905121186Ssimokawa ccb = orbi->ccb; 906121186Ssimokawa if (orbi->state == ORBI_STATUS_ABORTED) { 907121186Ssimokawa if (debug) 908127468Ssimokawa printf("%s: orbi aborted\n", __func__); 909123430Ssimokawa sbp_targ_remove_orb_info(orbi->login, orbi); 910121186Ssimokawa free(orbi->page_table, M_SBP_TARG); 911121186Ssimokawa free(orbi, M_SBP_TARG); 912121186Ssimokawa fw_xfer_free(xfer); 913121186Ssimokawa return; 914121186Ssimokawa } 915121186Ssimokawa if (xfer->resp != 0) { 916127468Ssimokawa printf("%s: xfer->resp = %d\n", __func__, xfer->resp); 917121186Ssimokawa orbi->status.resp = SBP_TRANS_FAIL; 918124877Ssimokawa orbi->status.status = OBJ_PT | SBE_TIMEOUT/*XXX*/; 919121186Ssimokawa orbi->status.dead = 1; 920121186Ssimokawa orbi->status.len = 1; 921170374Ssimokawa sbp_targ_abort(orbi->sc, STAILQ_NEXT(orbi, link)); 922121186Ssimokawa 923121186Ssimokawa sbp_targ_status_FIFO(orbi, 924123430Ssimokawa orbi->login->fifo_hi, orbi->login->fifo_lo, /*dequeue*/1); 925121186Ssimokawa free(orbi->page_table, M_SBP_TARG); 926121186Ssimokawa fw_xfer_free(xfer); 927121186Ssimokawa return; 928121186Ssimokawa } 929121186Ssimokawa res = ccb->csio.dxfer_len; 930121186Ssimokawa offset = 0; 931121186Ssimokawa if (debug) 932127468Ssimokawa printf("%s: dxfer_len=%d\n", __func__, res); 933121186Ssimokawa orbi->refcount ++; 934121186Ssimokawa for (p = orbi->page_table, i = orbi->orb4.data_size; i > 0; i --) { 935121186Ssimokawa t1 = ntohl(*p++); 936121186Ssimokawa t2 = ntohl(*p++); 937123430Ssimokawa if (debug > 1) 938121186Ssimokawa printf("page_table: %04x:%08x %d\n", 939121186Ssimokawa t1 & 0xffff, t2, t1>>16); 940121186Ssimokawa len = MIN(t1 >> 16, res); 941121186Ssimokawa res -= len; 942121186Ssimokawa sbp_targ_xfer_buf(orbi, offset, t1 & 0xffff, t2, len, 943121186Ssimokawa sbp_targ_cam_done); 944121186Ssimokawa offset += len; 945121186Ssimokawa if (res == 0) 946121186Ssimokawa break; 947121186Ssimokawa } 948121186Ssimokawa orbi->refcount --; 949121186Ssimokawa if (orbi->refcount == 0) 950127468Ssimokawa printf("%s: refcount == 0\n", __func__); 951121186Ssimokawa if (res !=0) 952121186Ssimokawa /* XXX handle res != 0 case */ 953127468Ssimokawa printf("%s: page table is too small(%d)\n", __func__, res); 954121186Ssimokawa 955121186Ssimokawa fw_xfer_free(xfer); 956121186Ssimokawa return; 957121186Ssimokawa} 958121186Ssimokawa 959121186Ssimokawastatic void 960121186Ssimokawasbp_targ_fetch_pt(struct orb_info *orbi) 961121186Ssimokawa{ 962121186Ssimokawa struct fw_xfer *xfer; 963121186Ssimokawa 964121186Ssimokawa if (debug) 965121186Ssimokawa printf("%s: page_table_size=%d\n", 966127468Ssimokawa __func__, orbi->orb4.data_size); 967121186Ssimokawa orbi->page_table = malloc(orbi->orb4.data_size*8, M_SBP_TARG, M_NOWAIT); 968121186Ssimokawa if (orbi->page_table == NULL) 969121186Ssimokawa goto error; 970121186Ssimokawa xfer = fwmem_read_block(orbi->fwdev, (void *)orbi, /*spd*/2, 971121186Ssimokawa orbi->data_hi, orbi->data_lo, orbi->orb4.data_size*8, 972121186Ssimokawa (void *)orbi->page_table, sbp_targ_pt_done); 973121186Ssimokawa if (xfer != NULL) 974121186Ssimokawa return; 975121186Ssimokawaerror: 976121186Ssimokawa orbi->ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 977121186Ssimokawa xpt_done(orbi->ccb); 978121186Ssimokawa return; 979121186Ssimokawa} 980121186Ssimokawa 981121186Ssimokawastatic void 982121186Ssimokawasbp_targ_action1(struct cam_sim *sim, union ccb *ccb) 983121186Ssimokawa{ 984121186Ssimokawa struct sbp_targ_softc *sc; 985121186Ssimokawa struct sbp_targ_lstate *lstate; 986121186Ssimokawa cam_status status; 987121186Ssimokawa u_int ccb_dir; 988121186Ssimokawa 989121186Ssimokawa sc = (struct sbp_targ_softc *)cam_sim_softc(sim); 990121186Ssimokawa 991121186Ssimokawa status = sbp_targ_find_devs(sc, ccb, &lstate, TRUE); 992121186Ssimokawa 993121186Ssimokawa switch (ccb->ccb_h.func_code) { 994121186Ssimokawa case XPT_CONT_TARGET_IO: 995121186Ssimokawa { 996121186Ssimokawa struct orb_info *orbi; 997121186Ssimokawa 998121186Ssimokawa if (debug) 999170374Ssimokawa printf("%s: XPT_CONT_TARGET_IO (0x%08x)\n", 1000170374Ssimokawa __func__, ccb->csio.tag_id); 1001121186Ssimokawa 1002121186Ssimokawa if (status != CAM_REQ_CMP) { 1003121186Ssimokawa ccb->ccb_h.status = status; 1004121186Ssimokawa xpt_done(ccb); 1005121186Ssimokawa break; 1006121186Ssimokawa } 1007121186Ssimokawa /* XXX transfer from/to initiator */ 1008121186Ssimokawa orbi = sbp_targ_get_orb_info(lstate, 1009121186Ssimokawa ccb->csio.tag_id, ccb->csio.init_id); 1010121186Ssimokawa if (orbi == NULL) { 1011121186Ssimokawa ccb->ccb_h.status = CAM_REQ_ABORTED; /* XXX */ 1012121186Ssimokawa xpt_done(ccb); 1013121186Ssimokawa break; 1014121186Ssimokawa } 1015121186Ssimokawa if (orbi->state == ORBI_STATUS_ABORTED) { 1016121186Ssimokawa if (debug) 1017127468Ssimokawa printf("%s: ctio aborted\n", __func__); 1018170374Ssimokawa sbp_targ_remove_orb_info_locked(orbi->login, orbi); 1019121186Ssimokawa free(orbi, M_SBP_TARG); 1020170374Ssimokawa ccb->ccb_h.status = CAM_REQ_ABORTED; 1021170374Ssimokawa xpt_done(ccb); 1022121186Ssimokawa break; 1023121186Ssimokawa } 1024121186Ssimokawa orbi->state = ORBI_STATUS_CTIO; 1025121186Ssimokawa 1026121186Ssimokawa orbi->ccb = ccb; 1027121186Ssimokawa ccb_dir = ccb->ccb_h.flags & CAM_DIR_MASK; 1028121186Ssimokawa 1029121186Ssimokawa /* XXX */ 1030121186Ssimokawa if (ccb->csio.dxfer_len == 0) 1031121186Ssimokawa ccb_dir = CAM_DIR_NONE; 1032121186Ssimokawa 1033121186Ssimokawa /* Sanity check */ 1034121186Ssimokawa if (ccb_dir == CAM_DIR_IN && orbi->orb4.dir == 0) 1035127468Ssimokawa printf("%s: direction mismatch\n", __func__); 1036121186Ssimokawa 1037121186Ssimokawa /* check page table */ 1038121186Ssimokawa if (ccb_dir != CAM_DIR_NONE && orbi->orb4.page_table_present) { 1039121186Ssimokawa if (debug) 1040121186Ssimokawa printf("%s: page_table_present\n", 1041127468Ssimokawa __func__); 1042121186Ssimokawa if (orbi->orb4.page_size != 0) { 1043121186Ssimokawa printf("%s: unsupported pagesize %d != 0\n", 1044127468Ssimokawa __func__, orbi->orb4.page_size); 1045121186Ssimokawa ccb->ccb_h.status = CAM_REQ_INVALID; 1046121186Ssimokawa xpt_done(ccb); 1047121186Ssimokawa break; 1048121186Ssimokawa } 1049121186Ssimokawa sbp_targ_fetch_pt(orbi); 1050121186Ssimokawa break; 1051121186Ssimokawa } 1052121186Ssimokawa 1053121186Ssimokawa /* Sanity check */ 1054121186Ssimokawa if (ccb_dir != CAM_DIR_NONE && 1055121186Ssimokawa orbi->orb4.data_size != ccb->csio.dxfer_len) 1056121186Ssimokawa printf("%s: data_size(%d) != dxfer_len(%d)\n", 1057127468Ssimokawa __func__, orbi->orb4.data_size, 1058121186Ssimokawa ccb->csio.dxfer_len); 1059121186Ssimokawa 1060121186Ssimokawa if (ccb_dir != CAM_DIR_NONE) 1061121186Ssimokawa sbp_targ_xfer_buf(orbi, 0, orbi->data_hi, 1062121186Ssimokawa orbi->data_lo, 1063121186Ssimokawa MIN(orbi->orb4.data_size, ccb->csio.dxfer_len), 1064121186Ssimokawa sbp_targ_cam_done); 1065121186Ssimokawa 1066121186Ssimokawa if (ccb_dir == CAM_DIR_NONE) { 1067170374Ssimokawa if ((ccb->ccb_h.flags & CAM_SEND_STATUS) != 0) { 1068170374Ssimokawa /* XXX */ 1069170374Ssimokawa SBP_UNLOCK(sc); 1070121186Ssimokawa sbp_targ_send_status(orbi, ccb); 1071170374Ssimokawa SBP_LOCK(sc); 1072170374Ssimokawa } 1073121186Ssimokawa ccb->ccb_h.status = CAM_REQ_CMP; 1074121186Ssimokawa xpt_done(ccb); 1075121186Ssimokawa } 1076121186Ssimokawa break; 1077121186Ssimokawa } 1078121186Ssimokawa case XPT_ACCEPT_TARGET_IO: /* Add Accept Target IO Resource */ 1079121186Ssimokawa if (status != CAM_REQ_CMP) { 1080121186Ssimokawa ccb->ccb_h.status = status; 1081121186Ssimokawa xpt_done(ccb); 1082121186Ssimokawa break; 1083121186Ssimokawa } 1084121186Ssimokawa SLIST_INSERT_HEAD(&lstate->accept_tios, &ccb->ccb_h, 1085121186Ssimokawa sim_links.sle); 1086121186Ssimokawa ccb->ccb_h.status = CAM_REQ_INPROG; 1087123430Ssimokawa if ((lstate->flags & F_ATIO_STARVED) != 0) { 1088123430Ssimokawa struct sbp_targ_login *login; 1089123430Ssimokawa 1090121186Ssimokawa if (debug) 1091127468Ssimokawa printf("%s: new atio arrived\n", __func__); 1092123430Ssimokawa lstate->flags &= ~F_ATIO_STARVED; 1093123430Ssimokawa STAILQ_FOREACH(login, &lstate->logins, link) 1094123430Ssimokawa if ((login->flags & F_ATIO_STARVED) != 0) { 1095123430Ssimokawa login->flags &= ~F_ATIO_STARVED; 1096123430Ssimokawa sbp_targ_fetch_orb(lstate->sc, 1097123430Ssimokawa login->fwdev, 1098123430Ssimokawa login->last_hi, login->last_lo, 1099123430Ssimokawa login, FETCH_CMD); 1100123430Ssimokawa } 1101121186Ssimokawa } 1102121186Ssimokawa break; 1103237825Sken case XPT_NOTIFY_ACKNOWLEDGE: /* recycle notify ack */ 1104237825Sken case XPT_IMMEDIATE_NOTIFY: /* Add Immediate Notify Resource */ 1105121186Ssimokawa if (status != CAM_REQ_CMP) { 1106121186Ssimokawa ccb->ccb_h.status = status; 1107121186Ssimokawa xpt_done(ccb); 1108121186Ssimokawa break; 1109121186Ssimokawa } 1110121186Ssimokawa SLIST_INSERT_HEAD(&lstate->immed_notifies, &ccb->ccb_h, 1111121186Ssimokawa sim_links.sle); 1112121186Ssimokawa ccb->ccb_h.status = CAM_REQ_INPROG; 1113121186Ssimokawa sbp_targ_send_lstate_events(sc, lstate); 1114121186Ssimokawa break; 1115121186Ssimokawa case XPT_EN_LUN: 1116121186Ssimokawa sbp_targ_en_lun(sc, ccb); 1117121186Ssimokawa xpt_done(ccb); 1118121186Ssimokawa break; 1119121186Ssimokawa case XPT_PATH_INQ: 1120121186Ssimokawa { 1121121186Ssimokawa struct ccb_pathinq *cpi = &ccb->cpi; 1122121186Ssimokawa 1123121186Ssimokawa cpi->version_num = 1; /* XXX??? */ 1124121186Ssimokawa cpi->hba_inquiry = PI_TAG_ABLE; 1125121186Ssimokawa cpi->target_sprt = PIT_PROCESSOR 1126121186Ssimokawa | PIT_DISCONNECT 1127121186Ssimokawa | PIT_TERM_IO; 1128121186Ssimokawa cpi->hba_misc = PIM_NOBUSRESET | PIM_NO_6_BYTE; 1129121186Ssimokawa cpi->hba_eng_cnt = 0; 1130121186Ssimokawa cpi->max_target = 7; /* XXX */ 1131121186Ssimokawa cpi->max_lun = MAX_LUN - 1; 1132121186Ssimokawa cpi->initiator_id = 7; /* XXX */ 1133121186Ssimokawa cpi->bus_id = sim->bus_id; 1134121186Ssimokawa cpi->base_transfer_speed = 400 * 1000 / 8; 1135121186Ssimokawa strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 1136121186Ssimokawa strncpy(cpi->hba_vid, "SBP_TARG", HBA_IDLEN); 1137121186Ssimokawa strncpy(cpi->dev_name, sim->sim_name, DEV_IDLEN); 1138121186Ssimokawa cpi->unit_number = sim->unit_number; 1139121186Ssimokawa 1140121186Ssimokawa cpi->ccb_h.status = CAM_REQ_CMP; 1141121186Ssimokawa xpt_done(ccb); 1142121186Ssimokawa break; 1143121186Ssimokawa } 1144121186Ssimokawa case XPT_ABORT: 1145121186Ssimokawa { 1146121186Ssimokawa union ccb *accb = ccb->cab.abort_ccb; 1147121186Ssimokawa 1148121186Ssimokawa switch (accb->ccb_h.func_code) { 1149121186Ssimokawa case XPT_ACCEPT_TARGET_IO: 1150237825Sken case XPT_IMMEDIATE_NOTIFY: 1151121186Ssimokawa ccb->ccb_h.status = sbp_targ_abort_ccb(sc, ccb); 1152121186Ssimokawa break; 1153121186Ssimokawa case XPT_CONT_TARGET_IO: 1154121186Ssimokawa /* XXX */ 1155121186Ssimokawa ccb->ccb_h.status = CAM_UA_ABORT; 1156121186Ssimokawa break; 1157121186Ssimokawa default: 1158121186Ssimokawa printf("%s: aborting unknown function %d\n", 1159127468Ssimokawa __func__, accb->ccb_h.func_code); 1160121186Ssimokawa ccb->ccb_h.status = CAM_REQ_INVALID; 1161121186Ssimokawa break; 1162121186Ssimokawa } 1163121186Ssimokawa xpt_done(ccb); 1164121186Ssimokawa break; 1165121186Ssimokawa } 1166121186Ssimokawa default: 1167121186Ssimokawa printf("%s: unknown function %d\n", 1168127468Ssimokawa __func__, ccb->ccb_h.func_code); 1169121186Ssimokawa ccb->ccb_h.status = CAM_REQ_INVALID; 1170121186Ssimokawa xpt_done(ccb); 1171121186Ssimokawa break; 1172121186Ssimokawa } 1173121186Ssimokawa return; 1174121186Ssimokawa} 1175121186Ssimokawa 1176121186Ssimokawastatic void 1177121186Ssimokawasbp_targ_action(struct cam_sim *sim, union ccb *ccb) 1178121186Ssimokawa{ 1179121186Ssimokawa int s; 1180121186Ssimokawa 1181121186Ssimokawa s = splfw(); 1182121186Ssimokawa sbp_targ_action1(sim, ccb); 1183121186Ssimokawa splx(s); 1184121186Ssimokawa} 1185121186Ssimokawa 1186121186Ssimokawastatic void 1187121186Ssimokawasbp_targ_poll(struct cam_sim *sim) 1188121186Ssimokawa{ 1189121186Ssimokawa /* XXX */ 1190121186Ssimokawa return; 1191121186Ssimokawa} 1192121186Ssimokawa 1193121186Ssimokawastatic void 1194121186Ssimokawasbp_targ_cmd_handler(struct fw_xfer *xfer) 1195121186Ssimokawa{ 1196121186Ssimokawa struct fw_pkt *fp; 1197129585Sdfr uint32_t *orb; 1198121186Ssimokawa struct corb4 *orb4; 1199121186Ssimokawa struct orb_info *orbi; 1200121186Ssimokawa struct ccb_accept_tio *atio; 1201121186Ssimokawa u_char *bytes; 1202121186Ssimokawa int i; 1203121186Ssimokawa 1204121186Ssimokawa orbi = (struct orb_info *)xfer->sc; 1205121186Ssimokawa if (xfer->resp != 0) { 1206127468Ssimokawa printf("%s: xfer->resp = %d\n", __func__, xfer->resp); 1207121186Ssimokawa orbi->status.resp = SBP_TRANS_FAIL; 1208124877Ssimokawa orbi->status.status = OBJ_ORB | SBE_TIMEOUT/*XXX*/; 1209121186Ssimokawa orbi->status.dead = 1; 1210121186Ssimokawa orbi->status.len = 1; 1211170374Ssimokawa sbp_targ_abort(orbi->sc, STAILQ_NEXT(orbi, link)); 1212121186Ssimokawa 1213121186Ssimokawa sbp_targ_status_FIFO(orbi, 1214123430Ssimokawa orbi->login->fifo_hi, orbi->login->fifo_lo, /*dequeue*/1); 1215121186Ssimokawa fw_xfer_free(xfer); 1216121186Ssimokawa return; 1217121186Ssimokawa } 1218121186Ssimokawa fp = &xfer->recv.hdr; 1219121186Ssimokawa 1220170374Ssimokawa atio = orbi->atio; 1221170374Ssimokawa 1222121186Ssimokawa if (orbi->state == ORBI_STATUS_ABORTED) { 1223127468Ssimokawa printf("%s: aborted\n", __func__); 1224123430Ssimokawa sbp_targ_remove_orb_info(orbi->login, orbi); 1225121186Ssimokawa free(orbi, M_SBP_TARG); 1226170374Ssimokawa atio->ccb_h.status = CAM_REQ_ABORTED; 1227170374Ssimokawa SBP_LOCK(orbi->sc); 1228170374Ssimokawa xpt_done((union ccb*)atio); 1229170374Ssimokawa SBP_UNLOCK(orbi->sc); 1230121186Ssimokawa goto done0; 1231121186Ssimokawa } 1232121186Ssimokawa orbi->state = ORBI_STATUS_ATIO; 1233121186Ssimokawa 1234121186Ssimokawa orb = orbi->orb; 1235121186Ssimokawa /* swap payload except SCSI command */ 1236121186Ssimokawa for (i = 0; i < 5; i ++) 1237121186Ssimokawa orb[i] = ntohl(orb[i]); 1238121186Ssimokawa 1239121186Ssimokawa orb4 = (struct corb4 *)&orb[4]; 1240121186Ssimokawa if (orb4->rq_fmt != 0) { 1241121186Ssimokawa /* XXX */ 1242127468Ssimokawa printf("%s: rq_fmt(%d) != 0\n", __func__, orb4->rq_fmt); 1243121186Ssimokawa } 1244121186Ssimokawa 1245121186Ssimokawa atio->ccb_h.target_id = 0; /* XXX */ 1246123430Ssimokawa atio->ccb_h.target_lun = orbi->login->lstate->lun; 1247121186Ssimokawa atio->sense_len = 0; 1248121186Ssimokawa atio->tag_action = 1; /* XXX */ 1249121186Ssimokawa atio->tag_id = orbi->orb_lo; 1250123430Ssimokawa atio->init_id = orbi->login->id; 1251123430Ssimokawa 1252121186Ssimokawa atio->ccb_h.flags = CAM_TAG_ACTION_VALID; 1253170374Ssimokawa bytes = (u_char *)&orb[5]; 1254121186Ssimokawa if (debug) 1255170374Ssimokawa printf("%s: %p %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", 1256170374Ssimokawa __func__, (void *)atio, 1257121186Ssimokawa bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], 1258121186Ssimokawa bytes[5], bytes[6], bytes[7], bytes[8], bytes[9]); 1259121186Ssimokawa switch (bytes[0] >> 5) { 1260121186Ssimokawa case 0: 1261121186Ssimokawa atio->cdb_len = 6; 1262121186Ssimokawa break; 1263121186Ssimokawa case 1: 1264121186Ssimokawa case 2: 1265121186Ssimokawa atio->cdb_len = 10; 1266121186Ssimokawa break; 1267121186Ssimokawa case 4: 1268121186Ssimokawa atio->cdb_len = 16; 1269121186Ssimokawa break; 1270121186Ssimokawa case 5: 1271121186Ssimokawa atio->cdb_len = 12; 1272121186Ssimokawa break; 1273121186Ssimokawa case 3: 1274121186Ssimokawa default: 1275121186Ssimokawa /* Only copy the opcode. */ 1276121186Ssimokawa atio->cdb_len = 1; 1277121186Ssimokawa printf("Reserved or VU command code type encountered\n"); 1278121186Ssimokawa break; 1279121186Ssimokawa } 1280121186Ssimokawa 1281121186Ssimokawa memcpy(atio->cdb_io.cdb_bytes, bytes, atio->cdb_len); 1282121186Ssimokawa 1283121186Ssimokawa atio->ccb_h.status |= CAM_CDB_RECVD; 1284121186Ssimokawa 1285121186Ssimokawa /* next ORB */ 1286121186Ssimokawa if ((orb[0] & (1<<31)) == 0) { 1287121186Ssimokawa if (debug) 1288127468Ssimokawa printf("%s: fetch next orb\n", __func__); 1289121186Ssimokawa orbi->status.src = SRC_NEXT_EXISTS; 1290121186Ssimokawa sbp_targ_fetch_orb(orbi->sc, orbi->fwdev, 1291123430Ssimokawa orb[0], orb[1], orbi->login, FETCH_CMD); 1292121186Ssimokawa } else { 1293121186Ssimokawa orbi->status.src = SRC_NO_NEXT; 1294123430Ssimokawa orbi->login->flags &= ~F_LINK_ACTIVE; 1295121186Ssimokawa } 1296121186Ssimokawa 1297121186Ssimokawa orbi->data_hi = orb[2]; 1298121186Ssimokawa orbi->data_lo = orb[3]; 1299121186Ssimokawa orbi->orb4 = *orb4; 1300121186Ssimokawa 1301170374Ssimokawa SBP_LOCK(orbi->sc); 1302121186Ssimokawa xpt_done((union ccb*)atio); 1303170374Ssimokawa SBP_UNLOCK(orbi->sc); 1304121186Ssimokawadone0: 1305121186Ssimokawa fw_xfer_free(xfer); 1306121186Ssimokawa return; 1307121186Ssimokawa} 1308121186Ssimokawa 1309123430Ssimokawastatic struct sbp_targ_login * 1310123430Ssimokawasbp_targ_get_login(struct sbp_targ_softc *sc, struct fw_device *fwdev, int lun) 1311123430Ssimokawa{ 1312123430Ssimokawa struct sbp_targ_lstate *lstate; 1313123430Ssimokawa struct sbp_targ_login *login; 1314123430Ssimokawa int i; 1315123430Ssimokawa 1316123430Ssimokawa lstate = sc->lstate[lun]; 1317123430Ssimokawa 1318123430Ssimokawa STAILQ_FOREACH(login, &lstate->logins, link) 1319123430Ssimokawa if (login->fwdev == fwdev) 1320123430Ssimokawa return (login); 1321123430Ssimokawa 1322123430Ssimokawa for (i = 0; i < MAX_LOGINS; i ++) 1323123430Ssimokawa if (sc->logins[i] == NULL) 1324123430Ssimokawa goto found; 1325123430Ssimokawa 1326127468Ssimokawa printf("%s: increase MAX_LOGIN\n", __func__); 1327123430Ssimokawa return (NULL); 1328123430Ssimokawa 1329123430Ssimokawafound: 1330123430Ssimokawa login = (struct sbp_targ_login *)malloc( 1331123430Ssimokawa sizeof(struct sbp_targ_login), M_SBP_TARG, M_NOWAIT | M_ZERO); 1332123430Ssimokawa 1333123430Ssimokawa if (login == NULL) { 1334127468Ssimokawa printf("%s: malloc failed\n", __func__); 1335123430Ssimokawa return (NULL); 1336123430Ssimokawa } 1337123430Ssimokawa 1338169475Ssimokawa login->id = i; 1339123430Ssimokawa login->fwdev = fwdev; 1340123430Ssimokawa login->lstate = lstate; 1341123430Ssimokawa login->last_hi = 0xffff; 1342123430Ssimokawa login->last_lo = 0xffffffff; 1343123430Ssimokawa login->hold_sec = 1; 1344123430Ssimokawa STAILQ_INIT(&login->orbs); 1345123430Ssimokawa CALLOUT_INIT(&login->hold_callout); 1346123430Ssimokawa sc->logins[i] = login; 1347123430Ssimokawa return (login); 1348123430Ssimokawa} 1349123430Ssimokawa 1350121186Ssimokawastatic void 1351121186Ssimokawasbp_targ_mgm_handler(struct fw_xfer *xfer) 1352121186Ssimokawa{ 1353121186Ssimokawa struct sbp_targ_lstate *lstate; 1354123430Ssimokawa struct sbp_targ_login *login; 1355121186Ssimokawa struct fw_pkt *fp; 1356129585Sdfr uint32_t *orb; 1357121186Ssimokawa struct morb4 *orb4; 1358121186Ssimokawa struct orb_info *orbi; 1359121186Ssimokawa int i; 1360121186Ssimokawa 1361121186Ssimokawa orbi = (struct orb_info *)xfer->sc; 1362121186Ssimokawa if (xfer->resp != 0) { 1363127468Ssimokawa printf("%s: xfer->resp = %d\n", __func__, xfer->resp); 1364121186Ssimokawa orbi->status.resp = SBP_TRANS_FAIL; 1365124877Ssimokawa orbi->status.status = OBJ_ORB | SBE_TIMEOUT/*XXX*/; 1366121186Ssimokawa orbi->status.dead = 1; 1367121186Ssimokawa orbi->status.len = 1; 1368170374Ssimokawa sbp_targ_abort(orbi->sc, STAILQ_NEXT(orbi, link)); 1369121186Ssimokawa 1370121186Ssimokawa sbp_targ_status_FIFO(orbi, 1371123430Ssimokawa orbi->login->fifo_hi, orbi->login->fifo_lo, /*dequeue*/0); 1372121186Ssimokawa fw_xfer_free(xfer); 1373121186Ssimokawa return; 1374121186Ssimokawa } 1375121186Ssimokawa fp = &xfer->recv.hdr; 1376121186Ssimokawa 1377121186Ssimokawa orb = orbi->orb; 1378121186Ssimokawa /* swap payload */ 1379121186Ssimokawa for (i = 0; i < 8; i ++) { 1380121186Ssimokawa orb[i] = ntohl(orb[i]); 1381121186Ssimokawa } 1382121186Ssimokawa orb4 = (struct morb4 *)&orb[4]; 1383121186Ssimokawa if (debug) 1384127468Ssimokawa printf("%s: %s\n", __func__, orb_fun_name[orb4->fun]); 1385121186Ssimokawa 1386121186Ssimokawa orbi->status.src = SRC_NO_NEXT; 1387121186Ssimokawa 1388121186Ssimokawa switch (orb4->fun << 16) { 1389121186Ssimokawa case ORB_FUN_LGI: 1390121186Ssimokawa { 1391123430Ssimokawa int exclusive = 0, lun; 1392121186Ssimokawa 1393123430Ssimokawa if (orb[4] & ORB_EXV) 1394123430Ssimokawa exclusive = 1; 1395123430Ssimokawa 1396123430Ssimokawa lun = orb4->id; 1397123430Ssimokawa lstate = orbi->sc->lstate[lun]; 1398123430Ssimokawa 1399123430Ssimokawa if (lun >= MAX_LUN || lstate == NULL || 1400123430Ssimokawa (exclusive && 1401123430Ssimokawa STAILQ_FIRST(&lstate->logins) != NULL && 1402123430Ssimokawa STAILQ_FIRST(&lstate->logins)->fwdev != orbi->fwdev) 1403123430Ssimokawa ) { 1404121186Ssimokawa /* error */ 1405121186Ssimokawa orbi->status.dead = 1; 1406121186Ssimokawa orbi->status.status = STATUS_ACCESS_DENY; 1407121186Ssimokawa orbi->status.len = 1; 1408121186Ssimokawa break; 1409121186Ssimokawa } 1410123430Ssimokawa 1411123430Ssimokawa /* allocate login */ 1412123430Ssimokawa login = sbp_targ_get_login(orbi->sc, orbi->fwdev, lun); 1413123430Ssimokawa if (login == NULL) { 1414123430Ssimokawa printf("%s: sbp_targ_get_login failed\n", 1415127468Ssimokawa __func__); 1416123430Ssimokawa orbi->status.dead = 1; 1417123430Ssimokawa orbi->status.status = STATUS_RES_UNAVAIL; 1418123430Ssimokawa orbi->status.len = 1; 1419123430Ssimokawa break; 1420123430Ssimokawa } 1421170374Ssimokawa printf("%s: login id=%d\n", __func__, login->id); 1422123430Ssimokawa 1423123430Ssimokawa login->fifo_hi = orb[6]; 1424123430Ssimokawa login->fifo_lo = orb[7]; 1425129585Sdfr login->loginres.len = htons(sizeof(uint32_t) * 4); 1426123430Ssimokawa login->loginres.id = htons(login->id); 1427123430Ssimokawa login->loginres.cmd_hi = htons(SBP_TARG_BIND_HI); 1428123430Ssimokawa login->loginres.cmd_lo = htonl(SBP_TARG_BIND_LO(login->id)); 1429123430Ssimokawa login->loginres.recon_hold = htons(login->hold_sec); 1430123430Ssimokawa 1431170374Ssimokawa STAILQ_INSERT_TAIL(&lstate->logins, login, link); 1432121186Ssimokawa fwmem_write_block(orbi->fwdev, NULL, /*spd*/2, orb[2], orb[3], 1433123430Ssimokawa sizeof(struct sbp_login_res), (void *)&login->loginres, 1434121186Ssimokawa fw_asy_callback_free); 1435123514Ssimokawa /* XXX return status after loginres is successfully written */ 1436121186Ssimokawa break; 1437121186Ssimokawa } 1438121186Ssimokawa case ORB_FUN_RCN: 1439123430Ssimokawa login = orbi->sc->logins[orb4->id]; 1440123430Ssimokawa if (login != NULL && login->fwdev == orbi->fwdev) { 1441123430Ssimokawa login->flags &= ~F_HOLD; 1442123430Ssimokawa callout_stop(&login->hold_callout); 1443123430Ssimokawa printf("%s: reconnected id=%d\n", 1444127468Ssimokawa __func__, login->id); 1445123430Ssimokawa } else { 1446123430Ssimokawa orbi->status.dead = 1; 1447123430Ssimokawa orbi->status.status = STATUS_ACCESS_DENY; 1448123430Ssimokawa printf("%s: reconnection faild id=%d\n", 1449127468Ssimokawa __func__, orb4->id); 1450123430Ssimokawa } 1451121186Ssimokawa break; 1452123430Ssimokawa case ORB_FUN_LGO: 1453123430Ssimokawa login = orbi->sc->logins[orb4->id]; 1454123430Ssimokawa if (login->fwdev != orbi->fwdev) { 1455127468Ssimokawa printf("%s: wrong initiator\n", __func__); 1456123430Ssimokawa break; 1457123430Ssimokawa } 1458123430Ssimokawa sbp_targ_dealloc_login(login); 1459123430Ssimokawa break; 1460121186Ssimokawa default: 1461121186Ssimokawa printf("%s: %s not implemented yet\n", 1462127468Ssimokawa __func__, orb_fun_name[orb4->fun]); 1463121186Ssimokawa break; 1464121186Ssimokawa } 1465121186Ssimokawa orbi->status.len = 1; 1466121186Ssimokawa sbp_targ_status_FIFO(orbi, orb[6], orb[7], /*dequeue*/0); 1467121186Ssimokawa fw_xfer_free(xfer); 1468121186Ssimokawa return; 1469121186Ssimokawa} 1470121186Ssimokawa 1471121186Ssimokawastatic void 1472121186Ssimokawasbp_targ_pointer_handler(struct fw_xfer *xfer) 1473121186Ssimokawa{ 1474121186Ssimokawa struct orb_info *orbi; 1475129585Sdfr uint32_t orb0, orb1; 1476121186Ssimokawa 1477121186Ssimokawa orbi = (struct orb_info *)xfer->sc; 1478121186Ssimokawa if (xfer->resp != 0) { 1479127468Ssimokawa printf("%s: xfer->resp = %d\n", __func__, xfer->resp); 1480121186Ssimokawa goto done; 1481121186Ssimokawa } 1482121186Ssimokawa 1483121186Ssimokawa orb0 = ntohl(orbi->orb[0]); 1484121186Ssimokawa orb1 = ntohl(orbi->orb[1]); 1485121186Ssimokawa if ((orb0 & (1 << 31)) != 0) { 1486127468Ssimokawa printf("%s: invalid pointer\n", __func__); 1487121186Ssimokawa goto done; 1488121186Ssimokawa } 1489123430Ssimokawa sbp_targ_fetch_orb(orbi->login->lstate->sc, orbi->fwdev, 1490129585Sdfr (uint16_t)orb0, orb1, orbi->login, FETCH_CMD); 1491121186Ssimokawadone: 1492121186Ssimokawa free(orbi, M_SBP_TARG); 1493121186Ssimokawa fw_xfer_free(xfer); 1494121186Ssimokawa return; 1495121186Ssimokawa} 1496121186Ssimokawa 1497121186Ssimokawastatic void 1498121186Ssimokawasbp_targ_fetch_orb(struct sbp_targ_softc *sc, struct fw_device *fwdev, 1499129585Sdfr uint16_t orb_hi, uint32_t orb_lo, struct sbp_targ_login *login, 1500121186Ssimokawa int mode) 1501121186Ssimokawa{ 1502121186Ssimokawa struct orb_info *orbi; 1503121186Ssimokawa 1504121186Ssimokawa if (debug) 1505127468Ssimokawa printf("%s: fetch orb %04x:%08x\n", __func__, orb_hi, orb_lo); 1506121186Ssimokawa orbi = malloc(sizeof(struct orb_info), M_SBP_TARG, M_NOWAIT | M_ZERO); 1507121186Ssimokawa if (orbi == NULL) { 1508127468Ssimokawa printf("%s: malloc failed\n", __func__); 1509121186Ssimokawa return; 1510121186Ssimokawa } 1511121186Ssimokawa orbi->sc = sc; 1512121186Ssimokawa orbi->fwdev = fwdev; 1513123430Ssimokawa orbi->login = login; 1514121186Ssimokawa orbi->orb_hi = orb_hi; 1515121186Ssimokawa orbi->orb_lo = orb_lo; 1516121186Ssimokawa orbi->status.orb_hi = htons(orb_hi); 1517121186Ssimokawa orbi->status.orb_lo = htonl(orb_lo); 1518121186Ssimokawa 1519121186Ssimokawa switch (mode) { 1520121186Ssimokawa case FETCH_MGM: 1521121186Ssimokawa fwmem_read_block(fwdev, (void *)orbi, /*spd*/2, orb_hi, orb_lo, 1522129585Sdfr sizeof(uint32_t) * 8, &orbi->orb[0], 1523121186Ssimokawa sbp_targ_mgm_handler); 1524121186Ssimokawa break; 1525121186Ssimokawa case FETCH_CMD: 1526121186Ssimokawa orbi->state = ORBI_STATUS_FETCH; 1527123430Ssimokawa login->last_hi = orb_hi; 1528123430Ssimokawa login->last_lo = orb_lo; 1529123430Ssimokawa login->flags |= F_LINK_ACTIVE; 1530121186Ssimokawa /* dequeue */ 1531170374Ssimokawa SBP_LOCK(sc); 1532121186Ssimokawa orbi->atio = (struct ccb_accept_tio *) 1533123430Ssimokawa SLIST_FIRST(&login->lstate->accept_tios); 1534121186Ssimokawa if (orbi->atio == NULL) { 1535170374Ssimokawa SBP_UNLOCK(sc); 1536127468Ssimokawa printf("%s: no free atio\n", __func__); 1537123430Ssimokawa login->lstate->flags |= F_ATIO_STARVED; 1538123430Ssimokawa login->flags |= F_ATIO_STARVED; 1539123430Ssimokawa#if 0 1540123430Ssimokawa /* XXX ?? */ 1541123430Ssimokawa login->fwdev = fwdev; 1542123430Ssimokawa#endif 1543121186Ssimokawa break; 1544121186Ssimokawa } 1545123430Ssimokawa SLIST_REMOVE_HEAD(&login->lstate->accept_tios, sim_links.sle); 1546170374Ssimokawa STAILQ_INSERT_TAIL(&login->orbs, orbi, link); 1547170374Ssimokawa SBP_UNLOCK(sc); 1548121186Ssimokawa fwmem_read_block(fwdev, (void *)orbi, /*spd*/2, orb_hi, orb_lo, 1549129585Sdfr sizeof(uint32_t) * 8, &orbi->orb[0], 1550121186Ssimokawa sbp_targ_cmd_handler); 1551121186Ssimokawa break; 1552121186Ssimokawa case FETCH_POINTER: 1553121186Ssimokawa orbi->state = ORBI_STATUS_POINTER; 1554123430Ssimokawa login->flags |= F_LINK_ACTIVE; 1555121186Ssimokawa fwmem_read_block(fwdev, (void *)orbi, /*spd*/2, orb_hi, orb_lo, 1556129585Sdfr sizeof(uint32_t) * 2, &orbi->orb[0], 1557121186Ssimokawa sbp_targ_pointer_handler); 1558121186Ssimokawa break; 1559121186Ssimokawa default: 1560127468Ssimokawa printf("%s: invalid mode %d\n", __func__, mode); 1561121186Ssimokawa } 1562121186Ssimokawa} 1563121186Ssimokawa 1564121186Ssimokawastatic void 1565121186Ssimokawasbp_targ_resp_callback(struct fw_xfer *xfer) 1566121186Ssimokawa{ 1567121186Ssimokawa struct sbp_targ_softc *sc; 1568121186Ssimokawa int s; 1569121186Ssimokawa 1570121186Ssimokawa if (debug) 1571127468Ssimokawa printf("%s: xfer=%p\n", __func__, xfer); 1572121186Ssimokawa sc = (struct sbp_targ_softc *)xfer->sc; 1573121186Ssimokawa fw_xfer_unload(xfer); 1574121186Ssimokawa xfer->recv.pay_len = SBP_TARG_RECV_LEN; 1575167632Ssimokawa xfer->hand = sbp_targ_recv; 1576121186Ssimokawa s = splfw(); 1577121186Ssimokawa STAILQ_INSERT_TAIL(&sc->fwb.xferlist, xfer, link); 1578121186Ssimokawa splx(s); 1579121186Ssimokawa} 1580121186Ssimokawa 1581121186Ssimokawastatic int 1582123430Ssimokawasbp_targ_cmd(struct fw_xfer *xfer, struct fw_device *fwdev, int login_id, 1583123430Ssimokawa int reg) 1584121186Ssimokawa{ 1585123430Ssimokawa struct sbp_targ_login *login; 1586121186Ssimokawa struct sbp_targ_softc *sc; 1587121186Ssimokawa int rtcode = 0; 1588121186Ssimokawa 1589123430Ssimokawa if (login_id < 0 || login_id >= MAX_LOGINS) 1590121186Ssimokawa return(RESP_ADDRESS_ERROR); 1591121186Ssimokawa 1592121186Ssimokawa sc = (struct sbp_targ_softc *)xfer->sc; 1593123430Ssimokawa login = sc->logins[login_id]; 1594123430Ssimokawa if (login == NULL) 1595121186Ssimokawa return(RESP_ADDRESS_ERROR); 1596121186Ssimokawa 1597123430Ssimokawa if (login->fwdev != fwdev) { 1598123430Ssimokawa /* XXX */ 1599123430Ssimokawa return(RESP_ADDRESS_ERROR); 1600123430Ssimokawa } 1601123430Ssimokawa 1602121186Ssimokawa switch (reg) { 1603121186Ssimokawa case 0x08: /* ORB_POINTER */ 1604121186Ssimokawa if (debug) 1605170374Ssimokawa printf("%s: ORB_POINTER(%d)\n", __func__, login_id); 1606123430Ssimokawa if ((login->flags & F_LINK_ACTIVE) != 0) { 1607123430Ssimokawa if (debug) 1608123430Ssimokawa printf("link active (ORB_POINTER)\n"); 1609123430Ssimokawa break; 1610123430Ssimokawa } 1611123430Ssimokawa sbp_targ_fetch_orb(sc, fwdev, 1612121186Ssimokawa ntohl(xfer->recv.payload[0]), 1613121186Ssimokawa ntohl(xfer->recv.payload[1]), 1614123430Ssimokawa login, FETCH_CMD); 1615121186Ssimokawa break; 1616121186Ssimokawa case 0x04: /* AGENT_RESET */ 1617121186Ssimokawa if (debug) 1618170374Ssimokawa printf("%s: AGENT RESET(%d)\n", __func__, login_id); 1619123430Ssimokawa login->last_hi = 0xffff; 1620123430Ssimokawa login->last_lo = 0xffffffff; 1621170374Ssimokawa sbp_targ_abort(sc, STAILQ_FIRST(&login->orbs)); 1622121186Ssimokawa break; 1623121186Ssimokawa case 0x10: /* DOORBELL */ 1624121186Ssimokawa if (debug) 1625170374Ssimokawa printf("%s: DOORBELL(%d)\n", __func__, login_id); 1626123430Ssimokawa if (login->last_hi == 0xffff && 1627123430Ssimokawa login->last_lo == 0xffffffff) { 1628121186Ssimokawa printf("%s: no previous pointer(DOORBELL)\n", 1629127468Ssimokawa __func__); 1630121186Ssimokawa break; 1631121186Ssimokawa } 1632123430Ssimokawa if ((login->flags & F_LINK_ACTIVE) != 0) { 1633121186Ssimokawa if (debug) 1634121186Ssimokawa printf("link active (DOORBELL)\n"); 1635121186Ssimokawa break; 1636121186Ssimokawa } 1637123430Ssimokawa sbp_targ_fetch_orb(sc, fwdev, 1638123430Ssimokawa login->last_hi, login->last_lo, 1639123430Ssimokawa login, FETCH_POINTER); 1640121186Ssimokawa break; 1641121186Ssimokawa case 0x00: /* AGENT_STATE */ 1642170374Ssimokawa printf("%s: AGENT_STATE (%d:ignore)\n", __func__, login_id); 1643121186Ssimokawa break; 1644121186Ssimokawa case 0x14: /* UNSOLICITED_STATE_ENABLE */ 1645170374Ssimokawa printf("%s: UNSOLICITED_STATE_ENABLE (%d:ignore)\n", 1646170374Ssimokawa __func__, login_id); 1647121186Ssimokawa break; 1648121186Ssimokawa default: 1649170374Ssimokawa printf("%s: invalid register %d(%d)\n", 1650170374Ssimokawa __func__, reg, login_id); 1651121186Ssimokawa rtcode = RESP_ADDRESS_ERROR; 1652121186Ssimokawa } 1653121186Ssimokawa 1654121186Ssimokawa return (rtcode); 1655121186Ssimokawa} 1656121186Ssimokawa 1657121186Ssimokawastatic int 1658121186Ssimokawasbp_targ_mgm(struct fw_xfer *xfer, struct fw_device *fwdev) 1659121186Ssimokawa{ 1660121186Ssimokawa struct sbp_targ_softc *sc; 1661121186Ssimokawa struct fw_pkt *fp; 1662121186Ssimokawa 1663121186Ssimokawa sc = (struct sbp_targ_softc *)xfer->sc; 1664121186Ssimokawa 1665121186Ssimokawa fp = &xfer->recv.hdr; 1666121186Ssimokawa if (fp->mode.wreqb.tcode != FWTCODE_WREQB){ 1667127468Ssimokawa printf("%s: tcode = %d\n", __func__, fp->mode.wreqb.tcode); 1668121186Ssimokawa return(RESP_TYPE_ERROR); 1669121186Ssimokawa } 1670121186Ssimokawa 1671121186Ssimokawa sbp_targ_fetch_orb(sc, fwdev, 1672121186Ssimokawa ntohl(xfer->recv.payload[0]), 1673121186Ssimokawa ntohl(xfer->recv.payload[1]), 1674121186Ssimokawa NULL, FETCH_MGM); 1675121186Ssimokawa 1676121186Ssimokawa return(0); 1677121186Ssimokawa} 1678121186Ssimokawa 1679121186Ssimokawastatic void 1680121186Ssimokawasbp_targ_recv(struct fw_xfer *xfer) 1681121186Ssimokawa{ 1682121186Ssimokawa struct fw_pkt *fp, *sfp; 1683121186Ssimokawa struct fw_device *fwdev; 1684129585Sdfr uint32_t lo; 1685121186Ssimokawa int s, rtcode; 1686121186Ssimokawa struct sbp_targ_softc *sc; 1687121186Ssimokawa 1688121186Ssimokawa s = splfw(); 1689121186Ssimokawa sc = (struct sbp_targ_softc *)xfer->sc; 1690121186Ssimokawa fp = &xfer->recv.hdr; 1691121186Ssimokawa fwdev = fw_noderesolve_nodeid(sc->fd.fc, fp->mode.wreqb.src & 0x3f); 1692121186Ssimokawa if (fwdev == NULL) { 1693121186Ssimokawa printf("%s: cannot resolve nodeid=%d\n", 1694127468Ssimokawa __func__, fp->mode.wreqb.src & 0x3f); 1695121186Ssimokawa rtcode = RESP_TYPE_ERROR; /* XXX */ 1696121186Ssimokawa goto done; 1697121186Ssimokawa } 1698121186Ssimokawa lo = fp->mode.wreqb.dest_lo; 1699170374Ssimokawa 1700121186Ssimokawa if (lo == SBP_TARG_BIND_LO(-1)) 1701121186Ssimokawa rtcode = sbp_targ_mgm(xfer, fwdev); 1702121186Ssimokawa else if (lo >= SBP_TARG_BIND_LO(0)) 1703123430Ssimokawa rtcode = sbp_targ_cmd(xfer, fwdev, SBP_TARG_LOGIN_ID(lo), 1704123430Ssimokawa lo % 0x20); 1705121186Ssimokawa else 1706121186Ssimokawa rtcode = RESP_ADDRESS_ERROR; 1707121186Ssimokawa 1708121186Ssimokawadone: 1709121186Ssimokawa if (rtcode != 0) 1710127468Ssimokawa printf("%s: rtcode = %d\n", __func__, rtcode); 1711121186Ssimokawa sfp = &xfer->send.hdr; 1712121186Ssimokawa xfer->send.spd = 2; /* XXX */ 1713167632Ssimokawa xfer->hand = sbp_targ_resp_callback; 1714121186Ssimokawa sfp->mode.wres.dst = fp->mode.wreqb.src; 1715121186Ssimokawa sfp->mode.wres.tlrt = fp->mode.wreqb.tlrt; 1716121186Ssimokawa sfp->mode.wres.tcode = FWTCODE_WRES; 1717121186Ssimokawa sfp->mode.wres.rtcode = rtcode; 1718121186Ssimokawa sfp->mode.wres.pri = 0; 1719121186Ssimokawa 1720121186Ssimokawa fw_asyreq(xfer->fc, -1, xfer); 1721121186Ssimokawa splx(s); 1722121186Ssimokawa} 1723121186Ssimokawa 1724121186Ssimokawastatic int 1725121186Ssimokawasbp_targ_attach(device_t dev) 1726121186Ssimokawa{ 1727121186Ssimokawa struct sbp_targ_softc *sc; 1728121186Ssimokawa struct cam_devq *devq; 1729170374Ssimokawa struct firewire_comm *fc; 1730121186Ssimokawa 1731121186Ssimokawa sc = (struct sbp_targ_softc *) device_get_softc(dev); 1732121186Ssimokawa bzero((void *)sc, sizeof(struct sbp_targ_softc)); 1733121186Ssimokawa 1734170374Ssimokawa mtx_init(&sc->mtx, "sbp_targ", NULL, MTX_DEF); 1735170374Ssimokawa sc->fd.fc = fc = device_get_ivars(dev); 1736121186Ssimokawa sc->fd.dev = dev; 1737123430Ssimokawa sc->fd.post_explore = (void *) sbp_targ_post_explore; 1738121186Ssimokawa sc->fd.post_busreset = (void *) sbp_targ_post_busreset; 1739121186Ssimokawa 1740169475Ssimokawa devq = cam_simq_alloc(/*maxopenings*/MAX_LUN*MAX_INITIATORS); 1741121186Ssimokawa if (devq == NULL) 1742121186Ssimokawa return (ENXIO); 1743121186Ssimokawa 1744121186Ssimokawa sc->sim = cam_sim_alloc(sbp_targ_action, sbp_targ_poll, 1745170374Ssimokawa "sbp_targ", sc, device_get_unit(dev), &sc->mtx, 1746121186Ssimokawa /*untagged*/ 1, /*tagged*/ 1, devq); 1747121186Ssimokawa if (sc->sim == NULL) { 1748121186Ssimokawa cam_simq_free(devq); 1749121186Ssimokawa return (ENXIO); 1750121186Ssimokawa } 1751121186Ssimokawa 1752170374Ssimokawa SBP_LOCK(sc); 1753170872Sscottl if (xpt_bus_register(sc->sim, dev, /*bus*/0) != CAM_SUCCESS) 1754121186Ssimokawa goto fail; 1755121186Ssimokawa 1756121186Ssimokawa if (xpt_create_path(&sc->path, /*periph*/ NULL, cam_sim_path(sc->sim), 1757121186Ssimokawa CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 1758121186Ssimokawa xpt_bus_deregister(cam_sim_path(sc->sim)); 1759121186Ssimokawa goto fail; 1760121186Ssimokawa } 1761170374Ssimokawa SBP_UNLOCK(sc); 1762121186Ssimokawa 1763121186Ssimokawa sc->fwb.start = SBP_TARG_BIND_START; 1764121186Ssimokawa sc->fwb.end = SBP_TARG_BIND_END; 1765121186Ssimokawa 1766121186Ssimokawa /* pre-allocate xfer */ 1767121186Ssimokawa STAILQ_INIT(&sc->fwb.xferlist); 1768169130Ssimokawa fw_xferlist_add(&sc->fwb.xferlist, M_SBP_TARG, 1769169130Ssimokawa /*send*/ 0, /*recv*/ SBP_TARG_RECV_LEN, MAX_LUN /* XXX */, 1770170374Ssimokawa fc, (void *)sc, sbp_targ_recv); 1771170374Ssimokawa fw_bindadd(fc, &sc->fwb); 1772121186Ssimokawa return 0; 1773121186Ssimokawa 1774121186Ssimokawafail: 1775170374Ssimokawa SBP_UNLOCK(sc); 1776121186Ssimokawa cam_sim_free(sc->sim, /*free_devq*/TRUE); 1777121186Ssimokawa return (ENXIO); 1778121186Ssimokawa} 1779121186Ssimokawa 1780121186Ssimokawastatic int 1781121186Ssimokawasbp_targ_detach(device_t dev) 1782121186Ssimokawa{ 1783121186Ssimokawa struct sbp_targ_softc *sc; 1784121186Ssimokawa struct sbp_targ_lstate *lstate; 1785121186Ssimokawa int i; 1786121186Ssimokawa 1787121186Ssimokawa sc = (struct sbp_targ_softc *)device_get_softc(dev); 1788121186Ssimokawa sc->fd.post_busreset = NULL; 1789121186Ssimokawa 1790170374Ssimokawa SBP_LOCK(sc); 1791121186Ssimokawa xpt_free_path(sc->path); 1792121186Ssimokawa xpt_bus_deregister(cam_sim_path(sc->sim)); 1793170374Ssimokawa SBP_UNLOCK(sc); 1794121186Ssimokawa cam_sim_free(sc->sim, /*free_devq*/TRUE); 1795121186Ssimokawa 1796121186Ssimokawa for (i = 0; i < MAX_LUN; i ++) { 1797121186Ssimokawa lstate = sc->lstate[i]; 1798121186Ssimokawa if (lstate != NULL) { 1799121186Ssimokawa xpt_free_path(lstate->path); 1800121186Ssimokawa free(lstate, M_SBP_TARG); 1801121186Ssimokawa } 1802121186Ssimokawa } 1803121186Ssimokawa if (sc->black_hole != NULL) { 1804121186Ssimokawa xpt_free_path(sc->black_hole->path); 1805121186Ssimokawa free(sc->black_hole, M_SBP_TARG); 1806121186Ssimokawa } 1807121186Ssimokawa 1808121186Ssimokawa fw_bindremove(sc->fd.fc, &sc->fwb); 1809169130Ssimokawa fw_xferlist_remove(&sc->fwb.xferlist); 1810121186Ssimokawa 1811170374Ssimokawa mtx_destroy(&sc->mtx); 1812170374Ssimokawa 1813121186Ssimokawa return 0; 1814121186Ssimokawa} 1815121186Ssimokawa 1816121186Ssimokawastatic devclass_t sbp_targ_devclass; 1817121186Ssimokawa 1818121186Ssimokawastatic device_method_t sbp_targ_methods[] = { 1819121186Ssimokawa /* device interface */ 1820121186Ssimokawa DEVMETHOD(device_identify, sbp_targ_identify), 1821121186Ssimokawa DEVMETHOD(device_probe, sbp_targ_probe), 1822121186Ssimokawa DEVMETHOD(device_attach, sbp_targ_attach), 1823121186Ssimokawa DEVMETHOD(device_detach, sbp_targ_detach), 1824121186Ssimokawa { 0, 0 } 1825121186Ssimokawa}; 1826121186Ssimokawa 1827121186Ssimokawastatic driver_t sbp_targ_driver = { 1828121186Ssimokawa "sbp_targ", 1829121186Ssimokawa sbp_targ_methods, 1830121186Ssimokawa sizeof(struct sbp_targ_softc), 1831121186Ssimokawa}; 1832121186Ssimokawa 1833121186SsimokawaDRIVER_MODULE(sbp_targ, firewire, sbp_targ_driver, sbp_targ_devclass, 0, 0); 1834121186SsimokawaMODULE_VERSION(sbp_targ, 1); 1835121186SsimokawaMODULE_DEPEND(sbp_targ, firewire, 1, 1, 1); 1836121186SsimokawaMODULE_DEPEND(sbp_targ, cam, 1, 1, 1); 1837