diff options
author | simokawa <simokawa@FreeBSD.org> | 2003-12-11 03:42:40 +0000 |
---|---|---|
committer | simokawa <simokawa@FreeBSD.org> | 2003-12-11 03:42:40 +0000 |
commit | f28990e98496ba9c52a346ada086bb1b40a9a9ca (patch) | |
tree | bbce7a7577c862d41145b73de8445621102a2ece /sys/dev/firewire | |
parent | c330930b3bebe26fafeea458e0652443cba7c4a3 (diff) | |
download | FreeBSD-src-f28990e98496ba9c52a346ada086bb1b40a9a9ca.zip FreeBSD-src-f28990e98496ba9c52a346ada086bb1b40a9a9ca.tar.gz |
MFp4:
- Introduce sbp_targ_login instead of sbp_targ_istate.
- Implement reconnection and logout.
- Freeze simq while bus reset.
Diffstat (limited to 'sys/dev/firewire')
-rw-r--r-- | sys/dev/firewire/sbp.h | 1 | ||||
-rw-r--r-- | sys/dev/firewire/sbp_targ.c | 438 |
2 files changed, 310 insertions, 129 deletions
diff --git a/sys/dev/firewire/sbp.h b/sys/dev/firewire/sbp.h index 1e878cf..c4b5e0a 100644 --- a/sys/dev/firewire/sbp.h +++ b/sys/dev/firewire/sbp.h @@ -125,6 +125,7 @@ struct sbp_status{ /* 6: Maximum payload too small */ /* 7: Reserved for future standardization */ /* 8: Resource unavailabe */ +#define STATUS_RES_UNAVAIL 8 /* 9: Function Rejected */ /* 10: Login ID not recognized */ /* 11: Dummy ORB completed */ diff --git a/sys/dev/firewire/sbp_targ.c b/sys/dev/firewire/sbp_targ.c index a5c3581..842e908 100644 --- a/sys/dev/firewire/sbp_targ.c +++ b/sys/dev/firewire/sbp_targ.c @@ -62,14 +62,17 @@ #include <cam/cam_periph.h> #include <cam/scsi/scsi_all.h> -#define SBP_TARG_RECV_LEN (8) -#define MAX_LUN 63 +#define SBP_TARG_RECV_LEN 8 +#define MAX_INITIATORS 8 +#define MAX_LUN 63 +#define MAX_LOGINS 63 +#define MAX_NODES 63 /* * management/command block agent registers * * BASE 0xffff f001 0000 management port - * BASE 0xffff f001 0020 command port for lun0 - * BASE 0xffff f001 0040 command port for lun1 + * BASE 0xffff f001 0020 command port for login id 0 + * BASE 0xffff f001 0040 command port for login id 1 * */ #define SBP_TARG_MGM 0x10000 /* offset from 0xffff f000 000 */ @@ -78,13 +81,19 @@ #define SBP_TARG_BIND_START (((u_int64_t)SBP_TARG_BIND_HI << 32) | \ SBP_TARG_BIND_LO(-1)) #define SBP_TARG_BIND_END (((u_int64_t)SBP_TARG_BIND_HI << 32) | \ - SBP_TARG_BIND_LO(MAX_LUN)) -#define SBP_TARG_LUN(lo) (((lo) - SBP_TARG_BIND_LO(0))/0x20) + SBP_TARG_BIND_LO(MAX_LOGINS)) +#define SBP_TARG_LOGIN_ID(lo) (((lo) - SBP_TARG_BIND_LO(0))/0x20) #define FETCH_MGM 0 #define FETCH_CMD 1 #define FETCH_POINTER 2 +#define F_LINK_ACTIVE (1 << 0) +#define F_ATIO_STARVED (1 << 1) +#define F_LOGIN (1 << 2) +#define F_HOLD (1 << 3) +#define F_FREEZED (1 << 4) + MALLOC_DEFINE(M_SBP_TARG, "sbp_targ", "SBP-II/FireWire target mode"); static int debug = 0; @@ -92,36 +101,44 @@ static int debug = 0; SYSCTL_INT(_debug, OID_AUTO, sbp_targ_debug, CTLFLAG_RW, &debug, 0, "SBP target mode debug flag"); -struct sbp_targ_softc { - struct firewire_dev_comm fd; - struct cam_sim *sim; - struct cam_path *path; - struct fw_bind fwb; - int ndevs; - struct crom_chunk unit; - struct sbp_targ_lstate *lstate[MAX_LUN]; - struct sbp_targ_lstate *black_hole; -}; - -struct sbp_targ_lstate { - struct sbp_targ_softc *sc; - struct cam_path *path; - struct ccb_hdr_slist accept_tios; - struct ccb_hdr_slist immed_notifies; - struct crom_chunk model; - /* XXX per initiater data */ +struct sbp_targ_login { + struct sbp_targ_lstate *lstate; struct fw_device *fwdev; struct sbp_login_res loginres; u_int32_t flags; -#define LINK_ACTIVE 1 -#define ATIO_STARVED 2 u_int16_t fifo_hi; u_int16_t last_hi; u_int32_t fifo_lo; u_int32_t last_lo; STAILQ_HEAD(, orb_info) orbs; - u_int16_t login_id; + u_int16_t id; + STAILQ_ENTRY(sbp_targ_login) link; + int hold_sec; + struct callout hold_callout; +}; + +struct sbp_targ_lstate { u_int16_t lun; + struct sbp_targ_softc *sc; + struct cam_path *path; + struct ccb_hdr_slist accept_tios; + struct ccb_hdr_slist immed_notifies; + struct crom_chunk model; + u_int32_t flags; + STAILQ_HEAD(, sbp_targ_login) logins; +}; + +struct sbp_targ_softc { + struct firewire_dev_comm fd; + struct cam_sim *sim; + struct cam_path *path; + struct fw_bind fwb; + int ndevs; + int flags; + struct crom_chunk unit; + struct sbp_targ_lstate *lstate[MAX_LUN]; + struct sbp_targ_lstate *black_hole; + struct sbp_targ_login *logins[MAX_LOGINS]; }; struct corb4 { @@ -167,7 +184,7 @@ struct morb4 { struct orb_info { struct sbp_targ_softc *sc; struct fw_device *fwdev; - struct sbp_targ_lstate *lstate; + struct sbp_targ_login *login; union ccb *ccb; struct ccb_accept_tio *atio; u_int8_t state; @@ -196,7 +213,7 @@ static char *orb_fun_name[] = { static void sbp_targ_recv(struct fw_xfer *); static void sbp_targ_fetch_orb(struct sbp_targ_softc *, struct fw_device *, - u_int16_t, u_int32_t, struct sbp_targ_lstate *, int); + u_int16_t, u_int32_t, struct sbp_targ_login *, int); static void sbp_targ_identify(driver_t *driver, device_t parent) @@ -218,6 +235,42 @@ sbp_targ_probe(device_t dev) return (0); } + +static void +sbp_targ_dealloc_login(struct sbp_targ_login *login) +{ + struct orb_info *orbi, *next; + + if (login == NULL) { + printf("%s: login = NULL\n", __FUNCTION__); + return; + } + for (orbi = STAILQ_FIRST(&login->orbs); orbi != NULL; orbi = next) { + next = STAILQ_NEXT(orbi, link); + free(orbi, M_SBP_TARG); + } + callout_stop(&login->hold_callout); + + STAILQ_REMOVE(&login->lstate->logins, login, sbp_targ_login, link); + login->lstate->sc->logins[login->id] = NULL; + free((void *)login, M_SBP_TARG); +} + +static void +sbp_targ_hold_expire(void *arg) +{ + struct sbp_targ_login *login; + + login = (struct sbp_targ_login *)arg; + + if (login->flags & F_HOLD) { + printf("%s: login_id=%d expired\n", __FUNCTION__, login->id); + sbp_targ_dealloc_login(login); + } else { + printf("%s: login_id=%d not hold\n", __FUNCTION__, login->id); + } +} + static void sbp_targ_post_busreset(void *arg) { @@ -226,14 +279,22 @@ sbp_targ_post_busreset(void *arg) struct crom_chunk *root; struct crom_chunk *unit; struct sbp_targ_lstate *lstate; + struct sbp_targ_login *login; int i; - sc = (struct sbp_targ_softc *) arg; + sc = (struct sbp_targ_softc *)arg; src = sc->fd.fc->crom_src; root = sc->fd.fc->crom_root; unit = &sc->unit; + if ((sc->flags & F_FREEZED) == 0) { + sc->flags |= F_FREEZED; + xpt_freeze_simq(sc->sim, /*count*/1); + } else { + printf("%s: already freezed\n", __FUNCTION__); + } + bzero(unit, sizeof(struct crom_chunk)); crom_add_chunk(src, root, unit, CROM_UDIR); @@ -254,6 +315,30 @@ sbp_targ_post_busreset(void *arg) crom_add_entry(unit, CSRKEY_MODEL, 1); crom_add_simple_text(src, unit, &lstate->model, "TargetMode"); } + + /* Process for reconnection hold time */ + for (i = 0; i < MAX_LOGINS; i ++) { + login = sc->logins[i]; + if (login == NULL) + continue; + if (login->flags & F_LOGIN) { + login->flags |= F_HOLD; + callout_reset(&login->hold_callout, + hz * login->hold_sec, + sbp_targ_hold_expire, (void *)login); + } + } +} + +static void +sbp_targ_post_explore(void *arg) +{ + struct sbp_targ_softc *sc; + + sc = (struct sbp_targ_softc *)arg; + sc->flags &= ~F_FREEZED; + xpt_release_simq(sc->sim, /*run queue*/TRUE); + return; } static cam_status @@ -289,7 +374,6 @@ sbp_targ_en_lun(struct sbp_targ_softc *sc, union ccb *ccb) { struct ccb_en_lun *cel = &ccb->cel; struct sbp_targ_lstate *lstate; - struct orb_info *orbi, *next; cam_status status; status = sbp_targ_find_devs(sc, ccb, &lstate, 0); @@ -337,9 +421,7 @@ sbp_targ_en_lun(struct sbp_targ_softc *sc, union ccb *ccb) } SLIST_INIT(&lstate->accept_tios); SLIST_INIT(&lstate->immed_notifies); - STAILQ_INIT(&lstate->orbs); - lstate->last_hi = 0xffff; - lstate->last_lo = 0xffffffff; + STAILQ_INIT(&lstate->logins); ccb->ccb_h.status = CAM_REQ_CMP; xpt_print_path(ccb->ccb_h.path); @@ -347,6 +429,8 @@ sbp_targ_en_lun(struct sbp_targ_softc *sc, union ccb *ccb) /* bus reset */ sc->fd.fc->ibr(sc->fd.fc); } else { + struct sbp_targ_login *login, *next; + if (lstate == NULL) { ccb->ccb_h.status = CAM_LUN_INVALID; return; @@ -371,10 +455,10 @@ sbp_targ_en_lun(struct sbp_targ_softc *sc, union ccb *ccb) printf("Target mode disabled\n"); xpt_free_path(lstate->path); - for (orbi = STAILQ_FIRST(&lstate->orbs); orbi != NULL; - orbi = next) { - next = STAILQ_NEXT(orbi, link); - free(orbi, M_SBP_TARG); + for (login = STAILQ_FIRST(&lstate->logins); login != NULL; + login = next) { + next = STAILQ_NEXT(login, link); + sbp_targ_dealloc_login(login); } if (ccb->ccb_h.target_id == CAM_TARGET_WILDCARD) @@ -401,9 +485,9 @@ sbp_targ_send_lstate_events(struct sbp_targ_softc *sc, } static __inline void -sbp_targ_remove_orb_info(struct sbp_targ_lstate *lstate, struct orb_info *orbi) +sbp_targ_remove_orb_info(struct sbp_targ_login *login, struct orb_info *orbi) { - STAILQ_REMOVE(&lstate->orbs, orbi, orb_info, link); + STAILQ_REMOVE(&login->orbs, orbi, orb_info, link); } /* @@ -415,7 +499,7 @@ sbp_targ_remove_orb_info(struct sbp_targ_lstate *lstate, struct orb_info *orbi) * variables. * * tag_id represents lower 32bit of ORB address. - * init_id represents node_id now. + * init_id represents login_id. * */ @@ -423,18 +507,18 @@ static struct orb_info * sbp_targ_get_orb_info(struct sbp_targ_lstate *lstate, u_int tag_id, u_int init_id) { + struct sbp_targ_login *login; struct orb_info *orbi; - STAILQ_FOREACH(orbi, &lstate->orbs, link) - if (orbi->orb_lo == tag_id && -#if 0 - orbi->orb_hi == (init_id & 0xffff) && - orbi->fwdev->dst == (init_id >> 16)) -#else - orbi->fwdev->dst == init_id) -#endif + login = lstate->sc->logins[init_id]; + if (login == NULL) { + printf("%s: no such login\n", __FUNCTION__); + return (NULL); + } + STAILQ_FOREACH(orbi, &login->orbs, link) + if (orbi->orb_lo == tag_id) goto found; - printf("%s: orb not found\n", __FUNCTION__); + printf("%s: orb not found tag_id=0x%08x\n", __FUNCTION__, tag_id); return (NULL); found: return (orbi); @@ -455,7 +539,7 @@ sbp_targ_abort(struct orb_info *orbi) orbi->ccb = NULL; } if (orbi->state <= ORBI_STATUS_ATIO) { - sbp_targ_remove_orb_info(orbi->lstate, orbi); + sbp_targ_remove_orb_info(orbi->login, orbi); free(orbi, M_SBP_TARG); } else orbi->state = ORBI_STATUS_ABORTED; @@ -484,7 +568,7 @@ sbp_targ_status_FIFO(struct orb_info *orbi, struct fw_xfer *xfer; if (dequeue) - sbp_targ_remove_orb_info(orbi->lstate, orbi); + sbp_targ_remove_orb_info(orbi->login, orbi); xfer = fwmem_write_block(orbi->fwdev, (void *)orbi, /*spd*/2, fifo_hi, fifo_lo, @@ -570,7 +654,7 @@ sbp_targ_send_status(struct orb_info *orbi, union ccb *ccb) } sbp_targ_status_FIFO(orbi, - orbi->lstate->fifo_hi, orbi->lstate->fifo_lo, /*dequeue*/1); + orbi->login->fifo_hi, orbi->login->fifo_lo, /*dequeue*/1); if (orbi->page_table != NULL) free(orbi->page_table, M_SBP_TARG); @@ -584,7 +668,7 @@ sbp_targ_cam_done(struct fw_xfer *xfer) orbi = (struct orb_info *)xfer->sc; - if (debug) + if (debug > 1) printf("%s: resp=%d refcount=%d\n", __FUNCTION__, xfer->resp, orbi->refcount); @@ -603,7 +687,7 @@ sbp_targ_cam_done(struct fw_xfer *xfer) if (orbi->state == ORBI_STATUS_ABORTED) { if (debug) printf("%s: orbi aborted\n", __FUNCTION__); - sbp_targ_remove_orb_info(orbi->lstate, orbi); + sbp_targ_remove_orb_info(orbi->login, orbi); if (orbi->page_table != NULL) free(orbi->page_table, M_SBP_TARG); free(orbi, M_SBP_TARG); @@ -615,7 +699,7 @@ sbp_targ_cam_done(struct fw_xfer *xfer) } else { orbi->status.len = 1; sbp_targ_status_FIFO(orbi, - orbi->lstate->fifo_hi, orbi->lstate->fifo_lo, + orbi->login->fifo_hi, orbi->login->fifo_lo, /*dequeue*/1); ccb->ccb_h.status = CAM_REQ_ABORTED; xpt_done(ccb); @@ -685,7 +769,7 @@ sbp_targ_xfer_buf(struct orb_info *orbi, u_int offset, u_int len, ccb_dir, off = 0; char *ptr; - if (debug) + if (debug > 1) printf("%s: offset=%d size=%d\n", __FUNCTION__, offset, size); ccb_dir = orbi->ccb->ccb_h.flags & CAM_DIR_MASK; ptr = (char *)orbi->ccb->csio.data_ptr + offset; @@ -727,7 +811,7 @@ sbp_targ_pt_done(struct fw_xfer *xfer) if (orbi->state == ORBI_STATUS_ABORTED) { if (debug) printf("%s: orbi aborted\n", __FUNCTION__); - sbp_targ_remove_orb_info(orbi->lstate, orbi); + sbp_targ_remove_orb_info(orbi->login, orbi); free(orbi->page_table, M_SBP_TARG); free(orbi, M_SBP_TARG); fw_xfer_free(xfer); @@ -742,7 +826,7 @@ sbp_targ_pt_done(struct fw_xfer *xfer) sbp_targ_abort(STAILQ_NEXT(orbi, link)); sbp_targ_status_FIFO(orbi, - orbi->lstate->fifo_hi, orbi->lstate->fifo_lo, /*dequeue*/1); + orbi->login->fifo_hi, orbi->login->fifo_lo, /*dequeue*/1); free(orbi->page_table, M_SBP_TARG); fw_xfer_free(xfer); return; @@ -755,7 +839,7 @@ sbp_targ_pt_done(struct fw_xfer *xfer) for (p = orbi->page_table, i = orbi->orb4.data_size; i > 0; i --) { t1 = ntohl(*p++); t2 = ntohl(*p++); - if (debug) + if (debug > 1) printf("page_table: %04x:%08x %d\n", t1 & 0xffff, t2, t1>>16); len = MIN(t1 >> 16, res); @@ -828,8 +912,6 @@ sbp_targ_action1(struct cam_sim *sim, union ccb *ccb) orbi = sbp_targ_get_orb_info(lstate, ccb->csio.tag_id, ccb->csio.init_id); if (orbi == NULL) { - printf("%s: no such ORB found, aborted?\n", - __FUNCTION__); ccb->ccb_h.status = CAM_REQ_ABORTED; /* XXX */ xpt_done(ccb); break; @@ -837,7 +919,7 @@ sbp_targ_action1(struct cam_sim *sim, union ccb *ccb) if (orbi->state == ORBI_STATUS_ABORTED) { if (debug) printf("%s: ctio aborted\n", __FUNCTION__); - sbp_targ_remove_orb_info(orbi->lstate, orbi); + sbp_targ_remove_orb_info(orbi->login, orbi); free(orbi, M_SBP_TARG); break; } @@ -900,13 +982,20 @@ sbp_targ_action1(struct cam_sim *sim, union ccb *ccb) SLIST_INSERT_HEAD(&lstate->accept_tios, &ccb->ccb_h, sim_links.sle); ccb->ccb_h.status = CAM_REQ_INPROG; - if ((lstate->flags & ATIO_STARVED) != 0) { + if ((lstate->flags & F_ATIO_STARVED) != 0) { + struct sbp_targ_login *login; + if (debug) printf("%s: new atio arrived\n", __FUNCTION__); - lstate->flags &= ~ATIO_STARVED; - sbp_targ_fetch_orb(lstate->sc, lstate->fwdev, - lstate->last_hi, lstate->last_lo, - lstate, FETCH_CMD); + lstate->flags &= ~F_ATIO_STARVED; + STAILQ_FOREACH(login, &lstate->logins, link) + if ((login->flags & F_ATIO_STARVED) != 0) { + login->flags &= ~F_ATIO_STARVED; + sbp_targ_fetch_orb(lstate->sc, + login->fwdev, + login->last_hi, login->last_lo, + login, FETCH_CMD); + } } break; case XPT_NOTIFY_ACK: /* recycle notify ack */ @@ -1007,7 +1096,6 @@ sbp_targ_cmd_handler(struct fw_xfer *xfer) struct corb4 *orb4; struct orb_info *orbi; struct ccb_accept_tio *atio; - struct sbp_targ_lstate *lstate; u_char *bytes; int i; @@ -1021,7 +1109,7 @@ sbp_targ_cmd_handler(struct fw_xfer *xfer) sbp_targ_abort(STAILQ_NEXT(orbi, link)); sbp_targ_status_FIFO(orbi, - orbi->lstate->fifo_hi, orbi->lstate->fifo_lo, /*dequeue*/1); + orbi->login->fifo_hi, orbi->login->fifo_lo, /*dequeue*/1); fw_xfer_free(xfer); return; } @@ -1029,14 +1117,12 @@ sbp_targ_cmd_handler(struct fw_xfer *xfer) if (orbi->state == ORBI_STATUS_ABORTED) { printf("%s: aborted\n", __FUNCTION__); - sbp_targ_remove_orb_info(orbi->lstate, orbi); + sbp_targ_remove_orb_info(orbi->login, orbi); free(orbi, M_SBP_TARG); goto done0; } orbi->state = ORBI_STATUS_ATIO; - lstate = orbi->lstate; - orb = orbi->orb; /* swap payload except SCSI command */ for (i = 0; i < 5; i ++) @@ -1050,15 +1136,12 @@ sbp_targ_cmd_handler(struct fw_xfer *xfer) atio = orbi->atio; atio->ccb_h.target_id = 0; /* XXX */ - atio->ccb_h.target_lun = lstate->lun; + atio->ccb_h.target_lun = orbi->login->lstate->lun; atio->sense_len = 0; atio->tag_action = 1; /* XXX */ atio->tag_id = orbi->orb_lo; -#if 0 - atio->init_id = (orbi->fwdev->dst << 16) | (orbi->orb_hi & 0xffff); -#else - atio->init_id = orbi->fwdev->dst; -#endif + atio->init_id = orbi->login->id; + atio->ccb_h.flags = CAM_TAG_ACTION_VALID; bytes = (char *)&orb[5]; if (debug) @@ -1098,10 +1181,10 @@ sbp_targ_cmd_handler(struct fw_xfer *xfer) printf("%s: fetch next orb\n", __FUNCTION__); orbi->status.src = SRC_NEXT_EXISTS; sbp_targ_fetch_orb(orbi->sc, orbi->fwdev, - orb[0], orb[1], orbi->lstate, FETCH_CMD); + orb[0], orb[1], orbi->login, FETCH_CMD); } else { orbi->status.src = SRC_NO_NEXT; - orbi->lstate->flags &= ~LINK_ACTIVE; + orbi->login->flags &= ~F_LINK_ACTIVE; } orbi->data_hi = orb[2]; @@ -1114,10 +1197,51 @@ done0: return; } +static struct sbp_targ_login * +sbp_targ_get_login(struct sbp_targ_softc *sc, struct fw_device *fwdev, int lun) +{ + struct sbp_targ_lstate *lstate; + struct sbp_targ_login *login; + int i; + + lstate = sc->lstate[lun]; + + STAILQ_FOREACH(login, &lstate->logins, link) + if (login->fwdev == fwdev) + return (login); + + for (i = 0; i < MAX_LOGINS; i ++) + if (sc->logins[i] == NULL) + goto found; + + printf("%s: increase MAX_LOGIN\n", __FUNCTION__); + return (NULL); + +found: + login = (struct sbp_targ_login *)malloc( + sizeof(struct sbp_targ_login), M_SBP_TARG, M_NOWAIT | M_ZERO); + + if (login == NULL) { + printf("%s: malloc failed\n", __FUNCTION__); + return (NULL); + } + + login->fwdev = fwdev; + login->lstate = lstate; + login->last_hi = 0xffff; + login->last_lo = 0xffffffff; + login->hold_sec = 1; + STAILQ_INIT(&login->orbs); + CALLOUT_INIT(&login->hold_callout); + sc->logins[i] = login; + return (login); +} + static void sbp_targ_mgm_handler(struct fw_xfer *xfer) { struct sbp_targ_lstate *lstate; + struct sbp_targ_login *login; struct fw_pkt *fp; u_int32_t *orb; struct morb4 *orb4; @@ -1134,7 +1258,7 @@ sbp_targ_mgm_handler(struct fw_xfer *xfer) sbp_targ_abort(STAILQ_NEXT(orbi, link)); sbp_targ_status_FIFO(orbi, - orbi->lstate->fifo_hi, orbi->lstate->fifo_lo, /*dequeue*/0); + orbi->login->fifo_hi, orbi->login->fifo_lo, /*dequeue*/0); fw_xfer_free(xfer); return; } @@ -1154,8 +1278,19 @@ sbp_targ_mgm_handler(struct fw_xfer *xfer) switch (orb4->fun << 16) { case ORB_FUN_LGI: { + int exclusive = 0, lun; + + if (orb[4] & ORB_EXV) + exclusive = 1; - if (orb4->id >= MAX_LUN || orbi->sc->lstate[orb4->id] == NULL) { + lun = orb4->id; + lstate = orbi->sc->lstate[lun]; + + if (lun >= MAX_LUN || lstate == NULL || + (exclusive && + STAILQ_FIRST(&lstate->logins) != NULL && + STAILQ_FIRST(&lstate->logins)->fwdev != orbi->fwdev) + ) { /* error */ orbi->status.dead = 1; orbi->status.status = STATUS_ACCESS_DENY; @@ -1164,25 +1299,55 @@ sbp_targ_mgm_handler(struct fw_xfer *xfer) /*dequeue*/0); break; } - /* XXX check exclusive login */ - lstate = orbi->sc->lstate[orb4->id]; - lstate->fifo_hi = orb[6]; - lstate->fifo_lo = orb[7]; - lstate->login_id = 0; /* XXX random number? */ - lstate->lun = orb4->id; - lstate->loginres.len = htons(sizeof(u_int32_t) * 4); - lstate->loginres.id = htons(lstate->login_id); - lstate->loginres.cmd_hi = htons(SBP_TARG_BIND_HI); - lstate->loginres.cmd_lo = htonl(SBP_TARG_BIND_LO(orb4->id)); - lstate->loginres.recon_hold = htons(0); /* XXX */ + + /* allocate login */ + login = sbp_targ_get_login(orbi->sc, orbi->fwdev, lun); + if (login == NULL) { + printf("%s: sbp_targ_get_login failed\n", + __FUNCTION__); + orbi->status.dead = 1; + orbi->status.status = STATUS_RES_UNAVAIL; + orbi->status.len = 1; + sbp_targ_status_FIFO(orbi, orb[6], orb[7], + /*dequeue*/0); + break; + } + + login->fifo_hi = orb[6]; + login->fifo_lo = orb[7]; + login->loginres.len = htons(sizeof(u_int32_t) * 4); + login->loginres.id = htons(login->id); + login->loginres.cmd_hi = htons(SBP_TARG_BIND_HI); + login->loginres.cmd_lo = htonl(SBP_TARG_BIND_LO(login->id)); + login->loginres.recon_hold = htons(login->hold_sec); + fwmem_write_block(orbi->fwdev, NULL, /*spd*/2, orb[2], orb[3], - sizeof(struct sbp_login_res), (void *)&lstate->loginres, + sizeof(struct sbp_login_res), (void *)&login->loginres, fw_asy_callback_free); + STAILQ_INSERT_TAIL(&lstate->logins, login, link); break; } case ORB_FUN_RCN: - orbi->status.dead = 1; - orbi->status.status = STATUS_ACCESS_DENY; + login = orbi->sc->logins[orb4->id]; + if (login != NULL && login->fwdev == orbi->fwdev) { + login->flags &= ~F_HOLD; + callout_stop(&login->hold_callout); + printf("%s: reconnected id=%d\n", + __FUNCTION__, login->id); + } else { + orbi->status.dead = 1; + orbi->status.status = STATUS_ACCESS_DENY; + printf("%s: reconnection faild id=%d\n", + __FUNCTION__, login->id); + } + break; + case ORB_FUN_LGO: + login = orbi->sc->logins[orb4->id]; + if (login->fwdev != orbi->fwdev) { + printf("%s: wrong initiator\n", __FUNCTION__); + break; + } + sbp_targ_dealloc_login(login); break; default: printf("%s: %s not implemented yet\n", @@ -1213,8 +1378,8 @@ sbp_targ_pointer_handler(struct fw_xfer *xfer) printf("%s: invalid pointer\n", __FUNCTION__); goto done; } - sbp_targ_fetch_orb(orbi->lstate->sc, orbi->fwdev, - (u_int16_t)orb0, orb1, orbi->lstate, FETCH_CMD); + sbp_targ_fetch_orb(orbi->login->lstate->sc, orbi->fwdev, + (u_int16_t)orb0, orb1, orbi->login, FETCH_CMD); done: free(orbi, M_SBP_TARG); fw_xfer_free(xfer); @@ -1223,7 +1388,7 @@ done: static void sbp_targ_fetch_orb(struct sbp_targ_softc *sc, struct fw_device *fwdev, - u_int16_t orb_hi, u_int32_t orb_lo, struct sbp_targ_lstate *lstate, + u_int16_t orb_hi, u_int32_t orb_lo, struct sbp_targ_login *login, int mode) { struct orb_info *orbi; @@ -1237,7 +1402,7 @@ sbp_targ_fetch_orb(struct sbp_targ_softc *sc, struct fw_device *fwdev, } orbi->sc = sc; orbi->fwdev = fwdev; - orbi->lstate = lstate; + orbi->login = login; orbi->orb_hi = orb_hi; orbi->orb_lo = orb_lo; orbi->status.orb_hi = htons(orb_hi); @@ -1251,26 +1416,31 @@ sbp_targ_fetch_orb(struct sbp_targ_softc *sc, struct fw_device *fwdev, break; case FETCH_CMD: orbi->state = ORBI_STATUS_FETCH; - lstate->last_hi = orb_hi; - lstate->last_lo = orb_lo; - lstate->flags |= LINK_ACTIVE; + login->last_hi = orb_hi; + login->last_lo = orb_lo; + login->flags |= F_LINK_ACTIVE; /* dequeue */ orbi->atio = (struct ccb_accept_tio *) - SLIST_FIRST(&lstate->accept_tios); + SLIST_FIRST(&login->lstate->accept_tios); if (orbi->atio == NULL) { printf("%s: no free atio\n", __FUNCTION__); - lstate->flags |= ATIO_STARVED; - lstate->fwdev = fwdev; + login->lstate->flags |= F_ATIO_STARVED; + login->flags |= F_ATIO_STARVED; +#if 0 + /* XXX ?? */ + login->fwdev = fwdev; +#endif break; } - SLIST_REMOVE_HEAD(&lstate->accept_tios, sim_links.sle); + SLIST_REMOVE_HEAD(&login->lstate->accept_tios, sim_links.sle); fwmem_read_block(fwdev, (void *)orbi, /*spd*/2, orb_hi, orb_lo, sizeof(u_int32_t) * 8, &orbi->orb[0], sbp_targ_cmd_handler); - STAILQ_INSERT_TAIL(&lstate->orbs, orbi, link); + STAILQ_INSERT_TAIL(&login->orbs, orbi, link); break; case FETCH_POINTER: orbi->state = ORBI_STATUS_POINTER; + login->flags |= F_LINK_ACTIVE; fwmem_read_block(fwdev, (void *)orbi, /*spd*/2, orb_hi, orb_lo, sizeof(u_int32_t) * 2, &orbi->orb[0], sbp_targ_pointer_handler); @@ -1298,55 +1468,64 @@ sbp_targ_resp_callback(struct fw_xfer *xfer) } static int -sbp_targ_cmd(struct fw_xfer *xfer, struct fw_device *fwdev, int lun, int reg) +sbp_targ_cmd(struct fw_xfer *xfer, struct fw_device *fwdev, int login_id, + int reg) { - struct sbp_targ_lstate *lstate; + struct sbp_targ_login *login; struct sbp_targ_softc *sc; int rtcode = 0; - if (lun < 0 || lun >= MAX_LUN) + if (login_id < 0 || login_id >= MAX_LOGINS) return(RESP_ADDRESS_ERROR); sc = (struct sbp_targ_softc *)xfer->sc; - lstate = sc->lstate[lun]; - if (lstate == NULL) + login = sc->logins[login_id]; + if (login == NULL) + return(RESP_ADDRESS_ERROR); + + if (login->fwdev != fwdev) { + /* XXX */ return(RESP_ADDRESS_ERROR); + } - /* XXX check logined? */ switch (reg) { case 0x08: /* ORB_POINTER */ if (debug) printf("%s: ORB_POINTER\n", __FUNCTION__); - sbp_targ_fetch_orb(lstate->sc, fwdev, + if ((login->flags & F_LINK_ACTIVE) != 0) { + if (debug) + printf("link active (ORB_POINTER)\n"); + break; + } + sbp_targ_fetch_orb(sc, fwdev, ntohl(xfer->recv.payload[0]), ntohl(xfer->recv.payload[1]), - lstate, FETCH_CMD); + login, FETCH_CMD); break; case 0x04: /* AGENT_RESET */ if (debug) printf("%s: AGENT RESET\n", __FUNCTION__); - lstate->last_hi = 0xffff; - lstate->last_lo = 0xffffffff; - sbp_targ_abort(STAILQ_FIRST(&lstate->orbs)); + login->last_hi = 0xffff; + login->last_lo = 0xffffffff; + sbp_targ_abort(STAILQ_FIRST(&login->orbs)); break; case 0x10: /* DOORBELL */ if (debug) printf("%s: DOORBELL\n", __FUNCTION__); - if (lstate->last_hi == 0xffff && - lstate->last_lo == 0xffffffff) { + if (login->last_hi == 0xffff && + login->last_lo == 0xffffffff) { printf("%s: no previous pointer(DOORBELL)\n", __FUNCTION__); break; } - if ((lstate->flags & LINK_ACTIVE) != 0) { + if ((login->flags & F_LINK_ACTIVE) != 0) { if (debug) printf("link active (DOORBELL)\n"); break; } - lstate->flags |= LINK_ACTIVE; - sbp_targ_fetch_orb(lstate->sc, fwdev, - lstate->last_hi, lstate->last_lo, - lstate, FETCH_POINTER); + sbp_targ_fetch_orb(sc, fwdev, + login->last_hi, login->last_lo, + login, FETCH_POINTER); break; case 0x00: /* AGENT_STATE */ printf("%s: AGENT_STATE (ignore)\n", __FUNCTION__); @@ -1408,7 +1587,8 @@ sbp_targ_recv(struct fw_xfer *xfer) if (lo == SBP_TARG_BIND_LO(-1)) rtcode = sbp_targ_mgm(xfer, fwdev); else if (lo >= SBP_TARG_BIND_LO(0)) - rtcode = sbp_targ_cmd(xfer, fwdev, SBP_TARG_LUN(lo), lo % 0x20); + rtcode = sbp_targ_cmd(xfer, fwdev, SBP_TARG_LOGIN_ID(lo), + lo % 0x20); else rtcode = RESP_ADDRESS_ERROR; @@ -1442,7 +1622,7 @@ sbp_targ_attach(device_t dev) sc->fd.fc = device_get_ivars(dev); sc->fd.dev = dev; - sc->fd.post_explore = NULL; + sc->fd.post_explore = (void *) sbp_targ_post_explore; sc->fd.post_busreset = (void *) sbp_targ_post_busreset; devq = cam_simq_alloc(/*maxopenings*/1); |