Unify port database use for target and initiator roles.

Aside from cleaner and more consistent code, this allows ports to be both
target and initiator same time, and easily switch from any role to any.

Sponsored by:	iXsystems, Inc.
This commit is contained in:
Alexander Motin 2015-07-13 15:11:05 +00:00
parent 647cdd025a
commit e68eef1442
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=285459
6 changed files with 300 additions and 507 deletions

View File

@ -65,16 +65,18 @@ __FBSDID("$FreeBSD$");
*/
#define MBOX_DELAY_COUNT 1000000 / 100
#define ISP_MARK_PORTDB(a, b, c) \
isp_prt(isp, ISP_LOG_SANCFG, \
"Chan %d ISP_MARK_PORTDB@LINE %d", b, __LINE__); \
isp_mark_portdb(a, b, c)
do { \
isp_prt(isp, ISP_LOG_SANCFG, \
"Chan %d ISP_MARK_PORTDB@LINE %d", (b), __LINE__); \
isp_mark_portdb((a), (b), (c)); \
} while (0)
/*
* Local static data
*/
static const char fconf[] = "Chan %d PortDB[%d] changed:\n current =(0x%x@0x%06x 0x%08x%08x 0x%08x%08x)\n database=(0x%x@0x%06x 0x%08x%08x 0x%08x%08x)";
static const char notresp[] = "Not RESPONSE in RESPONSE Queue (type 0x%x) @ idx %d (next %d) nlooked %d";
static const char topology[] = "Chan %d WWPN 0x%08x%08x PortID 0x%06x N-Port Handle %d, Connection '%s'";
static const char topology[] = "Chan %d WWPN 0x%08x%08x PortID 0x%06x handle 0x%x, Connection '%s'";
static const char bun[] = "bad underrun (count %d, resid %d, status %s)";
static const char lipd[] = "Chan %d LIP destroyed %d active commands";
static const char sacq[] = "unable to acquire scratch area";
@ -2222,37 +2224,11 @@ isp_fibre_init_2400(ispsoftc_t *isp)
isp->isp_state = ISP_INITSTATE;
}
static void
isp_del_all_init_entries(ispsoftc_t *isp, int chan)
{
fcparam *fcp = FCPARAM(isp, chan);
fcportdb_t *lp;
int i;
for (i = 0; i < MAX_FC_TARG; i++) {
lp = &fcp->portdb[i];
if (lp->state == FC_PORTDB_STATE_NIL || lp->target_mode)
continue;
lp->state = FC_PORTDB_STATE_NIL;
isp_async(isp, ISPASYNC_DEV_GONE, chan, lp, 1);
if (lp->autologin == 0) {
(void) isp_plogx(isp, chan, lp->handle,
lp->portid,
PLOGX_FLG_CMD_LOGO |
PLOGX_FLG_IMPLICIT |
PLOGX_FLG_FREE_NPHDL, 0);
} else {
lp->autologin = 0;
}
lp->new_prli_word3 = 0;
lp->new_portid = 0;
}
}
static void
isp_mark_portdb(ispsoftc_t *isp, int chan, int disposition)
{
fcparam *fcp = FCPARAM(isp, chan);
fcportdb_t *lp;
int i;
if (chan < 0 || chan >= isp->isp_nchan) {
@ -2260,32 +2236,28 @@ isp_mark_portdb(ispsoftc_t *isp, int chan, int disposition)
return;
}
for (i = 0; i < MAX_FC_TARG; i++) {
if (fcp->portdb[i].target_mode) {
if (disposition < 0) {
isp_prt(isp, ISP_LOGTINFO, "isp_mark_portdb: Chan %d zeroing handle 0x" "%04x port 0x%06x", chan,
fcp->portdb[i].handle, fcp->portdb[i].portid);
ISP_MEMZERO(&fcp->portdb[i], sizeof (fcportdb_t));
}
continue;
}
if (disposition == 0) {
ISP_MEMZERO(&fcp->portdb[i], sizeof (fcportdb_t));
} else {
switch (fcp->portdb[i].state) {
case FC_PORTDB_STATE_CHANGED:
case FC_PORTDB_STATE_PENDING_VALID:
case FC_PORTDB_STATE_VALID:
case FC_PORTDB_STATE_PROBATIONAL:
fcp->portdb[i].state = FC_PORTDB_STATE_PROBATIONAL;
break;
case FC_PORTDB_STATE_ZOMBIE:
break;
case FC_PORTDB_STATE_NIL:
default:
ISP_MEMZERO(&fcp->portdb[i], sizeof (fcportdb_t));
fcp->portdb[i].state = FC_PORTDB_STATE_NIL;
break;
lp = &fcp->portdb[i];
switch (lp->state) {
case FC_PORTDB_STATE_PROBATIONAL:
case FC_PORTDB_STATE_DEAD:
case FC_PORTDB_STATE_CHANGED:
case FC_PORTDB_STATE_PENDING_VALID:
case FC_PORTDB_STATE_VALID:
if (disposition > 0)
lp->state = FC_PORTDB_STATE_PROBATIONAL;
else {
lp->state = FC_PORTDB_STATE_NIL;
isp_async(isp, ISPASYNC_DEV_GONE, chan, lp);
}
break;
case FC_PORTDB_STATE_ZOMBIE:
break;
case FC_PORTDB_STATE_NIL:
case FC_PORTDB_STATE_NEW:
default:
ISP_MEMZERO(lp, sizeof(*lp));
lp->state = FC_PORTDB_STATE_NIL;
break;
}
}
}
@ -2473,7 +2445,7 @@ isp_port_login(ispsoftc_t *isp, uint16_t handle, uint32_t portid)
return (MBOX_PORT_ID_USED | (mbs.param[1] << 16));
case MBOX_LOOP_ID_USED:
isp_prt(isp, ISP_LOG_SANCFG|ISP_LOG_WARN1, "isp_port_login: handle 0x%04x in use for port id 0x%02xXXXX", handle, mbs.param[1] & 0xff);
isp_prt(isp, ISP_LOG_SANCFG|ISP_LOG_WARN1, "isp_port_login: handle 0x%x in use for port id 0x%02xXXXX", handle, mbs.param[1] & 0xff);
return (MBOX_LOOP_ID_USED);
case MBOX_COMMAND_COMPLETE:
@ -2559,7 +2531,7 @@ isp_getpdb(ispsoftc_t *isp, int chan, uint16_t id, isp_pdb_t *pdb, int dolock)
pdb->portid = BITS2WORD_24XX(un.bill.pdb_portid_bits);
ISP_MEMCPY(pdb->portname, un.bill.pdb_portname, 8);
ISP_MEMCPY(pdb->nodename, un.bill.pdb_nodename, 8);
isp_prt(isp, ISP_LOG_SANCFG, "Chan %d Port 0x%06x flags 0x%x curstate %x", chan, pdb->portid, un.bill.pdb_flags, un.bill.pdb_curstate);
isp_prt(isp, ISP_LOG_SANCFG, "Chan %d handle 0x%x Port 0x%06x flags 0x%x curstate %x", chan, id, pdb->portid, un.bill.pdb_flags, un.bill.pdb_curstate);
if (un.bill.pdb_curstate < PDB2400_STATE_PLOGI_DONE || un.bill.pdb_curstate > PDB2400_STATE_LOGGED_IN) {
mbs.param[0] = MBOX_NOT_LOGGED_IN;
if (dolock) {
@ -2587,6 +2559,7 @@ isp_dump_chip_portdb(ispsoftc_t *isp, int chan, int dolock)
isp_pdb_t pdb;
int lim, loopid;
isp_prt(isp, ISP_LOG_SANCFG|ISP_LOGINFO, "Chan %d chip port dump", chan);
if (ISP_CAP_2KLOGIN(isp)) {
lim = NPH_MAX_2K;
} else {
@ -2988,16 +2961,8 @@ isp_pdb_sync(ispsoftc_t *isp, int chan)
for (dbidx = 0; dbidx < MAX_FC_TARG; dbidx++) {
lp = &fcp->portdb[dbidx];
if (lp->state == FC_PORTDB_STATE_NIL || lp->target_mode) {
continue;
}
if (lp->state == FC_PORTDB_STATE_VALID) {
if (dbidx != FL_ID) {
isp_prt(isp,
ISP_LOGERR, "portdb idx %d already valid",
dbidx);
}
if (lp->state == FC_PORTDB_STATE_NIL ||
lp->state == FC_PORTDB_STATE_VALID) {
continue;
}
@ -3005,7 +2970,7 @@ isp_pdb_sync(ispsoftc_t *isp, int chan)
case FC_PORTDB_STATE_PROBATIONAL:
case FC_PORTDB_STATE_DEAD:
lp->state = FC_PORTDB_STATE_NIL;
isp_async(isp, ISPASYNC_DEV_GONE, chan, lp, 0);
isp_async(isp, ISPASYNC_DEV_GONE, chan, lp);
if (lp->autologin == 0) {
(void) isp_plogx(isp, chan, lp->handle,
lp->portid,
@ -3029,17 +2994,14 @@ isp_pdb_sync(ispsoftc_t *isp, int chan)
isp_async(isp, ISPASYNC_DEV_ARRIVED, chan, lp);
lp->new_prli_word3 = 0;
lp->new_portid = 0;
lp->announced = 0;
break;
case FC_PORTDB_STATE_CHANGED:
/*
* XXXX FIX THIS
*/
lp->state = FC_PORTDB_STATE_VALID;
isp_async(isp, ISPASYNC_DEV_CHANGED, chan, lp);
lp->portid = lp->new_portid;
lp->prli_word3 = lp->new_prli_word3;
lp->new_prli_word3 = 0;
lp->new_portid = 0;
lp->announced = 0;
break;
case FC_PORTDB_STATE_PENDING_VALID:
lp->portid = lp->new_portid;
@ -3050,13 +3012,12 @@ isp_pdb_sync(ispsoftc_t *isp, int chan)
lp->new_prli_word3 = 0;
lp->new_portid = 0;
}
lp->announced = 0;
break;
case FC_PORTDB_STATE_ZOMBIE:
break;
default:
isp_prt(isp, ISP_LOGWARN,
"isp_scan_loop: state %d for idx %d",
"isp_pdb_sync: state %d for idx %d",
lp->state, dbidx);
isp_dump_portdb(isp, chan);
}
@ -3127,7 +3088,6 @@ isp_scan_loop(ispsoftc_t *isp, int chan)
isp_prt(isp, ISP_LOG_SANCFG, "Chan %d FC scan loop 0..%d", chan, lim-1);
/*
* Run through the list and get the port database info for each one.
*/
@ -3211,6 +3171,9 @@ isp_scan_loop(ispsoftc_t *isp, int chan)
*/
if (tmp.node_wwn == 0 || tmp.port_wwn == 0 || tmp.portid == 0) {
int a, b, c;
isp_prt(isp, ISP_LOGWARN,
"Chan %d bad pdb (WWNN %016jx, WWPN %016jx, PortID %06x, W3 0x%x, H 0x%x) @ handle 0x%x",
chan, tmp.node_wwn, tmp.port_wwn, tmp.portid, tmp.prli_word3, tmp.handle, handle);
a = (tmp.node_wwn == 0);
b = (tmp.port_wwn == 0);
c = (tmp.portid == 0);
@ -3220,13 +3183,10 @@ isp_scan_loop(ispsoftc_t *isp, int chan)
tmp.port_wwn =
isp_get_wwn(isp, chan, handle, 0);
if (tmp.node_wwn && tmp.port_wwn) {
isp_prt(isp, ISP_LOGINFO, "DODGED!");
isp_prt(isp, ISP_LOGWARN, "DODGED!");
goto cont;
}
}
isp_prt(isp, ISP_LOGWARN,
"Chan %d bad pdb (%1d%1d%1d) @ handle 0x%x", chan,
a, b, c, handle);
isp_dump_portdb(isp, chan);
continue;
}
@ -3234,30 +3194,19 @@ isp_scan_loop(ispsoftc_t *isp, int chan)
/*
* Now search the entire port database
* for the same Port and Node WWN.
* for the same Port WWN.
*/
for (i = 0; i < MAX_FC_TARG; i++) {
lp = &fcp->portdb[i];
if (lp->state == FC_PORTDB_STATE_NIL || lp->target_mode) {
continue;
}
if (lp->node_wwn != tmp.node_wwn) {
continue;
}
if (lp->port_wwn != tmp.port_wwn) {
continue;
}
if (isp_find_pdb_by_wwn(isp, chan, tmp.port_wwn, &lp)) {
/*
* Okay- we've found a non-nil entry that matches.
* Check to make sure it's probational or a zombie.
*/
if (lp->state != FC_PORTDB_STATE_PROBATIONAL &&
lp->state != FC_PORTDB_STATE_ZOMBIE) {
lp->state != FC_PORTDB_STATE_ZOMBIE &&
lp->state != FC_PORTDB_STATE_VALID) {
isp_prt(isp, ISP_LOGERR,
"Chan %d [%d] not probational/zombie (0x%x)",
chan, i, lp->state);
chan, FC_PORTDB_TGT(isp, chan, lp), lp->state);
isp_dump_portdb(isp, chan);
ISP_MARK_PORTDB(isp, chan, 1);
isp_prt(isp, ISP_LOG_SANCFG, "Chan %d FC scan loop DONE (bad)", chan);
@ -3269,6 +3218,7 @@ isp_scan_loop(ispsoftc_t *isp, int chan)
* automatically.
*/
lp->autologin = 1;
lp->node_wwn = tmp.node_wwn;
/*
* Check to make see if really still the same
@ -3279,7 +3229,7 @@ isp_scan_loop(ispsoftc_t *isp, int chan)
lp->new_prli_word3 = tmp.prli_word3;
lp->state = FC_PORTDB_STATE_PENDING_VALID;
isp_prt(isp, ISP_LOG_SANCFG, "Chan %d Loop Port 0x%06x@0x%04x Pending Valid", chan, tmp.portid, tmp.handle);
break;
continue;
}
/*
@ -3296,13 +3246,6 @@ isp_scan_loop(ispsoftc_t *isp, int chan)
lp->state = FC_PORTDB_STATE_CHANGED;
lp->new_portid = tmp.portid;
lp->new_prli_word3 = tmp.prli_word3;
break;
}
/*
* Did we find and update an old entry?
*/
if (i < MAX_FC_TARG) {
continue;
}
@ -3311,9 +3254,6 @@ isp_scan_loop(ispsoftc_t *isp, int chan)
* for it and save info for later disposition.
*/
for (i = 0; i < MAX_FC_TARG; i++) {
if (fcp->portdb[i].target_mode) {
continue;
}
if (fcp->portdb[i].state == FC_PORTDB_STATE_NIL) {
break;
}
@ -3739,7 +3679,7 @@ isp_scan_fabric(ispsoftc_t *isp, int chan)
for (dbidx = 0; dbidx < MAX_FC_TARG; dbidx++) {
lp = &fcp->portdb[dbidx];
if (lp->state != FC_PORTDB_STATE_PROBATIONAL || lp->target_mode) {
if (lp->state != FC_PORTDB_STATE_PROBATIONAL) {
continue;
}
if (lp->portid == portid) {
@ -3781,7 +3721,7 @@ isp_scan_fabric(ispsoftc_t *isp, int chan)
if (r != 0) {
lp->new_portid = portid;
lp->state = FC_PORTDB_STATE_DEAD;
isp_prt(isp, ISP_LOG_SANCFG, "Chan %d Fabric Port 0x%06x is dead", chan, portid);
isp_prt(isp, ISP_LOG_SANCFG, "Chan %d Fabric PortID 0x%06x handle 0x%x is dead (%d)", chan, portid, lp->handle, r);
continue;
}
@ -3797,7 +3737,7 @@ isp_scan_fabric(ispsoftc_t *isp, int chan)
if (pdb.handle != lp->handle ||
pdb.portid != portid ||
wwpn != lp->port_wwn ||
wwnn != lp->node_wwn) {
(lp->node_wwn != 0 && wwnn != lp->node_wwn)) {
isp_prt(isp, ISP_LOG_SANCFG,
fconf, chan, dbidx, pdb.handle, pdb.portid,
(uint32_t) (wwnn >> 32), (uint32_t) wwnn,
@ -3815,8 +3755,9 @@ isp_scan_fabric(ispsoftc_t *isp, int chan)
* portid consistency after re-login.
*
*/
if (isp_login_device(isp, chan, portid, &pdb,
&oldhandle)) {
if ((fcp->role & ISP_ROLE_INITIATOR) == 0 ||
isp_login_device(isp, chan, portid, &pdb,
&oldhandle)) {
lp->new_portid = portid;
lp->state = FC_PORTDB_STATE_DEAD;
if (fcp->isp_loopstate !=
@ -3837,7 +3778,7 @@ isp_scan_fabric(ispsoftc_t *isp, int chan)
MAKE_WWN_FROM_NODE_NAME(wwnn, pdb.nodename);
MAKE_WWN_FROM_NODE_NAME(wwpn, pdb.portname);
if (wwpn != lp->port_wwn ||
wwnn != lp->node_wwn) {
(lp->node_wwn != 0 && wwnn != lp->node_wwn)) {
isp_prt(isp, ISP_LOGWARN, "changed WWN"
" after relogin");
lp->new_portid = portid;
@ -3875,6 +3816,9 @@ isp_scan_fabric(ispsoftc_t *isp, int chan)
continue;
}
if ((fcp->role & ISP_ROLE_INITIATOR) == 0)
continue;
/*
* Ah- a new entry. Search the database again for all non-NIL
* entries to make sure we never ever make a new database entry
@ -3888,12 +3832,6 @@ isp_scan_fabric(ispsoftc_t *isp, int chan)
lp <= &fcp->portdb[SNS_ID]) {
continue;
}
/*
* Skip any target mode entries.
*/
if (lp->target_mode) {
continue;
}
if (lp->state == FC_PORTDB_STATE_NIL) {
if (dbidx == MAX_FC_TARG) {
dbidx = lp - fcp->portdb;
@ -3966,10 +3904,9 @@ isp_scan_fabric(ispsoftc_t *isp, int chan)
if (dbidx >= FL_ID && dbidx <= SNS_ID) {
continue;
}
if (fcp->portdb[dbidx].target_mode) {
continue;
}
if (fcp->portdb[dbidx].node_wwn == wwnn && fcp->portdb[dbidx].port_wwn == wwpn) {
if ((fcp->portdb[dbidx].node_wwn == wwnn ||
fcp->portdb[dbidx].node_wwn == 0) &&
fcp->portdb[dbidx].port_wwn == wwpn) {
break;
}
}
@ -4007,6 +3944,7 @@ isp_scan_fabric(ispsoftc_t *isp, int chan)
*/
lp = &fcp->portdb[dbidx];
lp->handle = handle;
lp->node_wwn = wwnn;
lp->new_portid = portid;
lp->new_prli_word3 = nr;
if (lp->portid != portid || lp->prli_word3 != nr) {
@ -4393,7 +4331,7 @@ isp_start(XS_T *xs)
isp_prt(isp, ISP_LOGDEBUG2, "XS_TGT(xs)=%d", target);
lp = &fcp->portdb[target];
if (target < 0 || target >= MAX_FC_TARG ||
lp->dev_map_idx == 0) {
lp->is_target == 0) {
XS_SETERR(xs, HBA_SELTIMEOUT);
return (CMD_COMPLETE);
}
@ -4406,7 +4344,6 @@ isp_start(XS_T *xs)
XS_SETERR(xs, HBA_SELTIMEOUT);
return (CMD_COMPLETE);
}
lp->dirty = 1;
} else {
sdparam *sdp = SDPARAM(isp, XS_CHANNEL(xs));
if ((sdp->role & ISP_ROLE_INITIATOR) == 0) {
@ -4417,6 +4354,7 @@ isp_start(XS_T *xs)
if (sdp->update) {
isp_spi_update(isp, XS_CHANNEL(xs));
}
lp = NULL;
}
start_again:
@ -4703,7 +4641,7 @@ isp_control(ispsoftc_t *isp, ispctl_t ctl, ...)
break;
}
lp = &fcp->portdb[tgt];
if (lp->dev_map_idx == 0 ||
if (lp->is_target == 0 ||
lp->state != FC_PORTDB_STATE_VALID) {
isp_prt(isp, ISP_LOGWARN, "Chan %d abort of no longer valid target %d", chan, tgt);
break;
@ -4793,7 +4731,7 @@ isp_control(ispsoftc_t *isp, ispctl_t ctl, ...)
break;
}
lp = &fcp->portdb[tgt];
if (lp->dev_map_idx == 0 ||
if (lp->is_target == 0 ||
lp->state != FC_PORTDB_STATE_VALID) {
isp_prt(isp, ISP_LOGWARN, "Chan %d abort of no longer valid target %d", chan, tgt);
break;
@ -5004,12 +4942,6 @@ isp_control(ispsoftc_t *isp, ispctl_t ctl, ...)
role = va_arg(ap, int);
va_end(ap);
if (IS_FC(isp)) {
#ifdef ISP_TARGET_MODE
if ((role & ISP_ROLE_TARGET) == 0)
isp_del_all_wwn_entries(isp, chan);
#endif
if ((role & ISP_ROLE_INITIATOR) == 0)
isp_del_all_init_entries(isp, chan);
r = isp_fc_change_role(isp, chan, role);
} else {
SDPARAM(isp, chan)->role = role;
@ -7887,26 +7819,26 @@ isp_setdfltfcparm(ispsoftc_t *isp, int chan)
* not disturb an already active list of commands.
*/
void
int
isp_reinit(ispsoftc_t *isp, int do_load_defaults)
{
int i;
int i, res = 0;
isp_reset(isp, do_load_defaults);
if (isp->isp_state != ISP_RESETSTATE) {
res = EIO;
isp_prt(isp, ISP_LOGERR, "%s: cannot reset card", __func__);
ISP_DISABLE_INTS(isp);
goto cleanup;
}
isp_init(isp);
if (isp->isp_state == ISP_INITSTATE) {
isp->isp_state = ISP_RUNSTATE;
}
if (isp->isp_state != ISP_RUNSTATE) {
res = EIO;
#ifndef ISP_TARGET_MODE
isp_prt(isp, ISP_LOGWARN, "%s: not at runstate", __func__);
#endif
@ -7923,18 +7855,16 @@ isp_reinit(ispsoftc_t *isp, int do_load_defaults)
ISP_WRITE(isp, BIU2100_CSR, BIU2100_RISC_REGS);
}
}
}
}
cleanup:
isp->isp_nactive = 0;
isp_clear_commands(isp);
if (IS_FC(isp)) {
for (i = 0; i < isp->isp_nchan; i++) {
for (i = 0; i < isp->isp_nchan; i++)
ISP_MARK_PORTDB(isp, i, -1);
}
}
return (res);
}
/*

View File

@ -52,11 +52,10 @@ MODULE_DEPEND(isp, cam, 1, 1, 1);
int isp_announced = 0;
int isp_fabric_hysteresis = 5;
int isp_loop_down_limit = 60; /* default loop down limit */
int isp_change_is_bad = 0; /* "changed" devices are bad */
int isp_quickboot_time = 7; /* don't wait more than N secs for loop up */
int isp_gone_device_time = 30; /* grace time before reporting device lost */
int isp_autoconfig = 1; /* automatically attach/detach devices */
static const char prom3[] = "Chan %d PortID 0x%06x Departed from Target %u because of %s";
static const char prom3[] = "Chan %d [%u] PortID 0x%06x Departed because of %s";
static void isp_freeze_loopdown(ispsoftc_t *, int, char *);
static d_ioctl_t ispioctl;
@ -474,9 +473,6 @@ ispioctl(struct cdev *dev, u_long c, caddr_t addr, int flags, struct thread *td)
case ISP_RESETHBA:
ISP_LOCK(isp);
#ifdef ISP_TARGET_MODE
isp_del_all_wwn_entries(isp, ISP_NOCHAN);
#endif
isp_reinit(isp, 0);
ISP_UNLOCK(isp);
retval = 0;
@ -528,7 +524,7 @@ ispioctl(struct cdev *dev, u_long c, caddr_t addr, int flags, struct thread *td)
break;
}
lp = &FCPARAM(isp, ifc->chan)->portdb[ifc->loopid];
if (lp->state == FC_PORTDB_STATE_VALID || lp->target_mode) {
if (lp->state != FC_PORTDB_STATE_NIL) {
ifc->role = (lp->prli_word3 & SVC3_ROLE_MASK) >> SVC3_ROLE_SHIFT;
ifc->loopid = lp->handle;
ifc->portid = lp->portid;
@ -1512,13 +1508,7 @@ isp_disable_lun(ispsoftc_t *isp, union ccb *ccb)
done:
if (status == CAM_REQ_CMP) {
tptr->enabled = 0;
/*
* If we have no more luns enabled for this bus,
* delete all tracked wwns for it (if we are FC),
* and disable target mode.
*/
if (is_any_lun_enabled(isp, bus) == 0) {
isp_del_all_wwn_entries(isp, bus);
if (isp_disable_target_mode(isp, bus)) {
status = CAM_REQ_CMP_ERR;
}
@ -2467,7 +2457,9 @@ isp_handle_platform_atio2(ispsoftc_t *isp, at2_entry_t *aep)
/*
* If we're not in the port database, add ourselves.
*/
if (!IS_2100(isp) && isp_find_pdb_by_loopid(isp, 0, atiop->init_id, &lp) == 0) {
if (!IS_2100(isp) &&
(isp_find_pdb_by_handle(isp, 0, atiop->init_id, &lp) == 0 ||
lp->state == FC_PORTDB_STATE_ZOMBIE)) {
uint64_t iid =
(((uint64_t) aep->at_wwpn[0]) << 48) |
(((uint64_t) aep->at_wwpn[1]) << 32) |
@ -2594,6 +2586,7 @@ isp_handle_platform_atio7(ispsoftc_t *isp, at7_entry_t *aep)
*/
isp_prt(isp, ISP_LOGTINFO, "%s: [RX_ID 0x%x] D_ID 0x%06x found on Chan %d for S_ID 0x%06x wasn't in PDB already",
__func__, aep->at_rxid, did, chan, sid);
isp_dump_portdb(isp, chan);
isp_endcmd(isp, aep, NIL_HANDLE, chan, ECMD_TERMINATE, 0);
return;
}
@ -3116,7 +3109,7 @@ isp_handle_platform_notify_fc(ispsoftc_t *isp, in_fcentry_t *inp)
} else {
loopid = inp->in_iid;
}
if (isp_find_pdb_by_loopid(isp, 0, loopid, &lp)) {
if (isp_find_pdb_by_handle(isp, 0, loopid, &lp)) {
wwn = lp->port_wwn;
} else {
wwn = INI_ANY;
@ -3270,7 +3263,7 @@ isp_handle_platform_notify_24xx(ispsoftc_t *isp, in_fcentry_24xx_t *inot)
case IN24XX_PORT_LOGOUT:
ptr = "PORT LOGOUT";
if (isp_find_pdb_by_loopid(isp, ISP_GET_VPIDX(isp, inot->in_vpidx), nphdl, &lp)) {
if (isp_find_pdb_by_handle(isp, ISP_GET_VPIDX(isp, inot->in_vpidx), nphdl, &lp)) {
isp_del_wwn_entry(isp, ISP_GET_VPIDX(isp, inot->in_vpidx), lp->port_wwn, nphdl, lp->portid);
}
/* FALLTHROUGH */
@ -4606,13 +4599,6 @@ isp_make_here(ispsoftc_t *isp, fcportdb_t *fcp, int chan, int tgt)
xpt_free_ccb(ccb);
return;
}
/*
* Since we're about to issue a rescan, mark this device as not
* reported gone.
*/
fcp->reported_gone = 0;
xpt_rescan(ccb);
}
@ -4626,11 +4612,6 @@ isp_make_gone(ispsoftc_t *isp, fcportdb_t *fcp, int chan, int tgt)
return;
}
if (xpt_create_path(&tp, NULL, cam_sim_path(fc->sim), tgt, CAM_LUN_WILDCARD) == CAM_REQ_CMP) {
/*
* We're about to send out the lost device async
* notification, so indicate that we have reported it gone.
*/
fcp->reported_gone = 1;
xpt_async(AC_LOST_DEVICE, tp, NULL);
xpt_free_path(tp);
}
@ -4660,6 +4641,8 @@ isp_gdt_task(void *arg, int pending)
ispsoftc_t *isp = fc->isp;
int chan = fc - isp->isp_osinfo.pc.fc;
fcportdb_t *lp;
struct ac_contract ac;
struct ac_device_changed *adc;
int dbidx, more_to_do = 0;
ISP_LOCK(isp);
@ -4670,19 +4653,27 @@ isp_gdt_task(void *arg, int pending)
if (lp->state != FC_PORTDB_STATE_ZOMBIE) {
continue;
}
if (lp->dev_map_idx == 0 || lp->target_mode) {
continue;
}
if (lp->gone_timer != 0) {
isp_prt(isp, ISP_LOG_SANCFG, "%s: Chan %d more to do for target %u (timer=%u)", __func__, chan, lp->dev_map_idx - 1, lp->gone_timer);
lp->gone_timer -= 1;
more_to_do++;
continue;
}
lp->dev_map_idx = 0;
isp_prt(isp, ISP_LOGCONFIG, prom3, chan, dbidx, lp->portid, "Gone Device Timeout");
if (lp->is_target) {
lp->is_target = 0;
isp_make_gone(isp, lp, chan, dbidx);
}
if (lp->is_initiator) {
lp->is_initiator = 0;
ac.contract_number = AC_CONTRACT_DEV_CHG;
adc = (struct ac_device_changed *) ac.contract_data;
adc->wwpn = lp->port_wwn;
adc->port = lp->portid;
adc->target = lp->handle;
adc->arrived = 0;
xpt_async(AC_CONTRACT, fc->path, &ac);
}
lp->state = FC_PORTDB_STATE_NIL;
isp_prt(isp, ISP_LOGCONFIG, prom3, chan, lp->portid, dbidx, "Gone Device Timeout");
isp_make_gone(isp, lp, chan, dbidx);
}
if (fc->ready) {
if (more_to_do) {
@ -4718,6 +4709,8 @@ isp_ldt_task(void *arg, int pending)
ispsoftc_t *isp = fc->isp;
int chan = fc - isp->isp_osinfo.pc.fc;
fcportdb_t *lp;
struct ac_contract ac;
struct ac_device_changed *adc;
int dbidx, i;
ISP_LOCK(isp);
@ -4730,18 +4723,12 @@ isp_ldt_task(void *arg, int pending)
for (dbidx = 0; dbidx < MAX_FC_TARG; dbidx++) {
lp = &FCPARAM(isp, chan)->portdb[dbidx];
if (lp->state != FC_PORTDB_STATE_PROBATIONAL) {
if (lp->state == FC_PORTDB_STATE_NIL)
continue;
}
if (lp->dev_map_idx == 0 || lp->target_mode) {
continue;
}
/*
* XXX: CLEAN UP AND COMPLETE ANY PENDING COMMANDS FIRST!
*/
for (i = 0; i < isp->isp_maxcmds; i++) {
struct ccb_scsiio *xs;
@ -4758,19 +4745,24 @@ isp_ldt_task(void *arg, int pending)
isp->isp_xflist[i].handle, chan, XS_TGT(xs), XS_LUN(xs));
}
/*
* Mark that we've announced that this device is gone....
*/
lp->announced = 1;
lp->dev_map_idx = 0;
lp->state = FC_PORTDB_STATE_NIL;
isp_prt(isp, ISP_LOGCONFIG, prom3, chan, lp->portid, dbidx, "Loop Down Timeout");
isp_make_gone(isp, lp, chan, dbidx);
isp_prt(isp, ISP_LOGCONFIG, prom3, chan, dbidx, lp->portid, "Loop Down Timeout");
if (lp->is_target) {
lp->is_target = 0;
isp_make_gone(isp, lp, chan, dbidx);
}
if (lp->is_initiator) {
lp->is_initiator = 0;
ac.contract_number = AC_CONTRACT_DEV_CHG;
adc = (struct ac_device_changed *) ac.contract_data;
adc->wwpn = lp->port_wwn;
adc->port = lp->portid;
adc->target = lp->handle;
adc->arrived = 0;
xpt_async(AC_CONTRACT, fc->path, &ac);
}
}
if (FCPARAM(isp, chan)->role & ISP_ROLE_INITIATOR) {
isp_unfreeze_loopdown(isp, chan);
}
isp_unfreeze_loopdown(isp, chan);
/*
* The loop down timer has expired. Wake up the kthread
* to notice that fact (or make it false).
@ -5585,7 +5577,7 @@ isp_done(XS_T *sccb)
fcparam *fcp;
fcp = FCPARAM(isp, XS_CHANNEL(sccb));
fcp->portdb[XS_TGT(sccb)].reported_gone = 1;
fcp->portdb[XS_TGT(sccb)].is_target = 0;
}
if ((sccb->ccb_h.status & CAM_DEV_QFRZN) == 0) {
sccb->ccb_h.status |= CAM_DEV_QFRZN;
@ -5608,15 +5600,16 @@ isp_done(XS_T *sccb)
void
isp_async(ispsoftc_t *isp, ispasync_t cmd, ...)
{
int bus, now;
static const char prom0[] = "Chan %d PortID 0x%06x handle 0x%x %s %s WWPN 0x%08x%08x";
static const char prom2[] = "Chan %d PortID 0x%06x handle 0x%x %s %s tgt %u WWPN 0x%08x%08x";
int bus;
static const char prom[] = "Chan %d [%d] WWPN 0x%16jx PortID 0x%06x handle 0x%x %s %s";
char buf[64];
char *msg = NULL;
target_id_t tgt;
fcportdb_t *lp;
struct isp_fc *fc;
struct cam_path *tmppath;
struct ac_contract ac;
struct ac_device_changed *adc;
va_list ap;
switch (cmd) {
@ -5718,10 +5711,10 @@ isp_async(ispsoftc_t *isp, ispasync_t cmd, ...)
if (fc->path) {
isp_freeze_loopdown(isp, bus, msg);
}
if (!callout_active(&fc->ldt)) {
callout_reset(&fc->ldt, fc->loop_down_limit * hz, isp_ldt, fc);
isp_prt(isp, ISP_LOG_SANCFG|ISP_LOGDEBUG0, "Starting Loop Down Timer @ %lu", (unsigned long) time_uptime);
}
}
if (!callout_active(&fc->ldt)) {
callout_reset(&fc->ldt, fc->loop_down_limit * hz, isp_ldt, fc);
isp_prt(isp, ISP_LOG_SANCFG|ISP_LOGDEBUG0, "Starting Loop Down Timer @ %lu", (unsigned long) time_uptime);
}
}
isp_fcp_reset_crn(fc, /*tgt*/0, /*tgt_set*/ 0);
@ -5751,19 +5744,25 @@ isp_async(ispsoftc_t *isp, ispasync_t cmd, ...)
lp = va_arg(ap, fcportdb_t *);
va_end(ap);
fc = ISP_FC_PC(isp, bus);
lp->announced = 0;
lp->gone_timer = 0;
if ((FCPARAM(isp, bus)->role & ISP_ROLE_INITIATOR) && (lp->prli_word3 & PRLI_WD3_TARGET_FUNCTION)) {
lp->dev_map_idx = (lp - FCPARAM(isp, bus)->portdb) + 1;
}
tgt = FC_PORTDB_TGT(isp, bus, lp);
isp_gen_role_str(buf, sizeof (buf), lp->prli_word3);
if (lp->dev_map_idx) {
tgt = lp->dev_map_idx - 1;
isp_prt(isp, ISP_LOGCONFIG, prom2, bus, lp->portid, lp->handle, buf, "arrived at", tgt, (uint32_t) (lp->port_wwn >> 32), (uint32_t) lp->port_wwn);
isp_prt(isp, ISP_LOGCONFIG, prom, bus, tgt, lp->port_wwn, lp->portid, lp->handle, buf, "arrived");
if ((FCPARAM(isp, bus)->role & ISP_ROLE_INITIATOR) &&
(lp->prli_word3 & PRLI_WD3_TARGET_FUNCTION)) {
lp->is_target = 1;
isp_fcp_reset_crn(fc, tgt, /*tgt_set*/ 1);
isp_make_here(isp, lp, bus, tgt);
} else {
isp_prt(isp, ISP_LOGCONFIG, prom0, bus, lp->portid, lp->handle, buf, "arrived", (uint32_t) (lp->port_wwn >> 32), (uint32_t) lp->port_wwn);
}
if ((FCPARAM(isp, bus)->role & ISP_ROLE_TARGET) &&
(lp->prli_word3 & PRLI_WD3_INITIATOR_FUNCTION)) {
lp->is_initiator = 1;
ac.contract_number = AC_CONTRACT_DEV_CHG;
adc = (struct ac_device_changed *) ac.contract_data;
adc->wwpn = lp->port_wwn;
adc->port = lp->portid;
adc->target = lp->handle;
adc->arrived = 1;
xpt_async(AC_CONTRACT, fc->path, &ac);
}
break;
case ISPASYNC_DEV_CHANGED:
@ -5772,97 +5771,68 @@ isp_async(ispsoftc_t *isp, ispasync_t cmd, ...)
lp = va_arg(ap, fcportdb_t *);
va_end(ap);
fc = ISP_FC_PC(isp, bus);
lp->announced = 0;
lp->gone_timer = 0;
if (isp_change_is_bad) {
lp->state = FC_PORTDB_STATE_NIL;
if (lp->dev_map_idx) {
tgt = lp->dev_map_idx - 1;
lp->dev_map_idx = 0;
isp_prt(isp, ISP_LOGCONFIG, prom3, bus, lp->portid, tgt, "change is bad");
isp_make_gone(isp, lp, bus, tgt);
} else {
isp_gen_role_str(buf, sizeof (buf), lp->prli_word3);
isp_prt(isp, ISP_LOGCONFIG, prom0, bus, lp->portid, lp->handle, buf, "changed and departed",
(uint32_t) (lp->port_wwn >> 32), (uint32_t) lp->port_wwn);
}
} else {
lp->portid = lp->new_portid;
lp->prli_word3 = lp->new_prli_word3;
isp_gen_role_str(buf, sizeof (buf), lp->prli_word3);
if (lp->dev_map_idx) {
tgt = lp->dev_map_idx - 1;
isp_prt(isp, ISP_LOGCONFIG, prom2, bus, lp->portid, lp->handle, buf, "changed at", tgt,
(uint32_t) (lp->port_wwn >> 32), (uint32_t) lp->port_wwn);
tgt = FC_PORTDB_TGT(isp, bus, lp);
isp_gen_role_str(buf, sizeof (buf), lp->new_prli_word3);
isp_prt(isp, ISP_LOGCONFIG, prom, bus, tgt, lp->port_wwn, lp->new_portid, lp->handle, buf, "changed");
changed:
if (lp->is_target !=
((FCPARAM(isp, bus)->role & ISP_ROLE_INITIATOR) &&
(lp->new_prli_word3 & PRLI_WD3_TARGET_FUNCTION))) {
lp->is_target = !lp->is_target;
if (lp->is_target) {
isp_fcp_reset_crn(fc, tgt, /*tgt_set*/ 1);
isp_make_here(isp, lp, bus, tgt);
} else {
isp_prt(isp, ISP_LOGCONFIG, prom0, bus, lp->portid, lp->handle, buf, "changed", (uint32_t) (lp->port_wwn >> 32), (uint32_t) lp->port_wwn);
isp_make_gone(isp, lp, bus, tgt);
isp_fcp_reset_crn(fc, tgt, /*tgt_set*/ 1);
}
}
if (lp->is_initiator !=
((FCPARAM(isp, bus)->role & ISP_ROLE_TARGET) &&
(lp->new_prli_word3 & PRLI_WD3_INITIATOR_FUNCTION))) {
lp->is_initiator = !lp->is_initiator;
ac.contract_number = AC_CONTRACT_DEV_CHG;
adc = (struct ac_device_changed *) ac.contract_data;
adc->wwpn = lp->port_wwn;
adc->port = lp->portid;
adc->target = lp->handle;
adc->arrived = lp->is_initiator;
xpt_async(AC_CONTRACT, fc->path, &ac);
}
break;
case ISPASYNC_DEV_STAYED:
va_start(ap, cmd);
bus = va_arg(ap, int);
lp = va_arg(ap, fcportdb_t *);
va_end(ap);
fc = ISP_FC_PC(isp, bus);
tgt = FC_PORTDB_TGT(isp, bus, lp);
isp_gen_role_str(buf, sizeof (buf), lp->prli_word3);
if (lp->dev_map_idx) {
fc = ISP_FC_PC(isp, bus);
tgt = lp->dev_map_idx - 1;
isp_prt(isp, ISP_LOGCONFIG, prom2, bus, lp->portid, lp->handle, buf, "stayed at", tgt,
(uint32_t) (lp->port_wwn >> 32), (uint32_t) lp->port_wwn);
/*
* Only issue a rescan if we've actually reported
* that this device is gone.
*/
if (lp->reported_gone != 0) {
isp_prt(isp, ISP_LOGCONFIG, prom2, bus, lp->portid, lp->handle, buf, "rescanned at", tgt,
(uint32_t) (lp->port_wwn >> 32), (uint32_t) lp->port_wwn);
isp_make_here(isp, lp, bus, tgt);
}
} else {
isp_prt(isp, ISP_LOGCONFIG, prom0, bus, lp->portid, lp->handle, buf, "stayed",
(uint32_t) (lp->port_wwn >> 32), (uint32_t) lp->port_wwn);
}
break;
isp_prt(isp, ISP_LOGCONFIG, prom, bus, tgt, lp->port_wwn, lp->portid, lp->handle, buf, "stayed");
goto changed;
case ISPASYNC_DEV_GONE:
va_start(ap, cmd);
bus = va_arg(ap, int);
lp = va_arg(ap, fcportdb_t *);
now = va_arg(ap, int);
va_end(ap);
fc = ISP_FC_PC(isp, bus);
tgt = FC_PORTDB_TGT(isp, bus, lp);
/*
* If this has a virtual target and we haven't marked it
* that we're going to have isp_gdt tell the OS it's gone,
* set the isp_gdt timer running on it.
*
* If it isn't marked that isp_gdt is going to get rid of it,
* announce that it's gone.
*
* If this has a virtual target or initiator set the isp_gdt
* timer running on it to delay its departure.
*/
isp_gen_role_str(buf, sizeof (buf), lp->prli_word3);
if (lp->dev_map_idx && lp->announced == 0 && now) {
lp->announced = 1;
tgt = lp->dev_map_idx - 1;
lp->dev_map_idx = 0;
isp_make_gone(isp, lp, bus, tgt);
isp_prt(isp, ISP_LOGCONFIG, prom2, bus, lp->portid, lp->handle, buf, "gone at", tgt, (uint32_t) (lp->port_wwn >> 32), (uint32_t) lp->port_wwn);
isp_fcp_reset_crn(fc, tgt, /*tgt_set*/ 1);
} else if (lp->dev_map_idx && lp->announced == 0) {
lp->announced = 1;
if (lp->is_target || lp->is_initiator) {
lp->state = FC_PORTDB_STATE_ZOMBIE;
lp->gone_timer = ISP_FC_PC(isp, bus)->gone_device_time;
lp->gone_timer = fc->gone_device_time;
isp_prt(isp, ISP_LOGCONFIG, prom, bus, tgt, lp->port_wwn, lp->portid, lp->handle, buf, "gone zombie");
if (fc->ready && !callout_active(&fc->gdt)) {
isp_prt(isp, ISP_LOG_SANCFG|ISP_LOGDEBUG0, "Chan %d Starting Gone Device Timer with %u seconds time now %lu", bus, lp->gone_timer, (unsigned long)time_uptime);
callout_reset(&fc->gdt, hz, isp_gdt, fc);
}
tgt = lp->dev_map_idx - 1;
isp_prt(isp, ISP_LOGCONFIG, prom2, bus, lp->portid, lp->handle, buf, "gone zombie at", tgt, (uint32_t) (lp->port_wwn >> 32), (uint32_t) lp->port_wwn);
isp_fcp_reset_crn(fc, tgt, /*tgt_set*/ 1);
} else if (lp->announced == 0) {
isp_prt(isp, ISP_LOGCONFIG, prom0, bus, lp->portid, lp->handle, buf, "departed", (uint32_t) (lp->port_wwn >> 32), (uint32_t) lp->port_wwn);
break;
}
isp_prt(isp, ISP_LOGCONFIG, prom, bus, tgt, lp->port_wwn, lp->portid, lp->handle, buf, "gone");
break;
case ISPASYNC_CHANGE_NOTIFY:
{
@ -5928,13 +5898,11 @@ isp_async(ispsoftc_t *isp, ispasync_t cmd, ...)
case NT_LIP_RESET:
case NT_LINK_UP:
case NT_LINK_DOWN:
case NT_HBA_RESET:
/*
* No action need be taken here.
*/
break;
case NT_HBA_RESET:
isp_del_all_wwn_entries(isp, ISP_NOCHAN);
break;
case NT_GLOBAL_LOGOUT:
case NT_LOGOUT:
/*
@ -5942,34 +5910,6 @@ isp_async(ispsoftc_t *isp, ispasync_t cmd, ...)
*/
isp_handle_platform_target_notify_ack(isp, notify);
break;
case NT_ARRIVED:
{
struct ac_contract ac;
struct ac_device_changed *fc;
ac.contract_number = AC_CONTRACT_DEV_CHG;
fc = (struct ac_device_changed *) ac.contract_data;
fc->wwpn = notify->nt_wwn;
fc->port = notify->nt_sid;
fc->target = notify->nt_nphdl;
fc->arrived = 1;
xpt_async(AC_CONTRACT, ISP_FC_PC(isp, notify->nt_channel)->path, &ac);
break;
}
case NT_DEPARTED:
{
struct ac_contract ac;
struct ac_device_changed *fc;
ac.contract_number = AC_CONTRACT_DEV_CHG;
fc = (struct ac_device_changed *) ac.contract_data;
fc->wwpn = notify->nt_wwn;
fc->port = notify->nt_sid;
fc->target = notify->nt_nphdl;
fc->arrived = 0;
xpt_async(AC_CONTRACT, ISP_FC_PC(isp, notify->nt_channel)->path, &ac);
break;
}
default:
isp_prt(isp, ISP_LOGALL, "target notify code 0x%x", notify->nt_ncode);
isp_handle_platform_target_notify_ack(isp, notify);
@ -6060,7 +6000,7 @@ isp_async(ispsoftc_t *isp, ispasync_t cmd, ...)
nt->nt_tgt = TGT_ANY;
} else {
nt->nt_tgt = FCPARAM(isp, chan)->isp_wwpn;
if (isp_find_pdb_by_loopid(isp, chan, abts->abts_nphdl, &lp)) {
if (isp_find_pdb_by_handle(isp, chan, abts->abts_nphdl, &lp)) {
nt->nt_wwn = lp->port_wwn;
} else {
nt->nt_wwn = INI_ANY;

View File

@ -411,10 +411,6 @@ isp_fc_runstate(ispsoftc_t *isp, int chan, int tval)
}
}
if ((fcp->role & ISP_ROLE_INITIATOR) == 0) {
return (0);
}
if (isp_control(isp, ISPCTL_SCAN_LOOP, chan) != 0) {
isp_prt(isp, ISP_LOG_SANCFG, "isp_fc_runstate: scan loop fails on channel %d", chan);
return (LOOP_PDB_RCVD);
@ -444,7 +440,7 @@ isp_dump_portdb(ispsoftc_t *isp, int chan)
int i;
for (i = 0; i < MAX_FC_TARG; i++) {
char mb[4], buf1[64], buf2[64];
char buf1[64], buf2[64];
const char *dbs[8] = {
"NIL ",
"PROB",
@ -457,18 +453,13 @@ isp_dump_portdb(ispsoftc_t *isp, int chan)
};
fcportdb_t *lp = &fcp->portdb[i];
if (lp->state == FC_PORTDB_STATE_NIL && lp->target_mode == 0) {
if (lp->state == FC_PORTDB_STATE_NIL) {
continue;
}
if (lp->dev_map_idx) {
ISP_SNPRINTF(mb, sizeof (mb), "%3d", ((int) lp->dev_map_idx) - 1);
} else {
ISP_SNPRINTF(mb, sizeof (mb), "---");
}
isp_gen_role_str(buf1, sizeof (buf1), lp->prli_word3);
isp_gen_role_str(buf2, sizeof (buf2), lp->new_prli_word3);
isp_prt(isp, ISP_LOGALL, "Chan %d [%d]: hdl 0x%x %s al%d tgt %s %s 0x%06x =>%s 0x%06x; WWNN 0x%08x%08x WWPN 0x%08x%08x",
chan, i, lp->handle, dbs[lp->state], lp->autologin, mb, buf1, lp->portid, buf2, lp->new_portid,
isp_prt(isp, ISP_LOGALL, "Chan %d [%d]: hdl 0x%x %s al%d %s 0x%06x =>%s 0x%06x; WWNN 0x%08x%08x WWPN 0x%08x%08x",
chan, i, lp->handle, dbs[lp->state], lp->autologin, buf1, lp->portid, buf2, lp->new_portid,
(uint32_t) (lp->node_wwn >> 32), (uint32_t) (lp->node_wwn), (uint32_t) (lp->port_wwn >> 32), (uint32_t) (lp->port_wwn));
}
}
@ -603,20 +594,8 @@ isp_fc_change_role(ispsoftc_t *isp, int chan, int new_role)
return (ENXIO);
}
if (chan == 0) {
isp_clear_commands(isp);
isp_reset(isp, 0);
if (isp->isp_state != ISP_RESETSTATE) {
isp_prt(isp, ISP_LOGERR, "%s: cannot reset card", __func__);
return (EIO);
}
fcp->role = new_role;
isp_init(isp);
if (isp->isp_state != ISP_INITSTATE) {
isp_prt(isp, ISP_LOGERR, "%s: cannot init card", __func__);
return (EIO);
}
isp->isp_state = ISP_RUNSTATE;
return (0);
return (isp_reinit(isp, 0));
} else if (ISP_CAP_MULTI_ID(isp)) {
mbreg_t mbs;
vp_modify_t *vp;
@ -2347,8 +2326,10 @@ isp_destroy_tgt_handle(ispsoftc_t *isp, uint32_t handle)
}
}
#endif
/*
* Find target mode entries
* Find port database entries
*/
int
isp_find_pdb_by_wwn(ispsoftc_t *isp, int chan, uint64_t wwn, fcportdb_t **lptr)
@ -2359,10 +2340,10 @@ isp_find_pdb_by_wwn(ispsoftc_t *isp, int chan, uint64_t wwn, fcportdb_t **lptr)
if (chan >= isp->isp_nchan)
return (0);
fcp = FCPARAM(isp, chan);
for (i = MAX_FC_TARG - 1; i >= 0; i--) {
for (i = 0; i < MAX_FC_TARG; i++) {
fcportdb_t *lp = &fcp->portdb[i];
if (lp->target_mode == 0)
if (lp->state == FC_PORTDB_STATE_NIL)
continue;
if (lp->port_wwn == wwn) {
*lptr = lp;
@ -2372,8 +2353,10 @@ isp_find_pdb_by_wwn(ispsoftc_t *isp, int chan, uint64_t wwn, fcportdb_t **lptr)
return (0);
}
#ifdef ISP_TARGET_MODE
int
isp_find_pdb_by_loopid(ispsoftc_t *isp, int chan, uint32_t loopid, fcportdb_t **lptr)
isp_find_pdb_by_handle(ispsoftc_t *isp, int chan, uint32_t handle, fcportdb_t **lptr)
{
fcparam *fcp;
int i;
@ -2381,9 +2364,15 @@ isp_find_pdb_by_loopid(ispsoftc_t *isp, int chan, uint32_t loopid, fcportdb_t **
if (chan >= isp->isp_nchan)
return (0);
fcp = FCPARAM(isp, chan);
if ((i = fcp->isp_tgt_map[loopid]) > 0) {
*lptr = &fcp->portdb[i - 1];
return (1);
for (i = 0; i < MAX_FC_TARG; i++) {
fcportdb_t *lp = &fcp->portdb[i];
if (lp->state == FC_PORTDB_STATE_NIL)
continue;
if (lp->handle == handle) {
*lptr = lp;
return (1);
}
}
return (0);
}
@ -2397,10 +2386,10 @@ isp_find_pdb_by_sid(ispsoftc_t *isp, int chan, uint32_t sid, fcportdb_t **lptr)
if (chan >= isp->isp_nchan)
return (0);
fcp = FCPARAM(isp, chan);
for (i = MAX_FC_TARG - 1; i >= 0; i--) {
for (i = 0; i < MAX_FC_TARG; i++) {
fcportdb_t *lp = &fcp->portdb[i];
if (lp->target_mode == 0)
if (lp->state == FC_PORTDB_STATE_NIL)
continue;
if (lp->portid == sid) {
*lptr = lp;
@ -2437,14 +2426,13 @@ isp_add_wwn_entry(ispsoftc_t *isp, int chan, uint64_t ini, uint16_t nphdl, uint3
char buf[64];
fcparam *fcp;
fcportdb_t *lp;
isp_notify_t nt;
int i, something, take, taken;
int i, change;
fcp = FCPARAM(isp, chan);
if (nphdl >= MAX_NPORT_HANDLE) {
isp_prt(isp, ISP_LOGWARN, "Chan %d IID 0x%016llx "
"N-Port handle 0x%04x Port ID 0x%06x -- bad handle",
chan, (unsigned long long) ini, nphdl, s_id);
isp_prt(isp, ISP_LOGTINFO|ISP_LOGWARN, "Chan %d WWPN 0x%016llx "
"PortID 0x%06x handle 0x%x -- bad handle",
chan, (unsigned long long) ini, s_id, nphdl);
return;
}
@ -2453,146 +2441,118 @@ isp_add_wwn_entry(ispsoftc_t *isp, int chan, uint64_t ini, uint16_t nphdl, uint3
* with new parameters. Some cases of update can be suspicious,
* so log them verbosely and dump the whole port database.
*/
if ((i = fcp->isp_tgt_map[nphdl]) > 0) {
take = taken = i - 1;
lp = &fcp->portdb[taken];
something = 0;
if ((VALID_INI(ini) && isp_find_pdb_by_wwn(isp, chan, ini, &lp)) ||
(s_id != PORT_NONE && isp_find_pdb_by_sid(isp, chan, s_id, &lp))) {
change = 0;
lp->new_portid = lp->portid;
lp->new_prli_word3 = lp->prli_word3;
if (s_id != PORT_NONE && lp->portid != s_id) {
if (lp->portid == PORT_NONE) {
isp_prt(isp, ISP_LOGTINFO,
"Chan %d IID 0x%016llx N-port handle 0x%04x "
"gets Port ID 0x%06x",
"Chan %d WWPN 0x%016llx handle 0x%x "
"gets PortID 0x%06x",
chan, (unsigned long long) lp->port_wwn,
nphdl, s_id);
} else {
isp_prt(isp, ISP_LOGTINFO|ISP_LOGWARN,
"Chan %d IID 0x%016llx N-port handle 0x%04x "
"changes Port ID 0x%06x to 0x%06x",
"Chan %d WWPN 0x%016llx handle 0x%x "
"changes PortID 0x%06x to 0x%06x",
chan, (unsigned long long) lp->port_wwn,
nphdl, lp->portid, s_id);
if (isp->isp_dblev & (ISP_LOGTINFO|ISP_LOGWARN))
isp_dump_portdb(isp, chan);
}
lp->portid = s_id;
something++;
lp->new_portid = s_id;
change++;
}
if (VALID_INI(ini) && lp->port_wwn != ini) {
if (!VALID_INI(lp->port_wwn)) {
isp_prt(isp, ISP_LOGTINFO,
"Chan %d N-port handle 0x%04x Port ID "
"0x%06x gets WWN 0x%016llxx",
chan, nphdl, lp->portid,
"Chan %d PortID 0x%06x handle 0x%x "
"gets WWN 0x%016llxx",
chan, lp->portid, nphdl,
(unsigned long long) ini);
} else if (lp->port_wwn != ini) {
isp_prt(isp, ISP_LOGTINFO|ISP_LOGWARN,
"Chan %d N-port handle 0x%04x Port ID "
"0x%06x changes WWN 0x%016llx to 0x%016llx",
chan, nphdl, lp->portid,
"Chan %d PortID 0x%06x handle 0x%x "
"changes WWN 0x%016llx to 0x%016llx",
chan, lp->portid, nphdl,
(unsigned long long) lp->port_wwn,
(unsigned long long) ini);
if (isp->isp_dblev & (ISP_LOGTINFO|ISP_LOGWARN))
isp_dump_portdb(isp, chan);
}
lp->port_wwn = ini;
something++;
change++;
}
if (lp->prli_word3 != prli_params) {
lp->prli_word3 = prli_params;
isp_gen_role_str(buf, sizeof (buf), lp->prli_word3);
if (prli_params != 0 && lp->prli_word3 != prli_params) {
isp_gen_role_str(buf, sizeof (buf), prli_params);
isp_prt(isp, ISP_LOGTINFO|ISP_LOGCONFIG,
"Chan %d IID 0x%016llx N-Port Handle 0x%04x "
"Port ID 0x%06x changes PRLI Word 3 %s",
"Chan %d WWPN 0x%016llx PortID 0x%06x "
"handle 0x%x changes PRLI Word 3 %s",
chan, (unsigned long long) lp->port_wwn,
lp->handle, lp->portid, buf);
something++;
lp->portid, lp->handle, buf);
lp->new_prli_word3 = prli_params;
change++;
}
if (!something) {
if (lp->handle != nphdl) {
isp_prt(isp, ISP_LOGTINFO|ISP_LOGCONFIG,
"Chan %d WWPN 0x%016llx PortID 0x%06x "
"changes handle 0x%x to 0x%x",
chan, (unsigned long long) lp->port_wwn,
lp->portid, lp->handle, nphdl);
lp->handle = nphdl;
change++;
}
lp->state = FC_PORTDB_STATE_VALID;
if (change) {
isp_async(isp, ISPASYNC_DEV_CHANGED, chan, lp);
lp->portid = lp->new_portid;
lp->prli_word3 = lp->new_prli_word3;
lp->new_prli_word3 = 0;
lp->new_portid = 0;
} else {
isp_prt(isp, ISP_LOGTINFO,
"Chan %d IID 0x%016llx N-Port Handle 0x%04x "
"Port ID 0x%06x reentered",
"Chan %d WWPN 0x%016llx PortID 0x%06x "
"handle 0x%x reentered",
chan, (unsigned long long) lp->port_wwn,
lp->handle, lp->portid);
lp->portid, lp->handle);
isp_async(isp, ISPASYNC_DEV_STAYED, chan, lp);
}
} else
take = taken = -1;
/*
* Search for records colliding on handler, Port ID or WWN.
* Remove any found collisions, logging suspicious cases of
* still valid records.
*/
for (i = 0; i < MAX_FC_TARG; i++) {
lp = &fcp->portdb[i];
if (lp->target_mode == 0 || i == take)
continue;
if (lp->handle != nphdl && lp->portid != s_id &&
lp->port_wwn != ini)
continue;
if (lp->state == FC_PORTDB_STATE_VALID) {
isp_prt(isp, ISP_LOGTINFO|ISP_LOGWARN,
"Chan %d IID 0x%016llx N-Port Handle 0x%04x "
"Port ID 0x%06x is conflicting",
chan, (unsigned long long) lp->port_wwn,
lp->handle, lp->portid);
if (isp->isp_dblev & (ISP_LOGTINFO|ISP_LOGWARN))
isp_dump_portdb(isp, chan);
isp_del_wwn_entry(isp, chan,
lp->port_wwn, lp->handle, lp->portid);
}
ISP_MEMZERO(lp, sizeof (fcportdb_t));
take = i;
}
/* If valid record already exists -- we are done. */
if (taken >= 0)
return;
}
/* Search for room to insert new record. */
if (take < 0) {
for (i = MAX_FC_TARG - 1; i >= 0; i--) {
if (fcp->portdb[i].state == FC_PORTDB_STATE_NIL) {
take = i;
break;
}
}
for (i = 0; i < MAX_FC_TARG; i++) {
if (fcp->portdb[i].state == FC_PORTDB_STATE_NIL)
break;
}
if (take < 0) {
if (i >= MAX_FC_TARG) {
isp_prt(isp, ISP_LOGTINFO|ISP_LOGWARN,
"Chan %d IID 0x%016llx N-Port Handle 0x%04x Port ID 0x%06x "
"Chan %d WWPN 0x%016llx PortID 0x%06x handle 0x%x "
"-- no room in port database",
chan, (unsigned long long) ini, nphdl, s_id);
chan, (unsigned long long) ini, s_id, nphdl);
if (isp->isp_dblev & (ISP_LOGTINFO|ISP_LOGWARN))
isp_dump_portdb(isp, chan);
return;
}
/* Insert new record and mark it valid. */
lp = &fcp->portdb[take];
lp = &fcp->portdb[i];
ISP_MEMZERO(lp, sizeof (fcportdb_t));
lp->target_mode = 1;
lp->handle = nphdl;
lp->portid = s_id;
lp->port_wwn = ini;
lp->prli_word3 = prli_params;
lp->prli_word3 = (prli_params != 0) ? prli_params : PRLI_WD3_INITIATOR_FUNCTION;
lp->state = FC_PORTDB_STATE_VALID;
fcp->isp_tgt_map[nphdl] = take + 1;
isp_gen_role_str(buf, sizeof (buf), lp->prli_word3);
isp_prt(isp, ISP_LOGTINFO, "Chan %d IID 0x%016llx N-Port Handle 0x%04x"
" Port ID 0x%06x vtgt %d %s added", chan,
(unsigned long long) ini, nphdl, s_id, take, buf);
isp_prt(isp, ISP_LOGTINFO, "Chan %d WWPN 0x%016llx "
"PortID 0x%06x handle 0x%x vtgt %d %s added", chan,
(unsigned long long) ini, s_id, nphdl, i, buf);
/* Notify above levels about new initiator arrival. */
ISP_MEMZERO(&nt, sizeof (nt));
nt.nt_hba = isp;
nt.nt_wwn = ini;
nt.nt_tgt = FCPARAM(isp, chan)->isp_wwpn;
nt.nt_sid = s_id;
nt.nt_did = FCPARAM(isp, chan)->isp_portid;
nt.nt_nphdl = nphdl;
nt.nt_channel = chan;
nt.nt_ncode = NT_ARRIVED;
isp_async(isp, ISPASYNC_TARGET_NOTIFY, &nt);
/* Notify above levels about new port arrival. */
isp_async(isp, ISPASYNC_DEV_ARRIVED, chan, lp);
}
/*
@ -2602,45 +2562,27 @@ void
isp_del_wwn_entry(ispsoftc_t *isp, int chan, uint64_t ini, uint16_t nphdl, uint32_t s_id)
{
fcparam *fcp;
isp_notify_t nt;
fcportdb_t *lp;
if (nphdl >= MAX_NPORT_HANDLE) {
isp_prt(isp, ISP_LOGWARN, "Chan %d IID 0x%016llx bad N-Port handle 0x%04x Port ID 0x%06x",
chan, (unsigned long long) ini, nphdl, s_id);
isp_prt(isp, ISP_LOGWARN, "Chan %d WWPN 0x%016llx PortID 0x%06x bad handle 0x%x",
chan, (unsigned long long) ini, s_id, nphdl);
return;
}
fcp = FCPARAM(isp, chan);
if (fcp->isp_tgt_map[nphdl] == 0) {
lp = NULL;
} else {
lp = &fcp->portdb[fcp->isp_tgt_map[nphdl] - 1];
if (lp->target_mode == 0) {
lp = NULL;
}
}
if (lp == NULL) {
isp_prt(isp, ISP_LOGWARN, "Chan %d IID 0x%016llx N-Port Handle 0x%04x Port ID 0x%06x cannot be found to be deleted",
chan, (unsigned long long) ini, nphdl, s_id);
if (isp_find_pdb_by_handle(isp, chan, nphdl, &lp) == 0) {
isp_prt(isp, ISP_LOGWARN, "Chan %d WWPN 0x%016llx PortID 0x%06x handle 0x%x cannot be found to be deleted",
chan, (unsigned long long) ini, s_id, nphdl);
isp_dump_portdb(isp, chan);
return;
}
isp_prt(isp, ISP_LOGTINFO, "Chan %d IID 0x%016llx N-Port Handle 0x%04x Port ID 0x%06x vtgt %d deleted",
chan, (unsigned long long) lp->port_wwn, nphdl, lp->portid, fcp->isp_tgt_map[nphdl] - 1);
fcp->isp_tgt_map[nphdl] = 0;
lp->state = FC_PORTDB_STATE_DEAD;
isp_prt(isp, ISP_LOGTINFO, "Chan %d WWPN 0x%016llx PortID 0x%06x handle 0x%x vtgt %d deleted",
chan, (unsigned long long) lp->port_wwn, lp->portid, nphdl, FC_PORTDB_TGT(isp, chan, lp));
lp->state = FC_PORTDB_STATE_NIL;
ISP_MEMZERO(&nt, sizeof (nt));
nt.nt_hba = isp;
nt.nt_wwn = lp->port_wwn;
nt.nt_tgt = FCPARAM(isp, chan)->isp_wwpn;
nt.nt_sid = lp->portid;
nt.nt_did = FCPARAM(isp, chan)->isp_portid;
nt.nt_nphdl = nphdl;
nt.nt_channel = chan;
nt.nt_ncode = NT_DEPARTED;
isp_async(isp, ISPASYNC_TARGET_NOTIFY, &nt);
/* Notify above levels about gone port. */
isp_async(isp, ISPASYNC_DEV_GONE, chan, lp);
}
void
@ -2671,11 +2613,11 @@ isp_del_all_wwn_entries(ispsoftc_t *isp, int chan)
if (fcp == NULL) {
return;
}
for (i = 0; i < MAX_NPORT_HANDLE; i++) {
if (fcp->isp_tgt_map[i]) {
fcportdb_t *lp = &fcp->portdb[fcp->isp_tgt_map[i] - 1];
for (i = 0; i < MAX_FC_TARG; i++) {
fcportdb_t *lp = &fcp->portdb[i];
if (lp->state != FC_PORTDB_STATE_NIL)
isp_del_wwn_entry(isp, chan, lp->port_wwn, lp->handle, lp->portid);
}
}
}
@ -2702,7 +2644,7 @@ isp_del_wwn_entries(ispsoftc_t *isp, isp_notify_t *mp)
* We need to find the actual entry so we can delete it.
*/
if (mp->nt_nphdl != NIL_HANDLE) {
if (isp_find_pdb_by_loopid(isp, mp->nt_channel, mp->nt_nphdl, &lp)) {
if (isp_find_pdb_by_handle(isp, mp->nt_channel, mp->nt_nphdl, &lp)) {
isp_del_wwn_entry(isp, mp->nt_channel, lp->port_wwn, lp->handle, lp->portid);
return;
}
@ -2719,8 +2661,8 @@ isp_del_wwn_entries(ispsoftc_t *isp, isp_notify_t *mp)
return;
}
}
isp_prt(isp, ISP_LOGWARN, "Chan %d unable to find entry to delete N-port handle 0x%04x initiator WWN 0x%016llx Port ID 0x%06x",
mp->nt_channel, mp->nt_nphdl, (unsigned long long) mp->nt_wwn, mp->nt_sid);
isp_prt(isp, ISP_LOGWARN, "Chan %d unable to find entry to delete WWPN 0x%016jx PortID 0x%06x handle 0x%x",
mp->nt_channel, mp->nt_wwn, mp->nt_sid, mp->nt_nphdl);
}
void

View File

@ -165,9 +165,10 @@ int isp_allocate_xs_tgt(ispsoftc_t *, void *, uint32_t *);
void *isp_find_xs_tgt(ispsoftc_t *, uint32_t);
uint32_t isp_find_tgt_handle(ispsoftc_t *, void *);
void isp_destroy_tgt_handle(ispsoftc_t *, uint32_t);
#endif
int isp_find_pdb_by_wwn(ispsoftc_t *, int, uint64_t, fcportdb_t **);
int isp_find_pdb_by_loopid(ispsoftc_t *, int, uint32_t, fcportdb_t **);
#ifdef ISP_TARGET_MODE
int isp_find_pdb_by_handle(ispsoftc_t *, int, uint32_t, fcportdb_t **);
int isp_find_pdb_by_sid(ispsoftc_t *, int, uint32_t, fcportdb_t **);
void isp_find_chan_by_did(ispsoftc_t *, uint32_t, uint16_t *);
void isp_add_wwn_entry(ispsoftc_t *, int, uint64_t, uint16_t, uint32_t, uint16_t);

View File

@ -51,8 +51,6 @@ typedef enum {
NT_LOGOUT,
NT_GLOBAL_LOGOUT,
NT_CHANGED,
NT_ARRIVED,
NT_DEPARTED,
NT_HBA_RESET
} isp_ncode_t;

View File

@ -376,9 +376,6 @@ typedef struct {
* duples.
*
* + There can never be two non-NIL entries with the same handle.
*
* + There can never be two non-NIL entries which have the same dev_map_idx
* value.
*/
typedef struct {
/*
@ -389,8 +386,6 @@ typedef struct {
uint16_t handle;
/*
* The dev_map_idx, if nonzero, is the system virtual target ID (+1)
*
* A device is 'autologin' if the firmware automatically logs into
* it (re-logins as needed). Basically, local private loop devices.
*
@ -398,27 +393,24 @@ typedef struct {
*
* The state is the current state of this entry.
*
* The is_target is the current state of target on this port.
*
* The is_initiator is the current state of initiator on this port.
*
* Portid is obvious, as are node && port WWNs. The new_role and
* new_portid is for when we are pending a change.
*
* The 'target_mode' tag means that this entry arrived via a
* target mode command and is immune from normal flushing rules.
* You should also never see anything with an initiator role
* with this set.
*/
uint16_t prli_word3; /* PRLI parameters */
uint16_t new_prli_word3; /* Incoming new PRLI parameters */
uint16_t dev_map_idx : 12,
uint16_t : 12,
autologin : 1, /* F/W does PLOGI/PLOGO */
state : 3;
uint32_t : 7,
target_mode : 1,
uint32_t : 6,
is_target : 1,
is_initiator : 1,
portid : 24;
uint32_t
: 5,
reported_gone : 1,
announced : 1,
dirty : 1, /* commands have been run */
: 8,
new_portid : 24;
uint64_t node_wwn;
uint64_t port_wwn;
@ -434,6 +426,8 @@ typedef struct {
#define FC_PORTDB_STATE_ZOMBIE 6
#define FC_PORTDB_STATE_VALID 7
#define FC_PORTDB_TGT(isp, bus, pdb) (int)(lp - FCPARAM(isp, bus)->portdb)
/*
* FC card specific information
*
@ -485,18 +479,6 @@ typedef struct {
*/
fcportdb_t portdb[MAX_FC_TARG];
#ifdef ISP_TARGET_MODE
/*
* This maps N-Port Handle to portdb entry so we
* don't have to search for every incoming command.
*
* The mapping function is to take any non-zero entry and
* subtract one to get the portdb index. This means that
* entries which are zero are unmapped (i.e., don't exist).
*/
uint16_t isp_tgt_map[MAX_NPORT_HANDLE];
#endif
/*
* Scratch DMA mapped in area to fetch Port Database stuff, etc.
*/
@ -840,7 +822,7 @@ void isp_init(ispsoftc_t *);
/*
* Reset the ISP and call completion for any orphaned commands.
*/
void isp_reinit(ispsoftc_t *, int);
int isp_reinit(ispsoftc_t *, int);
/*
* Internal Interrupt Service Routine