summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorsimokawa <simokawa@FreeBSD.org>2003-12-11 03:42:40 +0000
committersimokawa <simokawa@FreeBSD.org>2003-12-11 03:42:40 +0000
commitf28990e98496ba9c52a346ada086bb1b40a9a9ca (patch)
treebbce7a7577c862d41145b73de8445621102a2ece /sys
parentc330930b3bebe26fafeea458e0652443cba7c4a3 (diff)
downloadFreeBSD-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')
-rw-r--r--sys/dev/firewire/sbp.h1
-rw-r--r--sys/dev/firewire/sbp_targ.c438
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);
OpenPOWER on IntegriCloud