- Introduce sbp_targ_login instead of sbp_targ_istate.
- Implement reconnection and logout.
- Freeze simq while bus reset.
This commit is contained in:
Hidetoshi Shimokawa 2003-12-11 03:42:40 +00:00
parent d50c65bfce
commit a73ff5105c
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=123430
2 changed files with 310 additions and 129 deletions

View File

@ -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 */

View File

@ -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_login {
struct sbp_targ_lstate *lstate;
struct fw_device *fwdev;
struct sbp_login_res loginres;
u_int32_t flags;
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 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_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 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 lun;
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 @@ sbp_targ_cmd_handler(struct fw_xfer *xfer)
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 (orb4->id >= MAX_LUN || orbi->sc->lstate[orb4->id] == NULL) {
if (orb[4] & ORB_EXV)
exclusive = 1;
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 @@ sbp_targ_pointer_handler(struct fw_xfer *xfer)
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);
/* XXX check logined? */
if (login->fwdev != fwdev) {
/* XXX */
return(RESP_ADDRESS_ERROR);
}
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);