MFp4:
- Introduce sbp_targ_login instead of sbp_targ_istate. - Implement reconnection and logout. - Freeze simq while bus reset.
This commit is contained in:
parent
d50c65bfce
commit
a73ff5105c
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=123430
@ -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 */
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user