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: stable/10/sys/dev/firewire/sbp_targ.c 315813 2017-03-23 06:41:13Z mav $ 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> 44225950Sken#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> 65230558Ssbruno#include <cam/scsi/scsi_message.h> 66121186Ssimokawa 67123430Ssimokawa#define SBP_TARG_RECV_LEN 8 68123430Ssimokawa#define MAX_INITIATORS 8 69123430Ssimokawa#define MAX_LUN 63 70123430Ssimokawa#define MAX_LOGINS 63 71123430Ssimokawa#define MAX_NODES 63 72121186Ssimokawa/* 73121186Ssimokawa * management/command block agent registers 74121186Ssimokawa * 75121186Ssimokawa * BASE 0xffff f001 0000 management port 76123430Ssimokawa * BASE 0xffff f001 0020 command port for login id 0 77123430Ssimokawa * BASE 0xffff f001 0040 command port for login id 1 78121186Ssimokawa * 79121186Ssimokawa */ 80121186Ssimokawa#define SBP_TARG_MGM 0x10000 /* offset from 0xffff f000 000 */ 81121186Ssimokawa#define SBP_TARG_BIND_HI 0xffff 82121186Ssimokawa#define SBP_TARG_BIND_LO(l) (0xf0000000 + SBP_TARG_MGM + 0x20 * ((l) + 1)) 83121186Ssimokawa#define SBP_TARG_BIND_START (((u_int64_t)SBP_TARG_BIND_HI << 32) | \ 84121186Ssimokawa SBP_TARG_BIND_LO(-1)) 85121186Ssimokawa#define SBP_TARG_BIND_END (((u_int64_t)SBP_TARG_BIND_HI << 32) | \ 86123430Ssimokawa SBP_TARG_BIND_LO(MAX_LOGINS)) 87123430Ssimokawa#define SBP_TARG_LOGIN_ID(lo) (((lo) - SBP_TARG_BIND_LO(0))/0x20) 88121186Ssimokawa 89121186Ssimokawa#define FETCH_MGM 0 90121186Ssimokawa#define FETCH_CMD 1 91121186Ssimokawa#define FETCH_POINTER 2 92121186Ssimokawa 93123430Ssimokawa#define F_LINK_ACTIVE (1 << 0) 94123430Ssimokawa#define F_ATIO_STARVED (1 << 1) 95123430Ssimokawa#define F_LOGIN (1 << 2) 96123430Ssimokawa#define F_HOLD (1 << 3) 97123430Ssimokawa#define F_FREEZED (1 << 4) 98123430Ssimokawa 99227293Sedstatic MALLOC_DEFINE(M_SBP_TARG, "sbp_targ", "SBP-II/FireWire target mode"); 100121186Ssimokawa 101121186Ssimokawastatic int debug = 0; 102121186Ssimokawa 103121186SsimokawaSYSCTL_INT(_debug, OID_AUTO, sbp_targ_debug, CTLFLAG_RW, &debug, 0, 104121186Ssimokawa "SBP target mode debug flag"); 105121186Ssimokawa 106123430Ssimokawastruct sbp_targ_login { 107123430Ssimokawa struct sbp_targ_lstate *lstate; 108123430Ssimokawa struct fw_device *fwdev; 109123430Ssimokawa struct sbp_login_res loginres; 110129585Sdfr uint16_t fifo_hi; 111129585Sdfr uint16_t last_hi; 112129585Sdfr uint32_t fifo_lo; 113129585Sdfr uint32_t last_lo; 114123430Ssimokawa STAILQ_HEAD(, orb_info) orbs; 115124877Ssimokawa STAILQ_ENTRY(sbp_targ_login) link; 116129585Sdfr uint16_t hold_sec; 117129585Sdfr uint16_t id; 118129585Sdfr uint8_t flags; 119129585Sdfr uint8_t spd; 120123430Ssimokawa struct callout hold_callout; 121123430Ssimokawa}; 122123430Ssimokawa 123123430Ssimokawastruct sbp_targ_lstate { 124129585Sdfr uint16_t lun; 125123430Ssimokawa struct sbp_targ_softc *sc; 126123430Ssimokawa struct cam_path *path; 127123430Ssimokawa struct ccb_hdr_slist accept_tios; 128123430Ssimokawa struct ccb_hdr_slist immed_notifies; 129123430Ssimokawa struct crom_chunk model; 130129585Sdfr uint32_t flags; 131123430Ssimokawa STAILQ_HEAD(, sbp_targ_login) logins; 132123430Ssimokawa}; 133123430Ssimokawa 134121186Ssimokawastruct sbp_targ_softc { 135121186Ssimokawa struct firewire_dev_comm fd; 136121186Ssimokawa struct cam_sim *sim; 137121186Ssimokawa struct cam_path *path; 138121186Ssimokawa struct fw_bind fwb; 139121186Ssimokawa int ndevs; 140123430Ssimokawa int flags; 141121186Ssimokawa struct crom_chunk unit; 142121186Ssimokawa struct sbp_targ_lstate *lstate[MAX_LUN]; 143121186Ssimokawa struct sbp_targ_lstate *black_hole; 144123430Ssimokawa struct sbp_targ_login *logins[MAX_LOGINS]; 145170374Ssimokawa struct mtx mtx; 146121186Ssimokawa}; 147170374Ssimokawa#define SBP_LOCK(sc) mtx_lock(&(sc)->mtx) 148170374Ssimokawa#define SBP_UNLOCK(sc) mtx_unlock(&(sc)->mtx) 149121186Ssimokawa 150121186Ssimokawastruct corb4 { 151121186Ssimokawa#if BYTE_ORDER == BIG_ENDIAN 152129585Sdfr uint32_t n:1, 153121186Ssimokawa rq_fmt:2, 154121186Ssimokawa :1, 155121186Ssimokawa dir:1, 156121186Ssimokawa spd:3, 157121186Ssimokawa max_payload:4, 158121186Ssimokawa page_table_present:1, 159121186Ssimokawa page_size:3, 160121186Ssimokawa data_size:16; 161121186Ssimokawa#else 162129585Sdfr uint32_t data_size:16, 163121186Ssimokawa page_size:3, 164121186Ssimokawa page_table_present:1, 165121186Ssimokawa max_payload:4, 166121186Ssimokawa spd:3, 167121186Ssimokawa dir:1, 168121186Ssimokawa :1, 169121186Ssimokawa rq_fmt:2, 170121186Ssimokawa n:1; 171121186Ssimokawa#endif 172121186Ssimokawa}; 173121186Ssimokawa 174121186Ssimokawastruct morb4 { 175121186Ssimokawa#if BYTE_ORDER == BIG_ENDIAN 176129585Sdfr uint32_t n:1, 177121186Ssimokawa rq_fmt:2, 178121186Ssimokawa :9, 179121186Ssimokawa fun:4, 180121186Ssimokawa id:16; 181121186Ssimokawa#else 182129585Sdfr uint32_t id:16, 183121186Ssimokawa fun:4, 184121186Ssimokawa :9, 185121186Ssimokawa rq_fmt:2, 186121186Ssimokawa n:1; 187121186Ssimokawa#endif 188121186Ssimokawa}; 189121186Ssimokawa 190230558Ssbruno 191230558Ssbruno/* 192230558Ssbruno * Urestricted page table format 193230558Ssbruno * states that the segment length 194230558Ssbruno * and high base addr are in the first 195230558Ssbruno * 32 bits and the base low is in 196230558Ssbruno * the second 197230558Ssbruno */ 198230558Ssbrunostruct unrestricted_page_table_fmt { 199230558Ssbruno uint16_t segment_len; 200230558Ssbruno uint16_t segment_base_high; 201230558Ssbruno uint32_t segment_base_low; 202230558Ssbruno}; 203230558Ssbruno 204230558Ssbruno 205121186Ssimokawastruct orb_info { 206121186Ssimokawa struct sbp_targ_softc *sc; 207121186Ssimokawa struct fw_device *fwdev; 208123430Ssimokawa struct sbp_targ_login *login; 209121186Ssimokawa union ccb *ccb; 210121186Ssimokawa struct ccb_accept_tio *atio; 211129585Sdfr uint8_t state; 212121186Ssimokawa#define ORBI_STATUS_NONE 0 213121186Ssimokawa#define ORBI_STATUS_FETCH 1 214121186Ssimokawa#define ORBI_STATUS_ATIO 2 215121186Ssimokawa#define ORBI_STATUS_CTIO 3 216121186Ssimokawa#define ORBI_STATUS_STATUS 4 217121186Ssimokawa#define ORBI_STATUS_POINTER 5 218121186Ssimokawa#define ORBI_STATUS_ABORTED 7 219129585Sdfr uint8_t refcount; 220129585Sdfr uint16_t orb_hi; 221129585Sdfr uint32_t orb_lo; 222129585Sdfr uint32_t data_hi; 223129585Sdfr uint32_t data_lo; 224121186Ssimokawa struct corb4 orb4; 225121186Ssimokawa STAILQ_ENTRY(orb_info) link; 226129585Sdfr uint32_t orb[8]; 227230558Ssbruno struct unrestricted_page_table_fmt *page_table; 228230558Ssbruno struct unrestricted_page_table_fmt *cur_pte; 229230558Ssbruno struct unrestricted_page_table_fmt *last_pte; 230230558Ssbruno uint32_t last_block_read; 231121186Ssimokawa struct sbp_status status; 232121186Ssimokawa}; 233121186Ssimokawa 234121186Ssimokawastatic char *orb_fun_name[] = { 235121186Ssimokawa ORB_FUN_NAMES 236121186Ssimokawa}; 237121186Ssimokawa 238121186Ssimokawastatic void sbp_targ_recv(struct fw_xfer *); 239121186Ssimokawastatic void sbp_targ_fetch_orb(struct sbp_targ_softc *, struct fw_device *, 240129585Sdfr uint16_t, uint32_t, struct sbp_targ_login *, int); 241230558Ssbrunostatic void sbp_targ_xfer_pt(struct orb_info *); 242170374Ssimokawastatic void sbp_targ_abort(struct sbp_targ_softc *, struct orb_info *); 243121186Ssimokawa 244121186Ssimokawastatic void 245121186Ssimokawasbp_targ_identify(driver_t *driver, device_t parent) 246121186Ssimokawa{ 247121186Ssimokawa BUS_ADD_CHILD(parent, 0, "sbp_targ", device_get_unit(parent)); 248121186Ssimokawa} 249121186Ssimokawa 250121186Ssimokawastatic int 251121186Ssimokawasbp_targ_probe(device_t dev) 252121186Ssimokawa{ 253121186Ssimokawa device_t pa; 254121186Ssimokawa 255121186Ssimokawa pa = device_get_parent(dev); 256121186Ssimokawa if(device_get_unit(dev) != device_get_unit(pa)){ 257121186Ssimokawa return(ENXIO); 258121186Ssimokawa } 259121186Ssimokawa 260121186Ssimokawa device_set_desc(dev, "SBP-2/SCSI over FireWire target mode"); 261121186Ssimokawa return (0); 262121186Ssimokawa} 263121186Ssimokawa 264121186Ssimokawastatic void 265123430Ssimokawasbp_targ_dealloc_login(struct sbp_targ_login *login) 266123430Ssimokawa{ 267123430Ssimokawa struct orb_info *orbi, *next; 268123430Ssimokawa 269123430Ssimokawa if (login == NULL) { 270127468Ssimokawa printf("%s: login = NULL\n", __func__); 271123430Ssimokawa return; 272123430Ssimokawa } 273123430Ssimokawa for (orbi = STAILQ_FIRST(&login->orbs); orbi != NULL; orbi = next) { 274123430Ssimokawa next = STAILQ_NEXT(orbi, link); 275230558Ssbruno if (debug) 276230558Ssbruno printf("%s: free orbi %p\n", __func__, orbi); 277123430Ssimokawa free(orbi, M_SBP_TARG); 278230558Ssbruno orbi = NULL; 279123430Ssimokawa } 280123430Ssimokawa callout_stop(&login->hold_callout); 281123430Ssimokawa 282123430Ssimokawa STAILQ_REMOVE(&login->lstate->logins, login, sbp_targ_login, link); 283123430Ssimokawa login->lstate->sc->logins[login->id] = NULL; 284230558Ssbruno if (debug) 285230558Ssbruno printf("%s: free login %p\n", __func__, login); 286123430Ssimokawa free((void *)login, M_SBP_TARG); 287230558Ssbruno login = NULL; 288123430Ssimokawa} 289123430Ssimokawa 290123430Ssimokawastatic void 291123430Ssimokawasbp_targ_hold_expire(void *arg) 292123430Ssimokawa{ 293123430Ssimokawa struct sbp_targ_login *login; 294123430Ssimokawa 295123430Ssimokawa login = (struct sbp_targ_login *)arg; 296123430Ssimokawa 297123430Ssimokawa if (login->flags & F_HOLD) { 298127468Ssimokawa printf("%s: login_id=%d expired\n", __func__, login->id); 299123430Ssimokawa sbp_targ_dealloc_login(login); 300123430Ssimokawa } else { 301127468Ssimokawa printf("%s: login_id=%d not hold\n", __func__, login->id); 302123430Ssimokawa } 303123430Ssimokawa} 304123430Ssimokawa 305123430Ssimokawastatic void 306121186Ssimokawasbp_targ_post_busreset(void *arg) 307121186Ssimokawa{ 308121186Ssimokawa struct sbp_targ_softc *sc; 309121186Ssimokawa struct crom_src *src; 310121186Ssimokawa struct crom_chunk *root; 311121186Ssimokawa struct crom_chunk *unit; 312121186Ssimokawa struct sbp_targ_lstate *lstate; 313123430Ssimokawa struct sbp_targ_login *login; 314121186Ssimokawa int i; 315121186Ssimokawa 316123430Ssimokawa sc = (struct sbp_targ_softc *)arg; 317121186Ssimokawa src = sc->fd.fc->crom_src; 318121186Ssimokawa root = sc->fd.fc->crom_root; 319121186Ssimokawa 320121186Ssimokawa unit = &sc->unit; 321121186Ssimokawa 322123430Ssimokawa if ((sc->flags & F_FREEZED) == 0) { 323170374Ssimokawa SBP_LOCK(sc); 324123430Ssimokawa sc->flags |= F_FREEZED; 325123430Ssimokawa xpt_freeze_simq(sc->sim, /*count*/1); 326170374Ssimokawa SBP_UNLOCK(sc); 327123430Ssimokawa } else { 328127468Ssimokawa printf("%s: already freezed\n", __func__); 329123430Ssimokawa } 330123430Ssimokawa 331121186Ssimokawa bzero(unit, sizeof(struct crom_chunk)); 332121186Ssimokawa 333121186Ssimokawa crom_add_chunk(src, root, unit, CROM_UDIR); 334121186Ssimokawa crom_add_entry(unit, CSRKEY_SPEC, CSRVAL_ANSIT10); 335121186Ssimokawa crom_add_entry(unit, CSRKEY_VER, CSRVAL_T10SBP2); 336121186Ssimokawa crom_add_entry(unit, CSRKEY_COM_SPEC, CSRVAL_ANSIT10); 337121186Ssimokawa crom_add_entry(unit, CSRKEY_COM_SET, CSRVAL_SCSI); 338121186Ssimokawa 339121186Ssimokawa crom_add_entry(unit, CROM_MGM, SBP_TARG_MGM >> 2); 340121186Ssimokawa crom_add_entry(unit, CSRKEY_UNIT_CH, (10<<8) | 8); 341121186Ssimokawa 342121186Ssimokawa for (i = 0; i < MAX_LUN; i ++) { 343121186Ssimokawa lstate = sc->lstate[i]; 344121186Ssimokawa if (lstate == NULL) 345121186Ssimokawa continue; 346121186Ssimokawa crom_add_entry(unit, CSRKEY_FIRM_VER, 1); 347121186Ssimokawa crom_add_entry(unit, CROM_LUN, i); 348121186Ssimokawa crom_add_entry(unit, CSRKEY_MODEL, 1); 349121186Ssimokawa crom_add_simple_text(src, unit, &lstate->model, "TargetMode"); 350121186Ssimokawa } 351123430Ssimokawa 352123430Ssimokawa /* Process for reconnection hold time */ 353123430Ssimokawa for (i = 0; i < MAX_LOGINS; i ++) { 354123430Ssimokawa login = sc->logins[i]; 355123430Ssimokawa if (login == NULL) 356123430Ssimokawa continue; 357170374Ssimokawa sbp_targ_abort(sc, STAILQ_FIRST(&login->orbs)); 358123430Ssimokawa if (login->flags & F_LOGIN) { 359123430Ssimokawa login->flags |= F_HOLD; 360123430Ssimokawa callout_reset(&login->hold_callout, 361123430Ssimokawa hz * login->hold_sec, 362123430Ssimokawa sbp_targ_hold_expire, (void *)login); 363123430Ssimokawa } 364123430Ssimokawa } 365121186Ssimokawa} 366121186Ssimokawa 367123430Ssimokawastatic void 368123430Ssimokawasbp_targ_post_explore(void *arg) 369123430Ssimokawa{ 370123430Ssimokawa struct sbp_targ_softc *sc; 371123430Ssimokawa 372123430Ssimokawa sc = (struct sbp_targ_softc *)arg; 373170374Ssimokawa SBP_LOCK(sc); 374123430Ssimokawa sc->flags &= ~F_FREEZED; 375123430Ssimokawa xpt_release_simq(sc->sim, /*run queue*/TRUE); 376170374Ssimokawa SBP_UNLOCK(sc); 377123430Ssimokawa return; 378123430Ssimokawa} 379123430Ssimokawa 380121186Ssimokawastatic cam_status 381121186Ssimokawasbp_targ_find_devs(struct sbp_targ_softc *sc, union ccb *ccb, 382121186Ssimokawa struct sbp_targ_lstate **lstate, int notfound_failure) 383121186Ssimokawa{ 384121186Ssimokawa u_int lun; 385121186Ssimokawa 386121186Ssimokawa /* XXX 0 is the only vaild target_id */ 387121186Ssimokawa if (ccb->ccb_h.target_id == CAM_TARGET_WILDCARD && 388121186Ssimokawa ccb->ccb_h.target_lun == CAM_LUN_WILDCARD) { 389121186Ssimokawa *lstate = sc->black_hole; 390230558Ssbruno if (debug) 391230558Ssbruno printf("setting black hole for this target id(%d)\n", ccb->ccb_h.target_id); 392121186Ssimokawa return (CAM_REQ_CMP); 393121186Ssimokawa } 394121186Ssimokawa 395121186Ssimokawa lun = ccb->ccb_h.target_lun; 396121186Ssimokawa if (lun >= MAX_LUN) 397121186Ssimokawa return (CAM_LUN_INVALID); 398121186Ssimokawa 399121186Ssimokawa *lstate = sc->lstate[lun]; 400121186Ssimokawa 401230558Ssbruno if (notfound_failure != 0 && *lstate == NULL) { 402230558Ssbruno if (debug) 403230558Ssbruno printf("%s: lstate for lun is invalid, target(%d), lun(%d)\n", 404230558Ssbruno __func__, ccb->ccb_h.target_id, lun); 405121186Ssimokawa return (CAM_PATH_INVALID); 406230558Ssbruno } else 407230558Ssbruno if (debug) 408230558Ssbruno printf("%s: setting lstate for tgt(%d) lun(%d)\n", 409230558Ssbruno __func__,ccb->ccb_h.target_id, lun); 410121186Ssimokawa 411121186Ssimokawa return (CAM_REQ_CMP); 412121186Ssimokawa} 413121186Ssimokawa 414121186Ssimokawastatic void 415121186Ssimokawasbp_targ_en_lun(struct sbp_targ_softc *sc, union ccb *ccb) 416121186Ssimokawa{ 417121186Ssimokawa struct ccb_en_lun *cel = &ccb->cel; 418121186Ssimokawa struct sbp_targ_lstate *lstate; 419121186Ssimokawa cam_status status; 420121186Ssimokawa 421121186Ssimokawa status = sbp_targ_find_devs(sc, ccb, &lstate, 0); 422121186Ssimokawa if (status != CAM_REQ_CMP) { 423121186Ssimokawa ccb->ccb_h.status = status; 424121186Ssimokawa return; 425121186Ssimokawa } 426121186Ssimokawa 427121186Ssimokawa if (cel->enable != 0) { 428121186Ssimokawa if (lstate != NULL) { 429121186Ssimokawa xpt_print_path(ccb->ccb_h.path); 430121186Ssimokawa printf("Lun already enabled\n"); 431121186Ssimokawa ccb->ccb_h.status = CAM_LUN_ALRDY_ENA; 432121186Ssimokawa return; 433121186Ssimokawa } 434121186Ssimokawa if (cel->grp6_len != 0 || cel->grp7_len != 0) { 435121186Ssimokawa ccb->ccb_h.status = CAM_REQ_INVALID; 436121186Ssimokawa printf("Non-zero Group Codes\n"); 437121186Ssimokawa return; 438121186Ssimokawa } 439121186Ssimokawa lstate = (struct sbp_targ_lstate *) 440121186Ssimokawa malloc(sizeof(*lstate), M_SBP_TARG, M_NOWAIT | M_ZERO); 441121186Ssimokawa if (lstate == NULL) { 442121186Ssimokawa xpt_print_path(ccb->ccb_h.path); 443121186Ssimokawa printf("Couldn't allocate lstate\n"); 444121186Ssimokawa ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 445121186Ssimokawa return; 446230558Ssbruno } else { 447230558Ssbruno if (debug) 448230558Ssbruno printf("%s: malloc'd lstate %p\n",__func__, lstate); 449230558Ssbruno } 450230558Ssbruno if (ccb->ccb_h.target_id == CAM_TARGET_WILDCARD) { 451121186Ssimokawa sc->black_hole = lstate; 452230558Ssbruno if (debug) 453230558Ssbruno printf("Blackhole set due to target id == %d\n", 454230558Ssbruno ccb->ccb_h.target_id); 455230558Ssbruno } else 456121186Ssimokawa sc->lstate[ccb->ccb_h.target_lun] = lstate; 457230558Ssbruno 458121186Ssimokawa memset(lstate, 0, sizeof(*lstate)); 459121186Ssimokawa lstate->sc = sc; 460121186Ssimokawa status = xpt_create_path(&lstate->path, /*periph*/NULL, 461121186Ssimokawa xpt_path_path_id(ccb->ccb_h.path), 462121186Ssimokawa xpt_path_target_id(ccb->ccb_h.path), 463121186Ssimokawa xpt_path_lun_id(ccb->ccb_h.path)); 464121186Ssimokawa if (status != CAM_REQ_CMP) { 465121186Ssimokawa free(lstate, M_SBP_TARG); 466230558Ssbruno lstate = NULL; 467121186Ssimokawa xpt_print_path(ccb->ccb_h.path); 468121186Ssimokawa printf("Couldn't allocate path\n"); 469121186Ssimokawa ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 470121186Ssimokawa return; 471121186Ssimokawa } 472121186Ssimokawa SLIST_INIT(&lstate->accept_tios); 473121186Ssimokawa SLIST_INIT(&lstate->immed_notifies); 474123430Ssimokawa STAILQ_INIT(&lstate->logins); 475121186Ssimokawa 476121186Ssimokawa ccb->ccb_h.status = CAM_REQ_CMP; 477121186Ssimokawa xpt_print_path(ccb->ccb_h.path); 478121186Ssimokawa printf("Lun now enabled for target mode\n"); 479121186Ssimokawa /* bus reset */ 480121186Ssimokawa sc->fd.fc->ibr(sc->fd.fc); 481121186Ssimokawa } else { 482123430Ssimokawa struct sbp_targ_login *login, *next; 483123430Ssimokawa 484121186Ssimokawa if (lstate == NULL) { 485121186Ssimokawa ccb->ccb_h.status = CAM_LUN_INVALID; 486230558Ssbruno printf("Invalid lstate for this target\n"); 487121186Ssimokawa return; 488121186Ssimokawa } 489121186Ssimokawa ccb->ccb_h.status = CAM_REQ_CMP; 490121186Ssimokawa 491121186Ssimokawa if (SLIST_FIRST(&lstate->accept_tios) != NULL) { 492121186Ssimokawa printf("ATIOs pending\n"); 493121186Ssimokawa ccb->ccb_h.status = CAM_REQ_INVALID; 494121186Ssimokawa } 495121186Ssimokawa 496121186Ssimokawa if (SLIST_FIRST(&lstate->immed_notifies) != NULL) { 497121186Ssimokawa printf("INOTs pending\n"); 498121186Ssimokawa ccb->ccb_h.status = CAM_REQ_INVALID; 499121186Ssimokawa } 500121186Ssimokawa 501121186Ssimokawa if (ccb->ccb_h.status != CAM_REQ_CMP) { 502230558Ssbruno printf("status != CAM_REQ_CMP\n"); 503121186Ssimokawa return; 504121186Ssimokawa } 505121186Ssimokawa 506121186Ssimokawa xpt_print_path(ccb->ccb_h.path); 507121186Ssimokawa printf("Target mode disabled\n"); 508121186Ssimokawa xpt_free_path(lstate->path); 509121186Ssimokawa 510123430Ssimokawa for (login = STAILQ_FIRST(&lstate->logins); login != NULL; 511123430Ssimokawa login = next) { 512123430Ssimokawa next = STAILQ_NEXT(login, link); 513123430Ssimokawa sbp_targ_dealloc_login(login); 514121186Ssimokawa } 515121186Ssimokawa 516121186Ssimokawa if (ccb->ccb_h.target_id == CAM_TARGET_WILDCARD) 517121186Ssimokawa sc->black_hole = NULL; 518121186Ssimokawa else 519121186Ssimokawa sc->lstate[ccb->ccb_h.target_lun] = NULL; 520230558Ssbruno if (debug) 521230558Ssbruno printf("%s: free lstate %p\n", __func__, lstate); 522121186Ssimokawa free(lstate, M_SBP_TARG); 523230558Ssbruno lstate = NULL; 524121186Ssimokawa 525121186Ssimokawa /* bus reset */ 526121186Ssimokawa sc->fd.fc->ibr(sc->fd.fc); 527121186Ssimokawa } 528121186Ssimokawa} 529121186Ssimokawa 530121186Ssimokawastatic void 531121186Ssimokawasbp_targ_send_lstate_events(struct sbp_targ_softc *sc, 532121186Ssimokawa struct sbp_targ_lstate *lstate) 533121186Ssimokawa{ 534121186Ssimokawa#if 0 535121186Ssimokawa struct ccb_hdr *ccbh; 536237601Sken struct ccb_immediate_notify *inot; 537121186Ssimokawa 538127468Ssimokawa printf("%s: not implemented yet\n", __func__); 539121186Ssimokawa#endif 540121186Ssimokawa} 541121186Ssimokawa 542170374Ssimokawa 543121186Ssimokawastatic __inline void 544170374Ssimokawasbp_targ_remove_orb_info_locked(struct sbp_targ_login *login, struct orb_info *orbi) 545170374Ssimokawa{ 546170374Ssimokawa STAILQ_REMOVE(&login->orbs, orbi, orb_info, link); 547170374Ssimokawa} 548170374Ssimokawa 549170374Ssimokawastatic __inline void 550123430Ssimokawasbp_targ_remove_orb_info(struct sbp_targ_login *login, struct orb_info *orbi) 551121186Ssimokawa{ 552170374Ssimokawa SBP_LOCK(orbi->sc); 553123430Ssimokawa STAILQ_REMOVE(&login->orbs, orbi, orb_info, link); 554170374Ssimokawa SBP_UNLOCK(orbi->sc); 555121186Ssimokawa} 556121186Ssimokawa 557121186Ssimokawa/* 558121186Ssimokawa * tag_id/init_id encoding 559121186Ssimokawa * 560121186Ssimokawa * tag_id and init_id has only 32bit for each. 561121186Ssimokawa * scsi_target can handle very limited number(up to 15) of init_id. 562121186Ssimokawa * we have to encode 48bit orb and 64bit EUI64 into these 563121186Ssimokawa * variables. 564121186Ssimokawa * 565121186Ssimokawa * tag_id represents lower 32bit of ORB address. 566123430Ssimokawa * init_id represents login_id. 567121186Ssimokawa * 568121186Ssimokawa */ 569121186Ssimokawa 570121186Ssimokawastatic struct orb_info * 571121186Ssimokawasbp_targ_get_orb_info(struct sbp_targ_lstate *lstate, 572121186Ssimokawa u_int tag_id, u_int init_id) 573121186Ssimokawa{ 574123430Ssimokawa struct sbp_targ_login *login; 575121186Ssimokawa struct orb_info *orbi; 576121186Ssimokawa 577123430Ssimokawa login = lstate->sc->logins[init_id]; 578123430Ssimokawa if (login == NULL) { 579127468Ssimokawa printf("%s: no such login\n", __func__); 580123430Ssimokawa return (NULL); 581123430Ssimokawa } 582123430Ssimokawa STAILQ_FOREACH(orbi, &login->orbs, link) 583123430Ssimokawa if (orbi->orb_lo == tag_id) 584121186Ssimokawa goto found; 585170374Ssimokawa printf("%s: orb not found tag_id=0x%08x init_id=%d\n", 586230558Ssbruno __func__, tag_id, init_id); 587121186Ssimokawa return (NULL); 588121186Ssimokawafound: 589121186Ssimokawa return (orbi); 590121186Ssimokawa} 591121186Ssimokawa 592121186Ssimokawastatic void 593170374Ssimokawasbp_targ_abort(struct sbp_targ_softc *sc, struct orb_info *orbi) 594121186Ssimokawa{ 595121186Ssimokawa struct orb_info *norbi; 596121186Ssimokawa 597170374Ssimokawa SBP_LOCK(sc); 598121186Ssimokawa for (; orbi != NULL; orbi = norbi) { 599170374Ssimokawa printf("%s: status=%d ccb=%p\n", __func__, orbi->state, orbi->ccb); 600121186Ssimokawa norbi = STAILQ_NEXT(orbi, link); 601121186Ssimokawa if (orbi->state != ORBI_STATUS_ABORTED) { 602121186Ssimokawa if (orbi->ccb != NULL) { 603121186Ssimokawa orbi->ccb->ccb_h.status = CAM_REQ_ABORTED; 604121186Ssimokawa xpt_done(orbi->ccb); 605121186Ssimokawa orbi->ccb = NULL; 606121186Ssimokawa } 607121186Ssimokawa if (orbi->state <= ORBI_STATUS_ATIO) { 608170374Ssimokawa sbp_targ_remove_orb_info_locked(orbi->login, orbi); 609230558Ssbruno if (debug) 610230558Ssbruno printf("%s: free orbi %p\n", __func__, orbi); 611121186Ssimokawa free(orbi, M_SBP_TARG); 612230558Ssbruno orbi = NULL; 613121186Ssimokawa } else 614121186Ssimokawa orbi->state = ORBI_STATUS_ABORTED; 615121186Ssimokawa } 616121186Ssimokawa } 617170374Ssimokawa SBP_UNLOCK(sc); 618121186Ssimokawa} 619121186Ssimokawa 620121186Ssimokawastatic void 621121186Ssimokawasbp_targ_free_orbi(struct fw_xfer *xfer) 622121186Ssimokawa{ 623121186Ssimokawa struct orb_info *orbi; 624121186Ssimokawa 625121186Ssimokawa if (xfer->resp != 0) { 626121186Ssimokawa /* XXX */ 627127468Ssimokawa printf("%s: xfer->resp = %d\n", __func__, xfer->resp); 628121186Ssimokawa } 629230558Ssbruno orbi = (struct orb_info *)xfer->sc; 630230558Ssbruno if ( orbi->page_table != NULL ) { 631230558Ssbruno if (debug) 632230558Ssbruno printf("%s: free orbi->page_table %p\n", __func__, orbi->page_table); 633230558Ssbruno free(orbi->page_table, M_SBP_TARG); 634230558Ssbruno orbi->page_table = NULL; 635230558Ssbruno } 636230558Ssbruno if (debug) 637230558Ssbruno printf("%s: free orbi %p\n", __func__, orbi); 638121186Ssimokawa free(orbi, M_SBP_TARG); 639230558Ssbruno orbi = NULL; 640121186Ssimokawa fw_xfer_free(xfer); 641121186Ssimokawa} 642121186Ssimokawa 643121186Ssimokawastatic void 644121186Ssimokawasbp_targ_status_FIFO(struct orb_info *orbi, 645129585Sdfr uint32_t fifo_hi, uint32_t fifo_lo, int dequeue) 646121186Ssimokawa{ 647121186Ssimokawa struct fw_xfer *xfer; 648121186Ssimokawa 649121186Ssimokawa if (dequeue) 650123430Ssimokawa sbp_targ_remove_orb_info(orbi->login, orbi); 651121186Ssimokawa 652121186Ssimokawa xfer = fwmem_write_block(orbi->fwdev, (void *)orbi, 653230558Ssbruno /*spd*/FWSPD_S400, fifo_hi, fifo_lo, 654129585Sdfr sizeof(uint32_t) * (orbi->status.len + 1), (char *)&orbi->status, 655121186Ssimokawa sbp_targ_free_orbi); 656121186Ssimokawa 657121186Ssimokawa if (xfer == NULL) { 658121186Ssimokawa /* XXX */ 659127468Ssimokawa printf("%s: xfer == NULL\n", __func__); 660121186Ssimokawa } 661121186Ssimokawa} 662121186Ssimokawa 663230558Ssbruno/* 664230558Ssbruno * Generate the appropriate CAM status for the 665230558Ssbruno * target. 666230558Ssbruno */ 667121186Ssimokawastatic void 668121186Ssimokawasbp_targ_send_status(struct orb_info *orbi, union ccb *ccb) 669121186Ssimokawa{ 670121186Ssimokawa struct sbp_status *sbp_status; 671170410Smjacob#if 0 672170374Ssimokawa struct orb_info *norbi; 673170410Smjacob#endif 674121186Ssimokawa 675121186Ssimokawa sbp_status = &orbi->status; 676121186Ssimokawa 677121186Ssimokawa orbi->state = ORBI_STATUS_STATUS; 678121186Ssimokawa 679121186Ssimokawa sbp_status->resp = 0; /* XXX */ 680121186Ssimokawa sbp_status->status = 0; /* XXX */ 681121186Ssimokawa sbp_status->dead = 0; /* XXX */ 682121186Ssimokawa 683230558Ssbruno ccb->ccb_h.status= CAM_REQ_CMP; 684230558Ssbruno 685121186Ssimokawa switch (ccb->csio.scsi_status) { 686121186Ssimokawa case SCSI_STATUS_OK: 687121186Ssimokawa if (debug) 688127468Ssimokawa printf("%s: STATUS_OK\n", __func__); 689121186Ssimokawa sbp_status->len = 1; 690121186Ssimokawa break; 691121186Ssimokawa case SCSI_STATUS_CHECK_COND: 692230558Ssbruno if (debug) 693230558Ssbruno printf("%s: STATUS SCSI_STATUS_CHECK_COND\n", __func__); 694230558Ssbruno goto process_scsi_status; 695121186Ssimokawa case SCSI_STATUS_BUSY: 696230558Ssbruno if (debug) 697230558Ssbruno printf("%s: STATUS SCSI_STATUS_BUSY\n", __func__); 698230558Ssbruno goto process_scsi_status; 699121186Ssimokawa case SCSI_STATUS_CMD_TERMINATED: 700230558Ssbrunoprocess_scsi_status: 701121186Ssimokawa { 702121186Ssimokawa struct sbp_cmd_status *sbp_cmd_status; 703121186Ssimokawa struct scsi_sense_data *sense; 704225950Sken int error_code, sense_key, asc, ascq; 705225950Sken uint8_t stream_bits; 706225950Sken uint8_t sks[3]; 707225950Sken uint64_t info; 708225950Sken int64_t sinfo; 709225950Sken int sense_len; 710121186Ssimokawa 711121186Ssimokawa sbp_cmd_status = (struct sbp_cmd_status *)&sbp_status->data[0]; 712121186Ssimokawa sbp_cmd_status->status = ccb->csio.scsi_status; 713121186Ssimokawa sense = &ccb->csio.sense_data; 714121186Ssimokawa 715170374Ssimokawa#if 0 /* XXX What we should do? */ 716170374Ssimokawa#if 0 717170374Ssimokawa sbp_targ_abort(orbi->sc, STAILQ_NEXT(orbi, link)); 718170374Ssimokawa#else 719170374Ssimokawa norbi = STAILQ_NEXT(orbi, link); 720170374Ssimokawa while (norbi) { 721170374Ssimokawa printf("%s: status=%d\n", __func__, norbi->state); 722170374Ssimokawa if (norbi->ccb != NULL) { 723170374Ssimokawa norbi->ccb->ccb_h.status = CAM_REQ_ABORTED; 724170374Ssimokawa xpt_done(norbi->ccb); 725170374Ssimokawa norbi->ccb = NULL; 726170374Ssimokawa } 727170374Ssimokawa sbp_targ_remove_orb_info_locked(orbi->login, norbi); 728170374Ssimokawa norbi = STAILQ_NEXT(norbi, link); 729170374Ssimokawa free(norbi, M_SBP_TARG); 730170374Ssimokawa } 731170374Ssimokawa#endif 732170374Ssimokawa#endif 733121186Ssimokawa 734225950Sken sense_len = ccb->csio.sense_len - ccb->csio.sense_resid; 735225950Sken scsi_extract_sense_len(sense, sense_len, &error_code, 736225950Sken &sense_key, &asc, &ascq, /*show_errors*/ 0); 737225950Sken 738225950Sken switch (error_code) { 739225950Sken case SSD_CURRENT_ERROR: 740225950Sken case SSD_DESC_CURRENT_ERROR: 741121186Ssimokawa sbp_cmd_status->sfmt = SBP_SFMT_CURR; 742225950Sken break; 743225950Sken default: 744121186Ssimokawa sbp_cmd_status->sfmt = SBP_SFMT_DEFER; 745225950Sken break; 746225950Sken } 747121186Ssimokawa 748225950Sken if (scsi_get_sense_info(sense, sense_len, SSD_DESC_INFO, &info, 749225950Sken &sinfo) == 0) { 750225950Sken uint32_t info_trunc; 751225950Sken sbp_cmd_status->valid = 1; 752225950Sken info_trunc = info; 753121186Ssimokawa 754225950Sken sbp_cmd_status->info = htobe32(info_trunc); 755225950Sken } else { 756225950Sken sbp_cmd_status->valid = 0; 757225950Sken } 758121186Ssimokawa 759225950Sken sbp_cmd_status->s_key = sense_key; 760225950Sken 761225950Sken if (scsi_get_stream_info(sense, sense_len, NULL, 762225950Sken &stream_bits) == 0) { 763225950Sken sbp_cmd_status->mark = 764225950Sken (stream_bits & SSD_FILEMARK) ? 1 : 0; 765225950Sken sbp_cmd_status->eom = 766225950Sken (stream_bits & SSD_EOM) ? 1 : 0; 767225950Sken sbp_cmd_status->ill_len = 768225950Sken (stream_bits & SSD_ILI) ? 1 : 0; 769225950Sken } else { 770225950Sken sbp_cmd_status->mark = 0; 771225950Sken sbp_cmd_status->eom = 0; 772225950Sken sbp_cmd_status->ill_len = 0; 773225950Sken } 774225950Sken 775225950Sken 776225950Sken /* add_sense_code(_qual), info, cmd_spec_info */ 777225950Sken sbp_status->len = 4; 778225950Sken 779225950Sken if (scsi_get_sense_info(sense, sense_len, SSD_DESC_COMMAND, 780225950Sken &info, &sinfo) == 0) { 781225950Sken uint32_t cmdspec_trunc; 782225950Sken 783225950Sken cmdspec_trunc = info; 784225950Sken 785225950Sken sbp_cmd_status->cdb = htobe32(cmdspec_trunc); 786225950Sken } 787225950Sken 788225950Sken sbp_cmd_status->s_code = asc; 789225950Sken sbp_cmd_status->s_qlfr = ascq; 790225950Sken 791225950Sken if (scsi_get_sense_info(sense, sense_len, SSD_DESC_FRU, &info, 792225950Sken &sinfo) == 0) { 793225950Sken sbp_cmd_status->fru = (uint8_t)info; 794121186Ssimokawa sbp_status->len = 5; 795225950Sken } else { 796225950Sken sbp_cmd_status->fru = 0; 797225950Sken } 798121186Ssimokawa 799225950Sken if (scsi_get_sks(sense, sense_len, sks) == 0) { 800225950Sken bcopy(sks, &sbp_cmd_status->s_keydep[0], sizeof(sks)); 801225950Sken sbp_status->len = 5; 802230558Ssbruno ccb->ccb_h.status |= CAM_SENT_SENSE; 803225950Sken } 804121186Ssimokawa 805121186Ssimokawa break; 806121186Ssimokawa } 807121186Ssimokawa default: 808127468Ssimokawa printf("%s: unknown scsi status 0x%x\n", __func__, 809121186Ssimokawa sbp_status->status); 810121186Ssimokawa } 811121186Ssimokawa 812170374Ssimokawa 813121186Ssimokawa sbp_targ_status_FIFO(orbi, 814123430Ssimokawa orbi->login->fifo_hi, orbi->login->fifo_lo, /*dequeue*/1); 815121186Ssimokawa} 816121186Ssimokawa 817230558Ssbruno/* 818230558Ssbruno * Invoked as a callback handler from fwmem_read/write_block 819230558Ssbruno * 820230558Ssbruno * Process read/write of initiator address space 821230558Ssbruno * completion and pass status onto the backend target. 822230558Ssbruno * If this is a partial read/write for a CCB then 823230558Ssbruno * we decrement the orbi's refcount to indicate 824230558Ssbruno * the status of the read/write is complete 825230558Ssbruno */ 826121186Ssimokawastatic void 827121186Ssimokawasbp_targ_cam_done(struct fw_xfer *xfer) 828121186Ssimokawa{ 829121186Ssimokawa struct orb_info *orbi; 830121186Ssimokawa union ccb *ccb; 831121186Ssimokawa 832121186Ssimokawa orbi = (struct orb_info *)xfer->sc; 833121186Ssimokawa 834230558Ssbruno if (debug) 835127468Ssimokawa printf("%s: resp=%d refcount=%d\n", __func__, 836121186Ssimokawa xfer->resp, orbi->refcount); 837121186Ssimokawa 838121186Ssimokawa if (xfer->resp != 0) { 839127468Ssimokawa printf("%s: xfer->resp = %d\n", __func__, xfer->resp); 840121186Ssimokawa orbi->status.resp = SBP_TRANS_FAIL; 841124877Ssimokawa orbi->status.status = OBJ_DATA | SBE_TIMEOUT/*XXX*/; 842121186Ssimokawa orbi->status.dead = 1; 843170374Ssimokawa sbp_targ_abort(orbi->sc, STAILQ_NEXT(orbi, link)); 844121186Ssimokawa } 845121186Ssimokawa 846121186Ssimokawa orbi->refcount --; 847121186Ssimokawa 848121186Ssimokawa ccb = orbi->ccb; 849121186Ssimokawa if (orbi->refcount == 0) { 850170374Ssimokawa orbi->ccb = NULL; 851121186Ssimokawa if (orbi->state == ORBI_STATUS_ABORTED) { 852121186Ssimokawa if (debug) 853127468Ssimokawa printf("%s: orbi aborted\n", __func__); 854123430Ssimokawa sbp_targ_remove_orb_info(orbi->login, orbi); 855230558Ssbruno if (orbi->page_table != NULL) { 856230558Ssbruno if (debug) 857230558Ssbruno printf("%s: free orbi->page_table %p\n", 858230558Ssbruno __func__, orbi->page_table); 859121186Ssimokawa free(orbi->page_table, M_SBP_TARG); 860230558Ssbruno } 861230558Ssbruno if (debug) 862230558Ssbruno printf("%s: free orbi %p\n", __func__, orbi); 863121186Ssimokawa free(orbi, M_SBP_TARG); 864230558Ssbruno orbi = NULL; 865230558Ssbruno } else if (orbi->status.resp == ORBI_STATUS_NONE) { 866230558Ssbruno if ((ccb->ccb_h.flags & CAM_SEND_STATUS) != 0) { 867230558Ssbruno if (debug) 868230558Ssbruno printf("%s: CAM_SEND_STATUS set %0x\n", __func__, ccb->ccb_h.flags); 869121186Ssimokawa sbp_targ_send_status(orbi, ccb); 870230558Ssbruno } else { 871230558Ssbruno if (debug) 872230558Ssbruno printf("%s: CAM_SEND_STATUS not set %0x\n", __func__, ccb->ccb_h.flags); 873230558Ssbruno ccb->ccb_h.status = CAM_REQ_CMP; 874230558Ssbruno } 875170374Ssimokawa SBP_LOCK(orbi->sc); 876121186Ssimokawa xpt_done(ccb); 877170374Ssimokawa SBP_UNLOCK(orbi->sc); 878121186Ssimokawa } else { 879121186Ssimokawa orbi->status.len = 1; 880121186Ssimokawa sbp_targ_status_FIFO(orbi, 881123430Ssimokawa orbi->login->fifo_hi, orbi->login->fifo_lo, 882121186Ssimokawa /*dequeue*/1); 883121186Ssimokawa ccb->ccb_h.status = CAM_REQ_ABORTED; 884170374Ssimokawa SBP_LOCK(orbi->sc); 885121186Ssimokawa xpt_done(ccb); 886170374Ssimokawa SBP_UNLOCK(orbi->sc); 887121186Ssimokawa } 888121186Ssimokawa } 889121186Ssimokawa 890121186Ssimokawa fw_xfer_free(xfer); 891121186Ssimokawa} 892121186Ssimokawa 893121186Ssimokawastatic cam_status 894121186Ssimokawasbp_targ_abort_ccb(struct sbp_targ_softc *sc, union ccb *ccb) 895121186Ssimokawa{ 896121186Ssimokawa union ccb *accb; 897121186Ssimokawa struct sbp_targ_lstate *lstate; 898121186Ssimokawa struct ccb_hdr_slist *list; 899121186Ssimokawa struct ccb_hdr *curelm; 900121186Ssimokawa int found; 901121186Ssimokawa cam_status status; 902121186Ssimokawa 903121186Ssimokawa status = sbp_targ_find_devs(sc, ccb, &lstate, 0); 904121186Ssimokawa if (status != CAM_REQ_CMP) 905121186Ssimokawa return (status); 906121186Ssimokawa 907121186Ssimokawa accb = ccb->cab.abort_ccb; 908121186Ssimokawa 909121186Ssimokawa if (accb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO) 910121186Ssimokawa list = &lstate->accept_tios; 911237601Sken else if (accb->ccb_h.func_code == XPT_IMMEDIATE_NOTIFY) 912121186Ssimokawa list = &lstate->immed_notifies; 913121186Ssimokawa else 914121186Ssimokawa return (CAM_UA_ABORT); 915121186Ssimokawa 916121186Ssimokawa curelm = SLIST_FIRST(list); 917121186Ssimokawa found = 0; 918121186Ssimokawa if (curelm == &accb->ccb_h) { 919121186Ssimokawa found = 1; 920121186Ssimokawa SLIST_REMOVE_HEAD(list, sim_links.sle); 921121186Ssimokawa } else { 922121186Ssimokawa while(curelm != NULL) { 923121186Ssimokawa struct ccb_hdr *nextelm; 924121186Ssimokawa 925121186Ssimokawa nextelm = SLIST_NEXT(curelm, sim_links.sle); 926121186Ssimokawa if (nextelm == &accb->ccb_h) { 927121186Ssimokawa found = 1; 928121186Ssimokawa SLIST_NEXT(curelm, sim_links.sle) = 929121186Ssimokawa SLIST_NEXT(nextelm, sim_links.sle); 930121186Ssimokawa break; 931121186Ssimokawa } 932121186Ssimokawa curelm = nextelm; 933121186Ssimokawa } 934121186Ssimokawa } 935121186Ssimokawa if (found) { 936121186Ssimokawa accb->ccb_h.status = CAM_REQ_ABORTED; 937121186Ssimokawa xpt_done(accb); 938121186Ssimokawa return (CAM_REQ_CMP); 939121186Ssimokawa } 940127468Ssimokawa printf("%s: not found\n", __func__); 941121186Ssimokawa return (CAM_PATH_INVALID); 942121186Ssimokawa} 943121186Ssimokawa 944230558Ssbruno/* 945230558Ssbruno * directly execute a read or write to the initiator 946230558Ssbruno * address space and set hand(sbp_targ_cam_done) to 947230558Ssbruno * process the completion from the SIM to the target. 948230558Ssbruno * set orbi->refcount to inidicate that a read/write 949230558Ssbruno * is inflight to/from the initiator. 950230558Ssbruno */ 951121186Ssimokawastatic void 952121186Ssimokawasbp_targ_xfer_buf(struct orb_info *orbi, u_int offset, 953129585Sdfr uint16_t dst_hi, uint32_t dst_lo, u_int size, 954121186Ssimokawa void (*hand)(struct fw_xfer *)) 955121186Ssimokawa{ 956121186Ssimokawa struct fw_xfer *xfer; 957121186Ssimokawa u_int len, ccb_dir, off = 0; 958121186Ssimokawa char *ptr; 959121186Ssimokawa 960123430Ssimokawa if (debug > 1) 961127468Ssimokawa printf("%s: offset=%d size=%d\n", __func__, offset, size); 962121186Ssimokawa ccb_dir = orbi->ccb->ccb_h.flags & CAM_DIR_MASK; 963121186Ssimokawa ptr = (char *)orbi->ccb->csio.data_ptr + offset; 964121186Ssimokawa 965121186Ssimokawa while (size > 0) { 966121186Ssimokawa /* XXX assume dst_lo + off doesn't overflow */ 967121186Ssimokawa len = MIN(size, 2048 /* XXX */); 968121186Ssimokawa size -= len; 969121186Ssimokawa orbi->refcount ++; 970230558Ssbruno if (ccb_dir == CAM_DIR_OUT) { 971230558Ssbruno if (debug) 972230558Ssbruno printf("%s: CAM_DIR_OUT --> read block in?\n",__func__); 973121186Ssimokawa xfer = fwmem_read_block(orbi->fwdev, 974230558Ssbruno (void *)orbi, /*spd*/FWSPD_S400, 975121186Ssimokawa dst_hi, dst_lo + off, len, 976121186Ssimokawa ptr + off, hand); 977230558Ssbruno } else { 978230558Ssbruno if (debug) 979230558Ssbruno printf("%s: CAM_DIR_IN --> write block out?\n",__func__); 980121186Ssimokawa xfer = fwmem_write_block(orbi->fwdev, 981230558Ssbruno (void *)orbi, /*spd*/FWSPD_S400, 982121186Ssimokawa dst_hi, dst_lo + off, len, 983121186Ssimokawa ptr + off, hand); 984230558Ssbruno } 985121186Ssimokawa if (xfer == NULL) { 986127468Ssimokawa printf("%s: xfer == NULL", __func__); 987121186Ssimokawa /* XXX what should we do?? */ 988121186Ssimokawa orbi->refcount --; 989121186Ssimokawa } 990121186Ssimokawa off += len; 991121186Ssimokawa } 992121186Ssimokawa} 993121186Ssimokawa 994121186Ssimokawastatic void 995121186Ssimokawasbp_targ_pt_done(struct fw_xfer *xfer) 996121186Ssimokawa{ 997121186Ssimokawa struct orb_info *orbi; 998230558Ssbruno struct unrestricted_page_table_fmt *pt; 999230558Ssbruno uint32_t i; 1000121186Ssimokawa 1001121186Ssimokawa orbi = (struct orb_info *)xfer->sc; 1002230558Ssbruno 1003121186Ssimokawa if (orbi->state == ORBI_STATUS_ABORTED) { 1004121186Ssimokawa if (debug) 1005127468Ssimokawa printf("%s: orbi aborted\n", __func__); 1006123430Ssimokawa sbp_targ_remove_orb_info(orbi->login, orbi); 1007230558Ssbruno if (debug) { 1008230558Ssbruno printf("%s: free orbi->page_table %p\n", __func__, orbi->page_table); 1009230558Ssbruno printf("%s: free orbi %p\n", __func__, orbi); 1010230558Ssbruno } 1011121186Ssimokawa free(orbi->page_table, M_SBP_TARG); 1012121186Ssimokawa free(orbi, M_SBP_TARG); 1013230558Ssbruno orbi = NULL; 1014121186Ssimokawa fw_xfer_free(xfer); 1015121186Ssimokawa return; 1016121186Ssimokawa } 1017121186Ssimokawa if (xfer->resp != 0) { 1018127468Ssimokawa printf("%s: xfer->resp = %d\n", __func__, xfer->resp); 1019121186Ssimokawa orbi->status.resp = SBP_TRANS_FAIL; 1020124877Ssimokawa orbi->status.status = OBJ_PT | SBE_TIMEOUT/*XXX*/; 1021121186Ssimokawa orbi->status.dead = 1; 1022121186Ssimokawa orbi->status.len = 1; 1023170374Ssimokawa sbp_targ_abort(orbi->sc, STAILQ_NEXT(orbi, link)); 1024121186Ssimokawa 1025230558Ssbruno if (debug) 1026230558Ssbruno printf("%s: free orbi->page_table %p\n", __func__, orbi->page_table); 1027230558Ssbruno 1028121186Ssimokawa sbp_targ_status_FIFO(orbi, 1029123430Ssimokawa orbi->login->fifo_hi, orbi->login->fifo_lo, /*dequeue*/1); 1030121186Ssimokawa free(orbi->page_table, M_SBP_TARG); 1031230558Ssbruno orbi->page_table = NULL; 1032121186Ssimokawa fw_xfer_free(xfer); 1033121186Ssimokawa return; 1034121186Ssimokawa } 1035230558Ssbruno orbi->refcount++; 1036230558Ssbruno/* 1037230558Ssbruno * Set endianess here so we don't have 1038230558Ssbruno * to deal with is later 1039230558Ssbruno */ 1040230558Ssbruno for (i = 0, pt = orbi->page_table; i < orbi->orb4.data_size; i++, pt++) { 1041230558Ssbruno pt->segment_len = ntohs(pt->segment_len); 1042230558Ssbruno if (debug) 1043230558Ssbruno printf("%s:segment_len = %u\n", __func__,pt->segment_len); 1044230558Ssbruno pt->segment_base_high = ntohs(pt->segment_base_high); 1045230558Ssbruno pt->segment_base_low = ntohl(pt->segment_base_low); 1046121186Ssimokawa } 1047230558Ssbruno 1048230558Ssbruno sbp_targ_xfer_pt(orbi); 1049230558Ssbruno 1050230558Ssbruno orbi->refcount--; 1051121186Ssimokawa if (orbi->refcount == 0) 1052127468Ssimokawa printf("%s: refcount == 0\n", __func__); 1053121186Ssimokawa 1054121186Ssimokawa fw_xfer_free(xfer); 1055121186Ssimokawa return; 1056121186Ssimokawa} 1057121186Ssimokawa 1058230558Ssbrunostatic void sbp_targ_xfer_pt(struct orb_info *orbi) 1059230558Ssbruno{ 1060230558Ssbruno union ccb *ccb; 1061230558Ssbruno uint32_t res, offset, len; 1062230558Ssbruno 1063230558Ssbruno ccb = orbi->ccb; 1064230558Ssbruno if (debug) 1065230558Ssbruno printf("%s: dxfer_len=%d\n", __func__, ccb->csio.dxfer_len); 1066230558Ssbruno res = ccb->csio.dxfer_len; 1067230558Ssbruno /* 1068230558Ssbruno * If the page table required multiple CTIO's to 1069230558Ssbruno * complete, then cur_pte is non NULL 1070230558Ssbruno * and we need to start from the last position 1071230558Ssbruno * If this is the first pass over a page table 1072230558Ssbruno * then we just start at the beginning of the page 1073230558Ssbruno * table. 1074230558Ssbruno * 1075230558Ssbruno * Parse the unrestricted page table and figure out where we need 1076230558Ssbruno * to shove the data from this read request. 1077230558Ssbruno */ 1078230558Ssbruno for (offset = 0, len = 0; (res != 0) && (orbi->cur_pte < orbi->last_pte); offset += len) { 1079230558Ssbruno len = MIN(orbi->cur_pte->segment_len, res); 1080230558Ssbruno res -= len; 1081230558Ssbruno if (debug) 1082230558Ssbruno printf("%s:page_table: %04x:%08x segment_len(%u) res(%u) len(%u)\n", 1083230558Ssbruno __func__, orbi->cur_pte->segment_base_high, 1084230558Ssbruno orbi->cur_pte->segment_base_low, 1085230558Ssbruno orbi->cur_pte->segment_len, 1086230558Ssbruno res, len); 1087230558Ssbruno sbp_targ_xfer_buf(orbi, offset, 1088230558Ssbruno orbi->cur_pte->segment_base_high, 1089230558Ssbruno orbi->cur_pte->segment_base_low, 1090230558Ssbruno len, sbp_targ_cam_done); 1091230558Ssbruno /* 1092230558Ssbruno * If we have only written partially to 1093230558Ssbruno * this page table, then we need to save 1094230558Ssbruno * our position for the next CTIO. If we 1095230558Ssbruno * have completed the page table, then we 1096230558Ssbruno * are safe to move on to the next entry. 1097230558Ssbruno */ 1098230558Ssbruno if (len == orbi->cur_pte->segment_len) { 1099230558Ssbruno orbi->cur_pte++; 1100230558Ssbruno } else { 1101230558Ssbruno uint32_t saved_base_low; 1102230558Ssbruno 1103230558Ssbruno /* Handle transfers that cross a 4GB boundary. */ 1104230558Ssbruno saved_base_low = orbi->cur_pte->segment_base_low; 1105230558Ssbruno orbi->cur_pte->segment_base_low += len; 1106230558Ssbruno if (orbi->cur_pte->segment_base_low < saved_base_low) 1107230558Ssbruno orbi->cur_pte->segment_base_high++; 1108230558Ssbruno 1109230558Ssbruno orbi->cur_pte->segment_len -= len; 1110230558Ssbruno } 1111230558Ssbruno } 1112230558Ssbruno if (debug) { 1113230558Ssbruno printf("%s: base_low(%08x) page_table_off(%p) last_block(%u)\n", 1114230558Ssbruno __func__, orbi->cur_pte->segment_base_low, 1115230558Ssbruno orbi->cur_pte, orbi->last_block_read); 1116230558Ssbruno } 1117230558Ssbruno if (res != 0) 1118230558Ssbruno printf("Warning - short pt encountered. " 1119230558Ssbruno "Could not transfer all data.\n"); 1120230558Ssbruno return; 1121230558Ssbruno} 1122230558Ssbruno 1123230558Ssbruno/* 1124230558Ssbruno * Create page table in local memory 1125230558Ssbruno * and transfer it from the initiator 1126230558Ssbruno * in order to know where we are supposed 1127230558Ssbruno * to put the data. 1128230558Ssbruno */ 1129230558Ssbruno 1130121186Ssimokawastatic void 1131121186Ssimokawasbp_targ_fetch_pt(struct orb_info *orbi) 1132121186Ssimokawa{ 1133121186Ssimokawa struct fw_xfer *xfer; 1134121186Ssimokawa 1135230558Ssbruno /* 1136230558Ssbruno * Pull in page table from initiator 1137230558Ssbruno * and setup for data from our 1138230558Ssbruno * backend device. 1139230558Ssbruno */ 1140230558Ssbruno if (orbi->page_table == NULL) { 1141230558Ssbruno orbi->page_table = malloc(orbi->orb4.data_size* 1142230558Ssbruno sizeof(struct unrestricted_page_table_fmt), 1143230558Ssbruno M_SBP_TARG, M_NOWAIT|M_ZERO); 1144230558Ssbruno if (orbi->page_table == NULL) 1145230558Ssbruno goto error; 1146230558Ssbruno orbi->cur_pte = orbi->page_table; 1147230558Ssbruno orbi->last_pte = orbi->page_table + orbi->orb4.data_size; 1148230558Ssbruno orbi->last_block_read = orbi->orb4.data_size; 1149230558Ssbruno if (debug && orbi->page_table != NULL) 1150230558Ssbruno printf("%s: malloc'd orbi->page_table(%p), orb4.data_size(%u)\n", 1151230558Ssbruno __func__, orbi->page_table, orbi->orb4.data_size); 1152230558Ssbruno 1153230558Ssbruno xfer = fwmem_read_block(orbi->fwdev, (void *)orbi, /*spd*/FWSPD_S400, 1154230558Ssbruno orbi->data_hi, orbi->data_lo, orbi->orb4.data_size* 1155230558Ssbruno sizeof(struct unrestricted_page_table_fmt), 1156230558Ssbruno (void *)orbi->page_table, sbp_targ_pt_done); 1157230558Ssbruno 1158230558Ssbruno if (xfer != NULL) 1159230558Ssbruno return; 1160230558Ssbruno } else { 1161230558Ssbruno /* 1162230558Ssbruno * This is a CTIO for a page table we have 1163230558Ssbruno * already malloc'd, so just directly invoke 1164230558Ssbruno * the xfer function on the orbi. 1165230558Ssbruno */ 1166230558Ssbruno sbp_targ_xfer_pt(orbi); 1167121186Ssimokawa return; 1168230558Ssbruno } 1169121186Ssimokawaerror: 1170121186Ssimokawa orbi->ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 1171230558Ssbruno if (debug) 1172230558Ssbruno printf("%s: free orbi->page_table %p due to xfer == NULL\n", __func__, orbi->page_table); 1173230558Ssbruno if (orbi->page_table != NULL) { 1174230558Ssbruno free(orbi->page_table, M_SBP_TARG); 1175230558Ssbruno orbi->page_table = NULL; 1176230558Ssbruno } 1177121186Ssimokawa xpt_done(orbi->ccb); 1178121186Ssimokawa return; 1179121186Ssimokawa} 1180121186Ssimokawa 1181121186Ssimokawastatic void 1182121186Ssimokawasbp_targ_action1(struct cam_sim *sim, union ccb *ccb) 1183121186Ssimokawa{ 1184121186Ssimokawa struct sbp_targ_softc *sc; 1185121186Ssimokawa struct sbp_targ_lstate *lstate; 1186121186Ssimokawa cam_status status; 1187121186Ssimokawa u_int ccb_dir; 1188121186Ssimokawa 1189121186Ssimokawa sc = (struct sbp_targ_softc *)cam_sim_softc(sim); 1190121186Ssimokawa 1191121186Ssimokawa status = sbp_targ_find_devs(sc, ccb, &lstate, TRUE); 1192121186Ssimokawa 1193121186Ssimokawa switch (ccb->ccb_h.func_code) { 1194121186Ssimokawa case XPT_CONT_TARGET_IO: 1195121186Ssimokawa { 1196121186Ssimokawa struct orb_info *orbi; 1197121186Ssimokawa 1198121186Ssimokawa if (debug) 1199170374Ssimokawa printf("%s: XPT_CONT_TARGET_IO (0x%08x)\n", 1200170374Ssimokawa __func__, ccb->csio.tag_id); 1201121186Ssimokawa 1202121186Ssimokawa if (status != CAM_REQ_CMP) { 1203121186Ssimokawa ccb->ccb_h.status = status; 1204121186Ssimokawa xpt_done(ccb); 1205121186Ssimokawa break; 1206121186Ssimokawa } 1207121186Ssimokawa /* XXX transfer from/to initiator */ 1208121186Ssimokawa orbi = sbp_targ_get_orb_info(lstate, 1209121186Ssimokawa ccb->csio.tag_id, ccb->csio.init_id); 1210121186Ssimokawa if (orbi == NULL) { 1211121186Ssimokawa ccb->ccb_h.status = CAM_REQ_ABORTED; /* XXX */ 1212121186Ssimokawa xpt_done(ccb); 1213121186Ssimokawa break; 1214121186Ssimokawa } 1215121186Ssimokawa if (orbi->state == ORBI_STATUS_ABORTED) { 1216121186Ssimokawa if (debug) 1217127468Ssimokawa printf("%s: ctio aborted\n", __func__); 1218170374Ssimokawa sbp_targ_remove_orb_info_locked(orbi->login, orbi); 1219230558Ssbruno if (debug) 1220230558Ssbruno printf("%s: free orbi %p\n", __func__, orbi); 1221121186Ssimokawa free(orbi, M_SBP_TARG); 1222170374Ssimokawa ccb->ccb_h.status = CAM_REQ_ABORTED; 1223170374Ssimokawa xpt_done(ccb); 1224121186Ssimokawa break; 1225121186Ssimokawa } 1226121186Ssimokawa orbi->state = ORBI_STATUS_CTIO; 1227121186Ssimokawa 1228121186Ssimokawa orbi->ccb = ccb; 1229121186Ssimokawa ccb_dir = ccb->ccb_h.flags & CAM_DIR_MASK; 1230121186Ssimokawa 1231121186Ssimokawa /* XXX */ 1232121186Ssimokawa if (ccb->csio.dxfer_len == 0) 1233121186Ssimokawa ccb_dir = CAM_DIR_NONE; 1234121186Ssimokawa 1235121186Ssimokawa /* Sanity check */ 1236121186Ssimokawa if (ccb_dir == CAM_DIR_IN && orbi->orb4.dir == 0) 1237127468Ssimokawa printf("%s: direction mismatch\n", __func__); 1238121186Ssimokawa 1239121186Ssimokawa /* check page table */ 1240121186Ssimokawa if (ccb_dir != CAM_DIR_NONE && orbi->orb4.page_table_present) { 1241121186Ssimokawa if (debug) 1242121186Ssimokawa printf("%s: page_table_present\n", 1243127468Ssimokawa __func__); 1244121186Ssimokawa if (orbi->orb4.page_size != 0) { 1245121186Ssimokawa printf("%s: unsupported pagesize %d != 0\n", 1246127468Ssimokawa __func__, orbi->orb4.page_size); 1247121186Ssimokawa ccb->ccb_h.status = CAM_REQ_INVALID; 1248121186Ssimokawa xpt_done(ccb); 1249121186Ssimokawa break; 1250121186Ssimokawa } 1251121186Ssimokawa sbp_targ_fetch_pt(orbi); 1252121186Ssimokawa break; 1253121186Ssimokawa } 1254121186Ssimokawa 1255121186Ssimokawa /* Sanity check */ 1256230558Ssbruno if (ccb_dir != CAM_DIR_NONE) { 1257121186Ssimokawa sbp_targ_xfer_buf(orbi, 0, orbi->data_hi, 1258121186Ssimokawa orbi->data_lo, 1259121186Ssimokawa MIN(orbi->orb4.data_size, ccb->csio.dxfer_len), 1260121186Ssimokawa sbp_targ_cam_done); 1261230558Ssbruno if ( orbi->orb4.data_size > ccb->csio.dxfer_len ) { 1262230558Ssbruno orbi->data_lo += ccb->csio.dxfer_len; 1263230558Ssbruno orbi->orb4.data_size -= ccb->csio.dxfer_len; 1264230558Ssbruno } 1265230558Ssbruno } 1266121186Ssimokawa 1267121186Ssimokawa if (ccb_dir == CAM_DIR_NONE) { 1268170374Ssimokawa if ((ccb->ccb_h.flags & CAM_SEND_STATUS) != 0) { 1269170374Ssimokawa /* XXX */ 1270170374Ssimokawa SBP_UNLOCK(sc); 1271121186Ssimokawa sbp_targ_send_status(orbi, ccb); 1272170374Ssimokawa SBP_LOCK(sc); 1273170374Ssimokawa } 1274121186Ssimokawa ccb->ccb_h.status = CAM_REQ_CMP; 1275121186Ssimokawa xpt_done(ccb); 1276121186Ssimokawa } 1277121186Ssimokawa break; 1278121186Ssimokawa } 1279121186Ssimokawa case XPT_ACCEPT_TARGET_IO: /* Add Accept Target IO Resource */ 1280121186Ssimokawa if (status != CAM_REQ_CMP) { 1281121186Ssimokawa ccb->ccb_h.status = status; 1282121186Ssimokawa xpt_done(ccb); 1283121186Ssimokawa break; 1284121186Ssimokawa } 1285121186Ssimokawa SLIST_INSERT_HEAD(&lstate->accept_tios, &ccb->ccb_h, 1286121186Ssimokawa sim_links.sle); 1287121186Ssimokawa ccb->ccb_h.status = CAM_REQ_INPROG; 1288123430Ssimokawa if ((lstate->flags & F_ATIO_STARVED) != 0) { 1289123430Ssimokawa struct sbp_targ_login *login; 1290123430Ssimokawa 1291121186Ssimokawa if (debug) 1292127468Ssimokawa printf("%s: new atio arrived\n", __func__); 1293123430Ssimokawa lstate->flags &= ~F_ATIO_STARVED; 1294123430Ssimokawa STAILQ_FOREACH(login, &lstate->logins, link) 1295123430Ssimokawa if ((login->flags & F_ATIO_STARVED) != 0) { 1296123430Ssimokawa login->flags &= ~F_ATIO_STARVED; 1297123430Ssimokawa sbp_targ_fetch_orb(lstate->sc, 1298123430Ssimokawa login->fwdev, 1299123430Ssimokawa login->last_hi, login->last_lo, 1300123430Ssimokawa login, FETCH_CMD); 1301123430Ssimokawa } 1302121186Ssimokawa } 1303121186Ssimokawa break; 1304237601Sken case XPT_NOTIFY_ACKNOWLEDGE: /* recycle notify ack */ 1305237601Sken case XPT_IMMEDIATE_NOTIFY: /* Add Immediate Notify Resource */ 1306121186Ssimokawa if (status != CAM_REQ_CMP) { 1307121186Ssimokawa ccb->ccb_h.status = status; 1308121186Ssimokawa xpt_done(ccb); 1309121186Ssimokawa break; 1310121186Ssimokawa } 1311121186Ssimokawa SLIST_INSERT_HEAD(&lstate->immed_notifies, &ccb->ccb_h, 1312121186Ssimokawa sim_links.sle); 1313121186Ssimokawa ccb->ccb_h.status = CAM_REQ_INPROG; 1314121186Ssimokawa sbp_targ_send_lstate_events(sc, lstate); 1315121186Ssimokawa break; 1316121186Ssimokawa case XPT_EN_LUN: 1317121186Ssimokawa sbp_targ_en_lun(sc, ccb); 1318121186Ssimokawa xpt_done(ccb); 1319121186Ssimokawa break; 1320121186Ssimokawa case XPT_PATH_INQ: 1321121186Ssimokawa { 1322121186Ssimokawa struct ccb_pathinq *cpi = &ccb->cpi; 1323121186Ssimokawa 1324121186Ssimokawa cpi->version_num = 1; /* XXX??? */ 1325121186Ssimokawa cpi->hba_inquiry = PI_TAG_ABLE; 1326121186Ssimokawa cpi->target_sprt = PIT_PROCESSOR 1327121186Ssimokawa | PIT_DISCONNECT 1328121186Ssimokawa | PIT_TERM_IO; 1329230558Ssbruno cpi->transport = XPORT_SPI; /* FIXME add XPORT_FW type to cam */ 1330314725Smav cpi->hba_misc = PIM_NOINITIATOR | PIM_NOBUSRESET | 1331314725Smav PIM_NO_6_BYTE; 1332121186Ssimokawa cpi->hba_eng_cnt = 0; 1333121186Ssimokawa cpi->max_target = 7; /* XXX */ 1334121186Ssimokawa cpi->max_lun = MAX_LUN - 1; 1335121186Ssimokawa cpi->initiator_id = 7; /* XXX */ 1336121186Ssimokawa cpi->bus_id = sim->bus_id; 1337121186Ssimokawa cpi->base_transfer_speed = 400 * 1000 / 8; 1338315813Smav strlcpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 1339315813Smav strlcpy(cpi->hba_vid, "SBP_TARG", HBA_IDLEN); 1340315813Smav strlcpy(cpi->dev_name, sim->sim_name, DEV_IDLEN); 1341121186Ssimokawa cpi->unit_number = sim->unit_number; 1342121186Ssimokawa 1343121186Ssimokawa cpi->ccb_h.status = CAM_REQ_CMP; 1344121186Ssimokawa xpt_done(ccb); 1345121186Ssimokawa break; 1346121186Ssimokawa } 1347121186Ssimokawa case XPT_ABORT: 1348121186Ssimokawa { 1349121186Ssimokawa union ccb *accb = ccb->cab.abort_ccb; 1350121186Ssimokawa 1351121186Ssimokawa switch (accb->ccb_h.func_code) { 1352121186Ssimokawa case XPT_ACCEPT_TARGET_IO: 1353237601Sken case XPT_IMMEDIATE_NOTIFY: 1354121186Ssimokawa ccb->ccb_h.status = sbp_targ_abort_ccb(sc, ccb); 1355121186Ssimokawa break; 1356121186Ssimokawa case XPT_CONT_TARGET_IO: 1357121186Ssimokawa /* XXX */ 1358121186Ssimokawa ccb->ccb_h.status = CAM_UA_ABORT; 1359121186Ssimokawa break; 1360121186Ssimokawa default: 1361121186Ssimokawa printf("%s: aborting unknown function %d\n", 1362127468Ssimokawa __func__, accb->ccb_h.func_code); 1363121186Ssimokawa ccb->ccb_h.status = CAM_REQ_INVALID; 1364121186Ssimokawa break; 1365121186Ssimokawa } 1366121186Ssimokawa xpt_done(ccb); 1367121186Ssimokawa break; 1368121186Ssimokawa } 1369230558Ssbruno#ifdef CAM_NEW_TRAN_CODE 1370230558Ssbruno case XPT_SET_TRAN_SETTINGS: 1371230558Ssbruno ccb->ccb_h.status = CAM_REQ_INVALID; 1372230558Ssbruno xpt_done(ccb); 1373230558Ssbruno break; 1374230558Ssbruno case XPT_GET_TRAN_SETTINGS: 1375230558Ssbruno { 1376230558Ssbruno struct ccb_trans_settings *cts = &ccb->cts; 1377230558Ssbruno struct ccb_trans_settings_scsi *scsi = 1378230558Ssbruno &cts->proto_specific.scsi; 1379230558Ssbruno struct ccb_trans_settings_spi *spi = 1380230558Ssbruno &cts->xport_specific.spi; 1381230558Ssbruno 1382230558Ssbruno cts->protocol = PROTO_SCSI; 1383230558Ssbruno cts->protocol_version = SCSI_REV_2; 1384230558Ssbruno cts->transport = XPORT_FW; /* should have a FireWire */ 1385230558Ssbruno cts->transport_version = 2; 1386230558Ssbruno spi->valid = CTS_SPI_VALID_DISC; 1387230558Ssbruno spi->flags = CTS_SPI_FLAGS_DISC_ENB; 1388230558Ssbruno scsi->valid = CTS_SCSI_VALID_TQ; 1389230558Ssbruno scsi->flags = CTS_SCSI_FLAGS_TAG_ENB; 1390230558Ssbruno#if 0 1391230558Ssbruno printf("%s:%d:%d XPT_GET_TRAN_SETTINGS:\n", 1392230558Ssbruno device_get_nameunit(sc->fd.dev), 1393230558Ssbruno ccb->ccb_h.target_id, ccb->ccb_h.target_lun); 1394230558Ssbruno#endif 1395230558Ssbruno cts->ccb_h.status = CAM_REQ_CMP; 1396230558Ssbruno xpt_done(ccb); 1397230558Ssbruno break; 1398230558Ssbruno } 1399230558Ssbruno#endif 1400230558Ssbruno 1401121186Ssimokawa default: 1402230558Ssbruno printf("%s: unknown function 0x%x\n", 1403127468Ssimokawa __func__, ccb->ccb_h.func_code); 1404230558Ssbruno ccb->ccb_h.status = CAM_PROVIDE_FAIL; 1405121186Ssimokawa xpt_done(ccb); 1406121186Ssimokawa break; 1407121186Ssimokawa } 1408121186Ssimokawa return; 1409121186Ssimokawa} 1410121186Ssimokawa 1411121186Ssimokawastatic void 1412121186Ssimokawasbp_targ_action(struct cam_sim *sim, union ccb *ccb) 1413121186Ssimokawa{ 1414121186Ssimokawa int s; 1415121186Ssimokawa 1416121186Ssimokawa s = splfw(); 1417121186Ssimokawa sbp_targ_action1(sim, ccb); 1418121186Ssimokawa splx(s); 1419121186Ssimokawa} 1420121186Ssimokawa 1421121186Ssimokawastatic void 1422121186Ssimokawasbp_targ_poll(struct cam_sim *sim) 1423121186Ssimokawa{ 1424121186Ssimokawa /* XXX */ 1425121186Ssimokawa return; 1426121186Ssimokawa} 1427121186Ssimokawa 1428121186Ssimokawastatic void 1429121186Ssimokawasbp_targ_cmd_handler(struct fw_xfer *xfer) 1430121186Ssimokawa{ 1431121186Ssimokawa struct fw_pkt *fp; 1432129585Sdfr uint32_t *orb; 1433121186Ssimokawa struct corb4 *orb4; 1434121186Ssimokawa struct orb_info *orbi; 1435121186Ssimokawa struct ccb_accept_tio *atio; 1436121186Ssimokawa u_char *bytes; 1437121186Ssimokawa int i; 1438121186Ssimokawa 1439121186Ssimokawa orbi = (struct orb_info *)xfer->sc; 1440121186Ssimokawa if (xfer->resp != 0) { 1441127468Ssimokawa printf("%s: xfer->resp = %d\n", __func__, xfer->resp); 1442121186Ssimokawa orbi->status.resp = SBP_TRANS_FAIL; 1443124877Ssimokawa orbi->status.status = OBJ_ORB | SBE_TIMEOUT/*XXX*/; 1444121186Ssimokawa orbi->status.dead = 1; 1445121186Ssimokawa orbi->status.len = 1; 1446170374Ssimokawa sbp_targ_abort(orbi->sc, STAILQ_NEXT(orbi, link)); 1447121186Ssimokawa 1448121186Ssimokawa sbp_targ_status_FIFO(orbi, 1449123430Ssimokawa orbi->login->fifo_hi, orbi->login->fifo_lo, /*dequeue*/1); 1450121186Ssimokawa fw_xfer_free(xfer); 1451121186Ssimokawa return; 1452121186Ssimokawa } 1453121186Ssimokawa fp = &xfer->recv.hdr; 1454121186Ssimokawa 1455170374Ssimokawa atio = orbi->atio; 1456170374Ssimokawa 1457121186Ssimokawa if (orbi->state == ORBI_STATUS_ABORTED) { 1458127468Ssimokawa printf("%s: aborted\n", __func__); 1459123430Ssimokawa sbp_targ_remove_orb_info(orbi->login, orbi); 1460121186Ssimokawa free(orbi, M_SBP_TARG); 1461170374Ssimokawa atio->ccb_h.status = CAM_REQ_ABORTED; 1462170374Ssimokawa SBP_LOCK(orbi->sc); 1463170374Ssimokawa xpt_done((union ccb*)atio); 1464170374Ssimokawa SBP_UNLOCK(orbi->sc); 1465121186Ssimokawa goto done0; 1466121186Ssimokawa } 1467121186Ssimokawa orbi->state = ORBI_STATUS_ATIO; 1468121186Ssimokawa 1469121186Ssimokawa orb = orbi->orb; 1470121186Ssimokawa /* swap payload except SCSI command */ 1471121186Ssimokawa for (i = 0; i < 5; i ++) 1472121186Ssimokawa orb[i] = ntohl(orb[i]); 1473121186Ssimokawa 1474121186Ssimokawa orb4 = (struct corb4 *)&orb[4]; 1475121186Ssimokawa if (orb4->rq_fmt != 0) { 1476121186Ssimokawa /* XXX */ 1477127468Ssimokawa printf("%s: rq_fmt(%d) != 0\n", __func__, orb4->rq_fmt); 1478121186Ssimokawa } 1479121186Ssimokawa 1480121186Ssimokawa atio->ccb_h.target_id = 0; /* XXX */ 1481123430Ssimokawa atio->ccb_h.target_lun = orbi->login->lstate->lun; 1482121186Ssimokawa atio->sense_len = 0; 1483230558Ssbruno atio->tag_action = MSG_SIMPLE_TASK; 1484121186Ssimokawa atio->tag_id = orbi->orb_lo; 1485123430Ssimokawa atio->init_id = orbi->login->id; 1486123430Ssimokawa 1487260342Smav atio->ccb_h.flags |= CAM_TAG_ACTION_VALID; 1488170374Ssimokawa bytes = (u_char *)&orb[5]; 1489121186Ssimokawa if (debug) 1490170374Ssimokawa printf("%s: %p %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", 1491170374Ssimokawa __func__, (void *)atio, 1492121186Ssimokawa bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], 1493121186Ssimokawa bytes[5], bytes[6], bytes[7], bytes[8], bytes[9]); 1494121186Ssimokawa switch (bytes[0] >> 5) { 1495121186Ssimokawa case 0: 1496121186Ssimokawa atio->cdb_len = 6; 1497121186Ssimokawa break; 1498121186Ssimokawa case 1: 1499121186Ssimokawa case 2: 1500121186Ssimokawa atio->cdb_len = 10; 1501121186Ssimokawa break; 1502121186Ssimokawa case 4: 1503121186Ssimokawa atio->cdb_len = 16; 1504121186Ssimokawa break; 1505121186Ssimokawa case 5: 1506121186Ssimokawa atio->cdb_len = 12; 1507121186Ssimokawa break; 1508121186Ssimokawa case 3: 1509121186Ssimokawa default: 1510121186Ssimokawa /* Only copy the opcode. */ 1511121186Ssimokawa atio->cdb_len = 1; 1512121186Ssimokawa printf("Reserved or VU command code type encountered\n"); 1513121186Ssimokawa break; 1514121186Ssimokawa } 1515121186Ssimokawa 1516121186Ssimokawa memcpy(atio->cdb_io.cdb_bytes, bytes, atio->cdb_len); 1517121186Ssimokawa 1518121186Ssimokawa atio->ccb_h.status |= CAM_CDB_RECVD; 1519121186Ssimokawa 1520121186Ssimokawa /* next ORB */ 1521121186Ssimokawa if ((orb[0] & (1<<31)) == 0) { 1522121186Ssimokawa if (debug) 1523127468Ssimokawa printf("%s: fetch next orb\n", __func__); 1524121186Ssimokawa orbi->status.src = SRC_NEXT_EXISTS; 1525121186Ssimokawa sbp_targ_fetch_orb(orbi->sc, orbi->fwdev, 1526123430Ssimokawa orb[0], orb[1], orbi->login, FETCH_CMD); 1527121186Ssimokawa } else { 1528121186Ssimokawa orbi->status.src = SRC_NO_NEXT; 1529123430Ssimokawa orbi->login->flags &= ~F_LINK_ACTIVE; 1530121186Ssimokawa } 1531121186Ssimokawa 1532121186Ssimokawa orbi->data_hi = orb[2]; 1533121186Ssimokawa orbi->data_lo = orb[3]; 1534121186Ssimokawa orbi->orb4 = *orb4; 1535121186Ssimokawa 1536170374Ssimokawa SBP_LOCK(orbi->sc); 1537121186Ssimokawa xpt_done((union ccb*)atio); 1538170374Ssimokawa SBP_UNLOCK(orbi->sc); 1539121186Ssimokawadone0: 1540121186Ssimokawa fw_xfer_free(xfer); 1541121186Ssimokawa return; 1542121186Ssimokawa} 1543121186Ssimokawa 1544123430Ssimokawastatic struct sbp_targ_login * 1545123430Ssimokawasbp_targ_get_login(struct sbp_targ_softc *sc, struct fw_device *fwdev, int lun) 1546123430Ssimokawa{ 1547123430Ssimokawa struct sbp_targ_lstate *lstate; 1548123430Ssimokawa struct sbp_targ_login *login; 1549123430Ssimokawa int i; 1550123430Ssimokawa 1551123430Ssimokawa lstate = sc->lstate[lun]; 1552123430Ssimokawa 1553123430Ssimokawa STAILQ_FOREACH(login, &lstate->logins, link) 1554123430Ssimokawa if (login->fwdev == fwdev) 1555123430Ssimokawa return (login); 1556123430Ssimokawa 1557123430Ssimokawa for (i = 0; i < MAX_LOGINS; i ++) 1558123430Ssimokawa if (sc->logins[i] == NULL) 1559123430Ssimokawa goto found; 1560123430Ssimokawa 1561127468Ssimokawa printf("%s: increase MAX_LOGIN\n", __func__); 1562123430Ssimokawa return (NULL); 1563123430Ssimokawa 1564123430Ssimokawafound: 1565123430Ssimokawa login = (struct sbp_targ_login *)malloc( 1566123430Ssimokawa sizeof(struct sbp_targ_login), M_SBP_TARG, M_NOWAIT | M_ZERO); 1567123430Ssimokawa 1568123430Ssimokawa if (login == NULL) { 1569127468Ssimokawa printf("%s: malloc failed\n", __func__); 1570123430Ssimokawa return (NULL); 1571123430Ssimokawa } 1572123430Ssimokawa 1573169475Ssimokawa login->id = i; 1574123430Ssimokawa login->fwdev = fwdev; 1575123430Ssimokawa login->lstate = lstate; 1576123430Ssimokawa login->last_hi = 0xffff; 1577123430Ssimokawa login->last_lo = 0xffffffff; 1578123430Ssimokawa login->hold_sec = 1; 1579123430Ssimokawa STAILQ_INIT(&login->orbs); 1580123430Ssimokawa CALLOUT_INIT(&login->hold_callout); 1581123430Ssimokawa sc->logins[i] = login; 1582123430Ssimokawa return (login); 1583123430Ssimokawa} 1584123430Ssimokawa 1585121186Ssimokawastatic void 1586121186Ssimokawasbp_targ_mgm_handler(struct fw_xfer *xfer) 1587121186Ssimokawa{ 1588121186Ssimokawa struct sbp_targ_lstate *lstate; 1589123430Ssimokawa struct sbp_targ_login *login; 1590121186Ssimokawa struct fw_pkt *fp; 1591129585Sdfr uint32_t *orb; 1592121186Ssimokawa struct morb4 *orb4; 1593121186Ssimokawa struct orb_info *orbi; 1594121186Ssimokawa int i; 1595121186Ssimokawa 1596121186Ssimokawa orbi = (struct orb_info *)xfer->sc; 1597121186Ssimokawa if (xfer->resp != 0) { 1598127468Ssimokawa printf("%s: xfer->resp = %d\n", __func__, xfer->resp); 1599121186Ssimokawa orbi->status.resp = SBP_TRANS_FAIL; 1600124877Ssimokawa orbi->status.status = OBJ_ORB | SBE_TIMEOUT/*XXX*/; 1601121186Ssimokawa orbi->status.dead = 1; 1602121186Ssimokawa orbi->status.len = 1; 1603170374Ssimokawa sbp_targ_abort(orbi->sc, STAILQ_NEXT(orbi, link)); 1604121186Ssimokawa 1605121186Ssimokawa sbp_targ_status_FIFO(orbi, 1606123430Ssimokawa orbi->login->fifo_hi, orbi->login->fifo_lo, /*dequeue*/0); 1607121186Ssimokawa fw_xfer_free(xfer); 1608121186Ssimokawa return; 1609121186Ssimokawa } 1610121186Ssimokawa fp = &xfer->recv.hdr; 1611121186Ssimokawa 1612121186Ssimokawa orb = orbi->orb; 1613121186Ssimokawa /* swap payload */ 1614121186Ssimokawa for (i = 0; i < 8; i ++) { 1615121186Ssimokawa orb[i] = ntohl(orb[i]); 1616121186Ssimokawa } 1617121186Ssimokawa orb4 = (struct morb4 *)&orb[4]; 1618121186Ssimokawa if (debug) 1619127468Ssimokawa printf("%s: %s\n", __func__, orb_fun_name[orb4->fun]); 1620121186Ssimokawa 1621121186Ssimokawa orbi->status.src = SRC_NO_NEXT; 1622121186Ssimokawa 1623121186Ssimokawa switch (orb4->fun << 16) { 1624121186Ssimokawa case ORB_FUN_LGI: 1625121186Ssimokawa { 1626123430Ssimokawa int exclusive = 0, lun; 1627121186Ssimokawa 1628123430Ssimokawa if (orb[4] & ORB_EXV) 1629123430Ssimokawa exclusive = 1; 1630123430Ssimokawa 1631123430Ssimokawa lun = orb4->id; 1632123430Ssimokawa lstate = orbi->sc->lstate[lun]; 1633123430Ssimokawa 1634123430Ssimokawa if (lun >= MAX_LUN || lstate == NULL || 1635123430Ssimokawa (exclusive && 1636123430Ssimokawa STAILQ_FIRST(&lstate->logins) != NULL && 1637123430Ssimokawa STAILQ_FIRST(&lstate->logins)->fwdev != orbi->fwdev) 1638123430Ssimokawa ) { 1639121186Ssimokawa /* error */ 1640121186Ssimokawa orbi->status.dead = 1; 1641121186Ssimokawa orbi->status.status = STATUS_ACCESS_DENY; 1642121186Ssimokawa orbi->status.len = 1; 1643121186Ssimokawa break; 1644121186Ssimokawa } 1645123430Ssimokawa 1646123430Ssimokawa /* allocate login */ 1647123430Ssimokawa login = sbp_targ_get_login(orbi->sc, orbi->fwdev, lun); 1648123430Ssimokawa if (login == NULL) { 1649123430Ssimokawa printf("%s: sbp_targ_get_login failed\n", 1650127468Ssimokawa __func__); 1651123430Ssimokawa orbi->status.dead = 1; 1652123430Ssimokawa orbi->status.status = STATUS_RES_UNAVAIL; 1653123430Ssimokawa orbi->status.len = 1; 1654123430Ssimokawa break; 1655123430Ssimokawa } 1656170374Ssimokawa printf("%s: login id=%d\n", __func__, login->id); 1657123430Ssimokawa 1658123430Ssimokawa login->fifo_hi = orb[6]; 1659123430Ssimokawa login->fifo_lo = orb[7]; 1660129585Sdfr login->loginres.len = htons(sizeof(uint32_t) * 4); 1661123430Ssimokawa login->loginres.id = htons(login->id); 1662123430Ssimokawa login->loginres.cmd_hi = htons(SBP_TARG_BIND_HI); 1663123430Ssimokawa login->loginres.cmd_lo = htonl(SBP_TARG_BIND_LO(login->id)); 1664123430Ssimokawa login->loginres.recon_hold = htons(login->hold_sec); 1665123430Ssimokawa 1666170374Ssimokawa STAILQ_INSERT_TAIL(&lstate->logins, login, link); 1667230558Ssbruno fwmem_write_block(orbi->fwdev, NULL, /*spd*/FWSPD_S400, orb[2], orb[3], 1668123430Ssimokawa sizeof(struct sbp_login_res), (void *)&login->loginres, 1669121186Ssimokawa fw_asy_callback_free); 1670123514Ssimokawa /* XXX return status after loginres is successfully written */ 1671121186Ssimokawa break; 1672121186Ssimokawa } 1673121186Ssimokawa case ORB_FUN_RCN: 1674123430Ssimokawa login = orbi->sc->logins[orb4->id]; 1675123430Ssimokawa if (login != NULL && login->fwdev == orbi->fwdev) { 1676123430Ssimokawa login->flags &= ~F_HOLD; 1677123430Ssimokawa callout_stop(&login->hold_callout); 1678123430Ssimokawa printf("%s: reconnected id=%d\n", 1679127468Ssimokawa __func__, login->id); 1680123430Ssimokawa } else { 1681123430Ssimokawa orbi->status.dead = 1; 1682123430Ssimokawa orbi->status.status = STATUS_ACCESS_DENY; 1683123430Ssimokawa printf("%s: reconnection faild id=%d\n", 1684127468Ssimokawa __func__, orb4->id); 1685123430Ssimokawa } 1686121186Ssimokawa break; 1687123430Ssimokawa case ORB_FUN_LGO: 1688123430Ssimokawa login = orbi->sc->logins[orb4->id]; 1689123430Ssimokawa if (login->fwdev != orbi->fwdev) { 1690127468Ssimokawa printf("%s: wrong initiator\n", __func__); 1691123430Ssimokawa break; 1692123430Ssimokawa } 1693123430Ssimokawa sbp_targ_dealloc_login(login); 1694123430Ssimokawa break; 1695121186Ssimokawa default: 1696121186Ssimokawa printf("%s: %s not implemented yet\n", 1697127468Ssimokawa __func__, orb_fun_name[orb4->fun]); 1698121186Ssimokawa break; 1699121186Ssimokawa } 1700121186Ssimokawa orbi->status.len = 1; 1701121186Ssimokawa sbp_targ_status_FIFO(orbi, orb[6], orb[7], /*dequeue*/0); 1702121186Ssimokawa fw_xfer_free(xfer); 1703121186Ssimokawa return; 1704121186Ssimokawa} 1705121186Ssimokawa 1706121186Ssimokawastatic void 1707121186Ssimokawasbp_targ_pointer_handler(struct fw_xfer *xfer) 1708121186Ssimokawa{ 1709121186Ssimokawa struct orb_info *orbi; 1710129585Sdfr uint32_t orb0, orb1; 1711121186Ssimokawa 1712121186Ssimokawa orbi = (struct orb_info *)xfer->sc; 1713121186Ssimokawa if (xfer->resp != 0) { 1714127468Ssimokawa printf("%s: xfer->resp = %d\n", __func__, xfer->resp); 1715121186Ssimokawa goto done; 1716121186Ssimokawa } 1717121186Ssimokawa 1718121186Ssimokawa orb0 = ntohl(orbi->orb[0]); 1719121186Ssimokawa orb1 = ntohl(orbi->orb[1]); 1720261455Seadler if ((orb0 & (1U << 31)) != 0) { 1721127468Ssimokawa printf("%s: invalid pointer\n", __func__); 1722121186Ssimokawa goto done; 1723121186Ssimokawa } 1724123430Ssimokawa sbp_targ_fetch_orb(orbi->login->lstate->sc, orbi->fwdev, 1725129585Sdfr (uint16_t)orb0, orb1, orbi->login, FETCH_CMD); 1726121186Ssimokawadone: 1727121186Ssimokawa free(orbi, M_SBP_TARG); 1728121186Ssimokawa fw_xfer_free(xfer); 1729121186Ssimokawa return; 1730121186Ssimokawa} 1731121186Ssimokawa 1732121186Ssimokawastatic void 1733121186Ssimokawasbp_targ_fetch_orb(struct sbp_targ_softc *sc, struct fw_device *fwdev, 1734129585Sdfr uint16_t orb_hi, uint32_t orb_lo, struct sbp_targ_login *login, 1735121186Ssimokawa int mode) 1736121186Ssimokawa{ 1737121186Ssimokawa struct orb_info *orbi; 1738121186Ssimokawa 1739121186Ssimokawa if (debug) 1740127468Ssimokawa printf("%s: fetch orb %04x:%08x\n", __func__, orb_hi, orb_lo); 1741121186Ssimokawa orbi = malloc(sizeof(struct orb_info), M_SBP_TARG, M_NOWAIT | M_ZERO); 1742121186Ssimokawa if (orbi == NULL) { 1743127468Ssimokawa printf("%s: malloc failed\n", __func__); 1744121186Ssimokawa return; 1745121186Ssimokawa } 1746121186Ssimokawa orbi->sc = sc; 1747121186Ssimokawa orbi->fwdev = fwdev; 1748123430Ssimokawa orbi->login = login; 1749121186Ssimokawa orbi->orb_hi = orb_hi; 1750121186Ssimokawa orbi->orb_lo = orb_lo; 1751121186Ssimokawa orbi->status.orb_hi = htons(orb_hi); 1752121186Ssimokawa orbi->status.orb_lo = htonl(orb_lo); 1753230558Ssbruno orbi->page_table = NULL; 1754121186Ssimokawa 1755121186Ssimokawa switch (mode) { 1756121186Ssimokawa case FETCH_MGM: 1757230558Ssbruno fwmem_read_block(fwdev, (void *)orbi, /*spd*/FWSPD_S400, orb_hi, orb_lo, 1758129585Sdfr sizeof(uint32_t) * 8, &orbi->orb[0], 1759121186Ssimokawa sbp_targ_mgm_handler); 1760121186Ssimokawa break; 1761121186Ssimokawa case FETCH_CMD: 1762121186Ssimokawa orbi->state = ORBI_STATUS_FETCH; 1763123430Ssimokawa login->last_hi = orb_hi; 1764123430Ssimokawa login->last_lo = orb_lo; 1765123430Ssimokawa login->flags |= F_LINK_ACTIVE; 1766121186Ssimokawa /* dequeue */ 1767170374Ssimokawa SBP_LOCK(sc); 1768121186Ssimokawa orbi->atio = (struct ccb_accept_tio *) 1769123430Ssimokawa SLIST_FIRST(&login->lstate->accept_tios); 1770121186Ssimokawa if (orbi->atio == NULL) { 1771170374Ssimokawa SBP_UNLOCK(sc); 1772127468Ssimokawa printf("%s: no free atio\n", __func__); 1773123430Ssimokawa login->lstate->flags |= F_ATIO_STARVED; 1774123430Ssimokawa login->flags |= F_ATIO_STARVED; 1775123430Ssimokawa#if 0 1776123430Ssimokawa /* XXX ?? */ 1777123430Ssimokawa login->fwdev = fwdev; 1778123430Ssimokawa#endif 1779121186Ssimokawa break; 1780121186Ssimokawa } 1781123430Ssimokawa SLIST_REMOVE_HEAD(&login->lstate->accept_tios, sim_links.sle); 1782170374Ssimokawa STAILQ_INSERT_TAIL(&login->orbs, orbi, link); 1783170374Ssimokawa SBP_UNLOCK(sc); 1784230558Ssbruno fwmem_read_block(fwdev, (void *)orbi, /*spd*/FWSPD_S400, orb_hi, orb_lo, 1785129585Sdfr sizeof(uint32_t) * 8, &orbi->orb[0], 1786121186Ssimokawa sbp_targ_cmd_handler); 1787121186Ssimokawa break; 1788121186Ssimokawa case FETCH_POINTER: 1789121186Ssimokawa orbi->state = ORBI_STATUS_POINTER; 1790123430Ssimokawa login->flags |= F_LINK_ACTIVE; 1791230558Ssbruno fwmem_read_block(fwdev, (void *)orbi, /*spd*/FWSPD_S400, orb_hi, orb_lo, 1792129585Sdfr sizeof(uint32_t) * 2, &orbi->orb[0], 1793121186Ssimokawa sbp_targ_pointer_handler); 1794121186Ssimokawa break; 1795121186Ssimokawa default: 1796127468Ssimokawa printf("%s: invalid mode %d\n", __func__, mode); 1797121186Ssimokawa } 1798121186Ssimokawa} 1799121186Ssimokawa 1800121186Ssimokawastatic void 1801121186Ssimokawasbp_targ_resp_callback(struct fw_xfer *xfer) 1802121186Ssimokawa{ 1803121186Ssimokawa struct sbp_targ_softc *sc; 1804121186Ssimokawa int s; 1805121186Ssimokawa 1806121186Ssimokawa if (debug) 1807127468Ssimokawa printf("%s: xfer=%p\n", __func__, xfer); 1808121186Ssimokawa sc = (struct sbp_targ_softc *)xfer->sc; 1809121186Ssimokawa fw_xfer_unload(xfer); 1810121186Ssimokawa xfer->recv.pay_len = SBP_TARG_RECV_LEN; 1811167632Ssimokawa xfer->hand = sbp_targ_recv; 1812121186Ssimokawa s = splfw(); 1813121186Ssimokawa STAILQ_INSERT_TAIL(&sc->fwb.xferlist, xfer, link); 1814121186Ssimokawa splx(s); 1815121186Ssimokawa} 1816121186Ssimokawa 1817121186Ssimokawastatic int 1818123430Ssimokawasbp_targ_cmd(struct fw_xfer *xfer, struct fw_device *fwdev, int login_id, 1819123430Ssimokawa int reg) 1820121186Ssimokawa{ 1821123430Ssimokawa struct sbp_targ_login *login; 1822121186Ssimokawa struct sbp_targ_softc *sc; 1823121186Ssimokawa int rtcode = 0; 1824121186Ssimokawa 1825123430Ssimokawa if (login_id < 0 || login_id >= MAX_LOGINS) 1826121186Ssimokawa return(RESP_ADDRESS_ERROR); 1827121186Ssimokawa 1828121186Ssimokawa sc = (struct sbp_targ_softc *)xfer->sc; 1829123430Ssimokawa login = sc->logins[login_id]; 1830123430Ssimokawa if (login == NULL) 1831121186Ssimokawa return(RESP_ADDRESS_ERROR); 1832121186Ssimokawa 1833123430Ssimokawa if (login->fwdev != fwdev) { 1834123430Ssimokawa /* XXX */ 1835123430Ssimokawa return(RESP_ADDRESS_ERROR); 1836123430Ssimokawa } 1837123430Ssimokawa 1838121186Ssimokawa switch (reg) { 1839121186Ssimokawa case 0x08: /* ORB_POINTER */ 1840121186Ssimokawa if (debug) 1841170374Ssimokawa printf("%s: ORB_POINTER(%d)\n", __func__, login_id); 1842123430Ssimokawa if ((login->flags & F_LINK_ACTIVE) != 0) { 1843123430Ssimokawa if (debug) 1844123430Ssimokawa printf("link active (ORB_POINTER)\n"); 1845123430Ssimokawa break; 1846123430Ssimokawa } 1847123430Ssimokawa sbp_targ_fetch_orb(sc, fwdev, 1848121186Ssimokawa ntohl(xfer->recv.payload[0]), 1849121186Ssimokawa ntohl(xfer->recv.payload[1]), 1850123430Ssimokawa login, FETCH_CMD); 1851121186Ssimokawa break; 1852121186Ssimokawa case 0x04: /* AGENT_RESET */ 1853121186Ssimokawa if (debug) 1854170374Ssimokawa printf("%s: AGENT RESET(%d)\n", __func__, login_id); 1855123430Ssimokawa login->last_hi = 0xffff; 1856123430Ssimokawa login->last_lo = 0xffffffff; 1857170374Ssimokawa sbp_targ_abort(sc, STAILQ_FIRST(&login->orbs)); 1858121186Ssimokawa break; 1859121186Ssimokawa case 0x10: /* DOORBELL */ 1860121186Ssimokawa if (debug) 1861170374Ssimokawa printf("%s: DOORBELL(%d)\n", __func__, login_id); 1862123430Ssimokawa if (login->last_hi == 0xffff && 1863123430Ssimokawa login->last_lo == 0xffffffff) { 1864121186Ssimokawa printf("%s: no previous pointer(DOORBELL)\n", 1865127468Ssimokawa __func__); 1866121186Ssimokawa break; 1867121186Ssimokawa } 1868123430Ssimokawa if ((login->flags & F_LINK_ACTIVE) != 0) { 1869121186Ssimokawa if (debug) 1870121186Ssimokawa printf("link active (DOORBELL)\n"); 1871121186Ssimokawa break; 1872121186Ssimokawa } 1873123430Ssimokawa sbp_targ_fetch_orb(sc, fwdev, 1874123430Ssimokawa login->last_hi, login->last_lo, 1875123430Ssimokawa login, FETCH_POINTER); 1876121186Ssimokawa break; 1877121186Ssimokawa case 0x00: /* AGENT_STATE */ 1878170374Ssimokawa printf("%s: AGENT_STATE (%d:ignore)\n", __func__, login_id); 1879121186Ssimokawa break; 1880121186Ssimokawa case 0x14: /* UNSOLICITED_STATE_ENABLE */ 1881170374Ssimokawa printf("%s: UNSOLICITED_STATE_ENABLE (%d:ignore)\n", 1882170374Ssimokawa __func__, login_id); 1883121186Ssimokawa break; 1884121186Ssimokawa default: 1885170374Ssimokawa printf("%s: invalid register %d(%d)\n", 1886170374Ssimokawa __func__, reg, login_id); 1887121186Ssimokawa rtcode = RESP_ADDRESS_ERROR; 1888121186Ssimokawa } 1889121186Ssimokawa 1890121186Ssimokawa return (rtcode); 1891121186Ssimokawa} 1892121186Ssimokawa 1893121186Ssimokawastatic int 1894121186Ssimokawasbp_targ_mgm(struct fw_xfer *xfer, struct fw_device *fwdev) 1895121186Ssimokawa{ 1896121186Ssimokawa struct sbp_targ_softc *sc; 1897121186Ssimokawa struct fw_pkt *fp; 1898121186Ssimokawa 1899121186Ssimokawa sc = (struct sbp_targ_softc *)xfer->sc; 1900121186Ssimokawa 1901121186Ssimokawa fp = &xfer->recv.hdr; 1902121186Ssimokawa if (fp->mode.wreqb.tcode != FWTCODE_WREQB){ 1903127468Ssimokawa printf("%s: tcode = %d\n", __func__, fp->mode.wreqb.tcode); 1904121186Ssimokawa return(RESP_TYPE_ERROR); 1905121186Ssimokawa } 1906121186Ssimokawa 1907121186Ssimokawa sbp_targ_fetch_orb(sc, fwdev, 1908121186Ssimokawa ntohl(xfer->recv.payload[0]), 1909121186Ssimokawa ntohl(xfer->recv.payload[1]), 1910121186Ssimokawa NULL, FETCH_MGM); 1911121186Ssimokawa 1912121186Ssimokawa return(0); 1913121186Ssimokawa} 1914121186Ssimokawa 1915121186Ssimokawastatic void 1916121186Ssimokawasbp_targ_recv(struct fw_xfer *xfer) 1917121186Ssimokawa{ 1918121186Ssimokawa struct fw_pkt *fp, *sfp; 1919121186Ssimokawa struct fw_device *fwdev; 1920129585Sdfr uint32_t lo; 1921121186Ssimokawa int s, rtcode; 1922121186Ssimokawa struct sbp_targ_softc *sc; 1923121186Ssimokawa 1924121186Ssimokawa s = splfw(); 1925121186Ssimokawa sc = (struct sbp_targ_softc *)xfer->sc; 1926121186Ssimokawa fp = &xfer->recv.hdr; 1927121186Ssimokawa fwdev = fw_noderesolve_nodeid(sc->fd.fc, fp->mode.wreqb.src & 0x3f); 1928121186Ssimokawa if (fwdev == NULL) { 1929121186Ssimokawa printf("%s: cannot resolve nodeid=%d\n", 1930127468Ssimokawa __func__, fp->mode.wreqb.src & 0x3f); 1931121186Ssimokawa rtcode = RESP_TYPE_ERROR; /* XXX */ 1932121186Ssimokawa goto done; 1933121186Ssimokawa } 1934121186Ssimokawa lo = fp->mode.wreqb.dest_lo; 1935170374Ssimokawa 1936121186Ssimokawa if (lo == SBP_TARG_BIND_LO(-1)) 1937121186Ssimokawa rtcode = sbp_targ_mgm(xfer, fwdev); 1938121186Ssimokawa else if (lo >= SBP_TARG_BIND_LO(0)) 1939123430Ssimokawa rtcode = sbp_targ_cmd(xfer, fwdev, SBP_TARG_LOGIN_ID(lo), 1940123430Ssimokawa lo % 0x20); 1941121186Ssimokawa else 1942121186Ssimokawa rtcode = RESP_ADDRESS_ERROR; 1943121186Ssimokawa 1944121186Ssimokawadone: 1945121186Ssimokawa if (rtcode != 0) 1946127468Ssimokawa printf("%s: rtcode = %d\n", __func__, rtcode); 1947121186Ssimokawa sfp = &xfer->send.hdr; 1948230558Ssbruno xfer->send.spd = FWSPD_S400; 1949167632Ssimokawa xfer->hand = sbp_targ_resp_callback; 1950121186Ssimokawa sfp->mode.wres.dst = fp->mode.wreqb.src; 1951121186Ssimokawa sfp->mode.wres.tlrt = fp->mode.wreqb.tlrt; 1952121186Ssimokawa sfp->mode.wres.tcode = FWTCODE_WRES; 1953121186Ssimokawa sfp->mode.wres.rtcode = rtcode; 1954121186Ssimokawa sfp->mode.wres.pri = 0; 1955121186Ssimokawa 1956121186Ssimokawa fw_asyreq(xfer->fc, -1, xfer); 1957121186Ssimokawa splx(s); 1958121186Ssimokawa} 1959121186Ssimokawa 1960121186Ssimokawastatic int 1961121186Ssimokawasbp_targ_attach(device_t dev) 1962121186Ssimokawa{ 1963121186Ssimokawa struct sbp_targ_softc *sc; 1964121186Ssimokawa struct cam_devq *devq; 1965170374Ssimokawa struct firewire_comm *fc; 1966121186Ssimokawa 1967121186Ssimokawa sc = (struct sbp_targ_softc *) device_get_softc(dev); 1968121186Ssimokawa bzero((void *)sc, sizeof(struct sbp_targ_softc)); 1969121186Ssimokawa 1970170374Ssimokawa mtx_init(&sc->mtx, "sbp_targ", NULL, MTX_DEF); 1971170374Ssimokawa sc->fd.fc = fc = device_get_ivars(dev); 1972121186Ssimokawa sc->fd.dev = dev; 1973123430Ssimokawa sc->fd.post_explore = (void *) sbp_targ_post_explore; 1974121186Ssimokawa sc->fd.post_busreset = (void *) sbp_targ_post_busreset; 1975121186Ssimokawa 1976169475Ssimokawa devq = cam_simq_alloc(/*maxopenings*/MAX_LUN*MAX_INITIATORS); 1977121186Ssimokawa if (devq == NULL) 1978121186Ssimokawa return (ENXIO); 1979121186Ssimokawa 1980121186Ssimokawa sc->sim = cam_sim_alloc(sbp_targ_action, sbp_targ_poll, 1981170374Ssimokawa "sbp_targ", sc, device_get_unit(dev), &sc->mtx, 1982121186Ssimokawa /*untagged*/ 1, /*tagged*/ 1, devq); 1983121186Ssimokawa if (sc->sim == NULL) { 1984121186Ssimokawa cam_simq_free(devq); 1985121186Ssimokawa return (ENXIO); 1986121186Ssimokawa } 1987121186Ssimokawa 1988170374Ssimokawa SBP_LOCK(sc); 1989170872Sscottl if (xpt_bus_register(sc->sim, dev, /*bus*/0) != CAM_SUCCESS) 1990121186Ssimokawa goto fail; 1991121186Ssimokawa 1992121186Ssimokawa if (xpt_create_path(&sc->path, /*periph*/ NULL, cam_sim_path(sc->sim), 1993121186Ssimokawa CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 1994121186Ssimokawa xpt_bus_deregister(cam_sim_path(sc->sim)); 1995121186Ssimokawa goto fail; 1996121186Ssimokawa } 1997170374Ssimokawa SBP_UNLOCK(sc); 1998121186Ssimokawa 1999121186Ssimokawa sc->fwb.start = SBP_TARG_BIND_START; 2000121186Ssimokawa sc->fwb.end = SBP_TARG_BIND_END; 2001121186Ssimokawa 2002121186Ssimokawa /* pre-allocate xfer */ 2003121186Ssimokawa STAILQ_INIT(&sc->fwb.xferlist); 2004169130Ssimokawa fw_xferlist_add(&sc->fwb.xferlist, M_SBP_TARG, 2005169130Ssimokawa /*send*/ 0, /*recv*/ SBP_TARG_RECV_LEN, MAX_LUN /* XXX */, 2006170374Ssimokawa fc, (void *)sc, sbp_targ_recv); 2007170374Ssimokawa fw_bindadd(fc, &sc->fwb); 2008121186Ssimokawa return 0; 2009121186Ssimokawa 2010121186Ssimokawafail: 2011170374Ssimokawa SBP_UNLOCK(sc); 2012121186Ssimokawa cam_sim_free(sc->sim, /*free_devq*/TRUE); 2013121186Ssimokawa return (ENXIO); 2014121186Ssimokawa} 2015121186Ssimokawa 2016121186Ssimokawastatic int 2017121186Ssimokawasbp_targ_detach(device_t dev) 2018121186Ssimokawa{ 2019121186Ssimokawa struct sbp_targ_softc *sc; 2020121186Ssimokawa struct sbp_targ_lstate *lstate; 2021121186Ssimokawa int i; 2022121186Ssimokawa 2023121186Ssimokawa sc = (struct sbp_targ_softc *)device_get_softc(dev); 2024121186Ssimokawa sc->fd.post_busreset = NULL; 2025121186Ssimokawa 2026170374Ssimokawa SBP_LOCK(sc); 2027121186Ssimokawa xpt_free_path(sc->path); 2028121186Ssimokawa xpt_bus_deregister(cam_sim_path(sc->sim)); 2029170374Ssimokawa SBP_UNLOCK(sc); 2030121186Ssimokawa cam_sim_free(sc->sim, /*free_devq*/TRUE); 2031121186Ssimokawa 2032121186Ssimokawa for (i = 0; i < MAX_LUN; i ++) { 2033121186Ssimokawa lstate = sc->lstate[i]; 2034121186Ssimokawa if (lstate != NULL) { 2035121186Ssimokawa xpt_free_path(lstate->path); 2036121186Ssimokawa free(lstate, M_SBP_TARG); 2037121186Ssimokawa } 2038121186Ssimokawa } 2039121186Ssimokawa if (sc->black_hole != NULL) { 2040121186Ssimokawa xpt_free_path(sc->black_hole->path); 2041121186Ssimokawa free(sc->black_hole, M_SBP_TARG); 2042121186Ssimokawa } 2043121186Ssimokawa 2044121186Ssimokawa fw_bindremove(sc->fd.fc, &sc->fwb); 2045169130Ssimokawa fw_xferlist_remove(&sc->fwb.xferlist); 2046121186Ssimokawa 2047170374Ssimokawa mtx_destroy(&sc->mtx); 2048170374Ssimokawa 2049121186Ssimokawa return 0; 2050121186Ssimokawa} 2051121186Ssimokawa 2052121186Ssimokawastatic devclass_t sbp_targ_devclass; 2053121186Ssimokawa 2054121186Ssimokawastatic device_method_t sbp_targ_methods[] = { 2055121186Ssimokawa /* device interface */ 2056121186Ssimokawa DEVMETHOD(device_identify, sbp_targ_identify), 2057121186Ssimokawa DEVMETHOD(device_probe, sbp_targ_probe), 2058121186Ssimokawa DEVMETHOD(device_attach, sbp_targ_attach), 2059121186Ssimokawa DEVMETHOD(device_detach, sbp_targ_detach), 2060121186Ssimokawa { 0, 0 } 2061121186Ssimokawa}; 2062121186Ssimokawa 2063121186Ssimokawastatic driver_t sbp_targ_driver = { 2064121186Ssimokawa "sbp_targ", 2065121186Ssimokawa sbp_targ_methods, 2066121186Ssimokawa sizeof(struct sbp_targ_softc), 2067121186Ssimokawa}; 2068121186Ssimokawa 2069121186SsimokawaDRIVER_MODULE(sbp_targ, firewire, sbp_targ_driver, sbp_targ_devclass, 0, 0); 2070121186SsimokawaMODULE_VERSION(sbp_targ, 1); 2071121186SsimokawaMODULE_DEPEND(sbp_targ, firewire, 1, 1, 1); 2072121186SsimokawaMODULE_DEPEND(sbp_targ, cam, 1, 1, 1); 2073