From owner-p4-projects@FreeBSD.ORG Sun Nov 12 18:57:18 2006 Return-Path: X-Original-To: p4-projects@freebsd.org Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id DAE3F16A47B; Sun, 12 Nov 2006 18:57:17 +0000 (UTC) X-Original-To: perforce@freebsd.org Delivered-To: perforce@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 9C01316A416 for ; Sun, 12 Nov 2006 18:57:17 +0000 (UTC) (envelope-from mjacob@freebsd.org) Received: from repoman.freebsd.org (repoman.freebsd.org [216.136.204.115]) by mx1.FreeBSD.org (Postfix) with ESMTP id 9ECFA43D6D for ; Sun, 12 Nov 2006 18:57:13 +0000 (GMT) (envelope-from mjacob@freebsd.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.13.6/8.13.6) with ESMTP id kACIvDvI064913 for ; Sun, 12 Nov 2006 18:57:13 GMT (envelope-from mjacob@freebsd.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.13.6/8.13.4/Submit) id kACIvDpx064910 for perforce@freebsd.org; Sun, 12 Nov 2006 18:57:13 GMT (envelope-from mjacob@freebsd.org) Date: Sun, 12 Nov 2006 18:57:13 GMT Message-Id: <200611121857.kACIvDpx064910@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to mjacob@freebsd.org using -f From: Matt Jacob To: Perforce Change Reviews Cc: Subject: PERFORCE change 109812 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 12 Nov 2006 18:57:18 -0000 http://perforce.freebsd.org/chv.cgi?CH=109812 Change 109812 by mjacob@newisp on 2006/11/12 18:56:32 Macroize isp_mark_portdb so we can print out debugging aboutg where we invalidate the portdb. Add more SANCFG printouts. Add a ZOMBIE state to portdb entries- this is exempt from being marked by isp_mark_portdb. When we arrive in isp_pdb_sync and announce to the outer layers that a device is 'gone', it has the option of setting the portdb entry as being 'ZOMBIE' and setting a timer that will be used to clear the entry entirely or handle it arriving again before the timeout. For FreeBSD, implement both a loop down and a gone device timer. Add a isp_mstohz function. Affected files ... .. //depot/projects/newisp/dev/isp/isp.c#29 edit .. //depot/projects/newisp/dev/isp/isp_freebsd.c#23 edit .. //depot/projects/newisp/dev/isp/isp_freebsd.h#16 edit Differences ... ==== //depot/projects/newisp/dev/isp/isp.c#29 (text+ko) ==== @@ -60,6 +60,9 @@ */ #define MBOX_DELAY_COUNT 1000000 / 100 +#define ISP_MARK_PORTDB(a, b) \ + isp_prt(isp, ISP_LOGSANCFG, "line %d: markportdb", __LINE__); \ + isp_mark_portdb(a, b) /* * Local static data @@ -116,7 +119,7 @@ static int isp_getpdb(ispsoftc_t *, uint16_t, isp_pdb_t *, int); static uint64_t isp_get_portname(ispsoftc_t *, int, int); static int isp_fclink_test(ispsoftc_t *, int); -static const char *isp2100_fw_statename(int); +static const char *ispfc_fw_statename(int); static int isp_pdb_sync(ispsoftc_t *); static int isp_scan_loop(ispsoftc_t *); static int isp_gid_ft_sns(ispsoftc_t *); @@ -1172,7 +1175,7 @@ /* * Do this *before* initializing the firmware. */ - isp_mark_portdb(isp, 0); + ISP_MARK_PORTDB(isp, 0); FCPARAM(isp)->isp_fwstate = FW_CONFIG_WAIT; FCPARAM(isp)->isp_loopstate = LOOP_NIL; @@ -2053,7 +2056,6 @@ int i; for (i = 0; i < MAX_FC_TARG; i++) { - fcp->isp_ini_map[i] = 0; if (onprobation == 0) { MEMZERO(&fcp->portdb[i], sizeof (fcportdb_t)); } else { @@ -2065,6 +2067,8 @@ fcp->portdb[i].state = FC_PORTDB_STATE_PROBATIONAL; break; + case FC_PORTDB_STATE_ZOMBIE: + break; case FC_PORTDB_STATE_NIL: default: MEMZERO(&fcp->portdb[i], sizeof (fcportdb_t)); @@ -2415,8 +2419,8 @@ fcp = isp->isp_param; - isp_prt(isp, ISP_LOGDEBUG0, "FC Link Test Entry"); - isp_mark_portdb(isp, 1); + isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "FC Link Test Entry"); + ISP_MARK_PORTDB(isp, 1); /* * Wait up to N microseconds for F/W to go to a ready state. @@ -2431,9 +2435,10 @@ GET_NANOTIME(&hra); isp_fw_state(isp); if (lwfs != fcp->isp_fwstate) { - isp_prt(isp, ISP_LOGINFO, "Firmware State <%s->%s>", - isp2100_fw_statename((int)lwfs), - isp2100_fw_statename((int)fcp->isp_fwstate)); + isp_prt(isp, ISP_LOGCONFIG|ISP_LOGSANCFG, + "Firmware State <%s->%s>", + ispfc_fw_statename((int)lwfs), + ispfc_fw_statename((int)fcp->isp_fwstate)); lwfs = fcp->isp_fwstate; } if (fcp->isp_fwstate == FW_READY) { @@ -2485,7 +2490,7 @@ * If we haven't gone to 'ready' state, return. */ if (fcp->isp_fwstate != FW_READY) { - isp_prt(isp, ISP_LOGDEBUG0, + isp_prt(isp, ISP_LOGSANCFG, "isp_fclink_test: not at FW_READY state"); return (-1); } @@ -2597,19 +2602,19 @@ /* * Announce ourselves, too. */ - isp_prt(isp, ISP_LOGCONFIG, topology, fcp->isp_portid, + isp_prt(isp, ISP_LOGSANCFG|ISP_LOGCONFIG, topology, fcp->isp_portid, fcp->isp_loopid, toponames[fcp->isp_topo]); - isp_prt(isp, ISP_LOGCONFIG, ourwwn, + isp_prt(isp, ISP_LOGSANCFG|ISP_LOGCONFIG, ourwwn, (uint32_t) (ISP_NODEWWN(isp) >> 32), (uint32_t) ISP_NODEWWN(isp), (uint32_t) (ISP_PORTWWN(isp) >> 32), (uint32_t) ISP_PORTWWN(isp)); - isp_prt(isp, ISP_LOGDEBUG0, "FC Link Test Complete"); + isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "FC Link Test Complete"); return (0); } static const char * -isp2100_fw_statename(int state) +ispfc_fw_statename(int state) { switch(state) { case FW_CONFIG_WAIT: return "Config Wait"; @@ -2688,6 +2693,8 @@ } } + isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "Synchronizing PDBs"); + fcp->isp_loopstate = LOOP_SYNCING_PDB; for (dbidx = 0; dbidx < MAX_FC_TARG; dbidx++) { @@ -2712,8 +2719,8 @@ /* * It's up to the outer layers to clear isp_ini_map. */ + lp->state = FC_PORTDB_STATE_NIL; isp_async(isp, ISPASYNC_DEV_GONE, lp); - lp->state = FC_PORTDB_STATE_NIL; if (lp->autologin == 0) { if (IS_24XX(isp)) { int action = @@ -2733,38 +2740,35 @@ } lp->new_roles = 0; lp->new_portid = 0; + /* + * Note that we might come out of this with our state + * set to FC_PORTDB_STATE_ZOMBIE. + */ break; case FC_PORTDB_STATE_NEW: /* - * If *we* have a new target dole and *it* has a target - * role, assign a new target id to it. + * It's up to the outer layers to assign a virtual + * target id in isp_ini_map (if any). */ lp->portid = lp->new_portid; lp->roles = lp->new_roles; - /* - * It's up to the outer layers to assign a virtual - * target id in isp_ini_map (if any). - */ + lp->state = FC_PORTDB_STATE_VALID; isp_async(isp, ISPASYNC_DEV_ARRIVED, lp); - lp->state = FC_PORTDB_STATE_VALID; lp->new_roles = 0; lp->new_portid = 0; + lp->reserved = 0; + lp->new_reserved = 0; break; case FC_PORTDB_STATE_CHANGED: - /* - * For now, just have a policy of accepting 'changed' - * devices. - */ - lp->portid = lp->new_portid; - lp->roles = lp->new_roles; - if (lp->ini_map_idx) { - int t = lp->ini_map_idx - 1; - fcp->isp_ini_map[t] = dbidx + 1; - } +/* + * XXXX FIX THIS + */ + lp->state = FC_PORTDB_STATE_VALID; isp_async(isp, ISPASYNC_DEV_CHANGED, lp); - lp->state = FC_PORTDB_STATE_VALID; lp->new_roles = 0; lp->new_portid = 0; + lp->reserved = 0; + lp->new_reserved = 0; break; case FC_PORTDB_STATE_PENDING_VALID: lp->portid = lp->new_portid; @@ -2773,15 +2777,20 @@ int t = lp->ini_map_idx - 1; fcp->isp_ini_map[t] = dbidx + 1; } + lp->state = FC_PORTDB_STATE_VALID; isp_async(isp, ISPASYNC_DEV_STAYED, lp); - lp->state = FC_PORTDB_STATE_VALID; if (dbidx != FL_ID) { lp->new_roles = 0; lp->new_portid = 0; } + lp->reserved = 0; + lp->new_reserved = 0; + break; + case FC_PORTDB_STATE_ZOMBIE: break; default: - isp_prt(isp, ISP_LOGERR, "eh? state %d for idx %d", + isp_prt(isp, ISP_LOGWARN, + "isp_scan_loop: state %d for idx %d", lp->state, dbidx); isp_dump_portdb(isp); } @@ -2807,7 +2816,7 @@ fcparam *fcp = isp->isp_param; int i; isp_pdb_t pdb; - uint16_t dbidx, lim = 0; + uint16_t handle, lim = 0; if (fcp->isp_fwstate < FW_READY || fcp->isp_loopstate < LOOP_PDB_RCVD) { @@ -2844,17 +2853,18 @@ } fcp->isp_loopstate = LOOP_SCANNING_LOOP; - isp_prt(isp, ISP_LOGDEBUG0, "scanning loop 0..%d", lim-1); + + isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "FC scan loop 0..%d", lim-1); /* * Run through the list and get the port database info for each one. */ - for (dbidx = 0; dbidx < lim; dbidx++) { + for (handle = 0; handle < lim; handle++) { /* * But don't even try for ourselves... */ - if (dbidx == fcp->isp_loopid) { + if (handle == fcp->isp_loopid) { continue; } @@ -2863,7 +2873,7 @@ * known to hang. This trick gets around that problem. */ if (IS_2100(isp) || IS_2200(isp)) { - uint64_t node_wwn = isp_get_portname(isp, dbidx, 1); + uint64_t node_wwn = isp_get_portname(isp, handle, 1); if (fcp->isp_loopstate < LOOP_SCANNING_LOOP) { return (-1); } @@ -2875,29 +2885,29 @@ /* * Get the port database entity for this index. */ - if (isp_getpdb(isp, dbidx, &pdb, 1) != 0) { + if (isp_getpdb(isp, handle, &pdb, 1) != 0) { if (fcp->isp_loopstate < LOOP_SCANNING_LOOP) { - isp_mark_portdb(isp, 1); + ISP_MARK_PORTDB(isp, 1); return (-1); } continue; } if (fcp->isp_loopstate < LOOP_SCANNING_LOOP) { - isp_mark_portdb(isp, 1); + ISP_MARK_PORTDB(isp, 1); return (-1); } /* * On *very* old 2100 firmware we would end up sometimes * with the firmware returning the port database entry - * for something else. We used to restart locally, but - * now we punt. + * for something else. We used to restart this, but + * now we just punt. */ - if (IS_2100(isp) && pdb.handle != dbidx) { + if (IS_2100(isp) && pdb.handle != handle) { isp_prt(isp, ISP_LOGWARN, "giving up on synchronizing the port database"); - isp_mark_portdb(isp, 1); + ISP_MARK_PORTDB(isp, 1); return (-1); } @@ -2916,8 +2926,7 @@ * which shift on a loop. */ if (tmp.node_wwn == 0 || tmp.port_wwn == 0 || tmp.portid == 0) { - isp_prt(isp, ISP_LOGWARN, - "bad pdb entry at loop %d", dbidx); + isp_prt(isp, ISP_LOGWARN, "bad pdb @ loop %d", handle); isp_dump_portdb(isp); continue; } @@ -2940,22 +2949,27 @@ /* * Okay- we've found a non-nil entry that matches. - * Check to make sure it's probational. + * Check to make sure it's probational or a zombie. */ - if (lp->state != FC_PORTDB_STATE_PROBATIONAL) { + if (lp->state != FC_PORTDB_STATE_PROBATIONAL && + lp->state != FC_PORTDB_STATE_ZOMBIE) { isp_prt(isp, ISP_LOGERR, - "portdb entry %d not probational (0x%x)", + "[%d] not probational/zombie (0x%x)", i, lp->state); isp_dump_portdb(isp); - isp_mark_portdb(isp, 1); + ISP_MARK_PORTDB(isp, 1); return (-1); } + /* + * Mark the device as something the f/w logs into + * automatically. + */ lp->autologin = 1; + /* - * Check to make sure it's really the same - * device and update the initiator map before - * we mark it as pending valid. + * Check to make see if really still the same + * device. If it is, we mark it pending valid. */ if (lp->portid == tmp.portid && lp->handle == tmp.handle && @@ -2963,12 +2977,15 @@ lp->new_portid = tmp.portid; lp->new_roles = tmp.roles; lp->state = FC_PORTDB_STATE_PENDING_VALID; + isp_prt(isp, ISP_LOGSANCFG, + "Loop Port 0x%06x@0x%x Pending Valid", + tmp.portid, tmp.handle); break; } /* - * We can wipe out the old handle value here because - * it's no longer valid. + * We can wipe out the old handle value + * here because it's no longer valid. */ lp->handle = tmp.handle; @@ -2976,6 +2993,9 @@ * Claim that this has changed and let somebody else * decide what to do. */ + isp_prt(isp, ISP_LOGSANCFG, + "Loop Port 0x%06x@0x%x changed", + tmp.portid, tmp.handle); lp->state = FC_PORTDB_STATE_CHANGED; lp->new_portid = tmp.portid; lp->new_roles = tmp.roles; @@ -2999,23 +3019,23 @@ } } if (i == MAX_FC_TARG) { - isp_prt(isp, ISP_LOGERR, - "could not find slot for new entry"); + isp_prt(isp, ISP_LOGERR, "out of portdb entries"); continue; } lp = &fcp->portdb[i]; + MEMZERO(lp, sizeof (fcportdb_t)); lp->autologin = 1; lp->state = FC_PORTDB_STATE_NEW; - lp->portid = 0; - lp->roles = 0; lp->new_portid = tmp.portid; lp->new_roles = tmp.roles; lp->handle = tmp.handle; lp->port_wwn = tmp.port_wwn; lp->node_wwn = tmp.node_wwn; + isp_prt(isp, ISP_LOGSANCFG, + "Loop Port 0x%06x@0x%x is New Entry", + tmp.portid, tmp.handle); } - fcp->isp_loopstate = LOOP_LSCAN_DONE; return (0); } @@ -3196,7 +3216,7 @@ int portidx, portlim, r; sns_gid_ft_rsp_t *rs0, *rs1; - isp_prt(isp, ISP_LOGDEBUG0, "FC Scan Fabric"); + isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "FC Scan Fabric"); if (fcp->isp_fwstate != FW_READY || fcp->isp_loopstate < LOOP_LSCAN_DONE) { return (-1); @@ -3206,7 +3226,8 @@ } if (fcp->isp_topo != TOPO_FL_PORT && fcp->isp_topo != TOPO_F_PORT) { fcp->isp_loopstate = LOOP_FSCAN_DONE; - isp_prt(isp, ISP_LOGDEBUG0, "FC Scan Fabric Done (no fabric)"); + isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, + "FC Scan Fabric Done (no fabric)"); return (0); } @@ -3241,7 +3262,7 @@ int level; if (rs1->snscb_cthdr.ct_reason == 9 && rs1->snscb_cthdr.ct_explanation == 7) { - level = ISP_LOGDEBUG0; + level = ISP_LOGSANCFG|ISP_LOGDEBUG0; } else { level = ISP_LOGWARN; } @@ -3286,8 +3307,8 @@ "fabric too big for scratch area: increase ISP2100_SCRLEN"); } portlim = portidx + 1; - isp_prt(isp, ISP_LOGDEBUG0, "got %d ports back from name server", - portlim); + isp_prt(isp, ISP_LOGSANCFG, + "got %d ports back from name server", portlim); for (portidx = 0; portidx < portlim; portidx++) { int npidx; @@ -3311,7 +3332,7 @@ rs1->snscb_ports[npidx].portid[0] = 0; rs1->snscb_ports[npidx].portid[1] = 0; rs1->snscb_ports[npidx].portid[2] = 0; - isp_prt(isp, ISP_LOGDEBUG0, + isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "removing duplicate PortID 0x%x entry from list", portid); } @@ -3344,7 +3365,7 @@ ((rs1->snscb_ports[portidx].portid[2])); if (portid == 0) { - isp_prt(isp, ISP_LOGDEBUG0, + isp_prt(isp, ISP_LOGSANCFG, "skipping null PortID at idx %d", portidx); continue; } @@ -3353,15 +3374,18 @@ * Skip ourselves... */ if (portid == fcp->isp_portid) { - isp_prt(isp, ISP_LOGDEBUG0, + isp_prt(isp, ISP_LOGSANCFG, "skip ourselves @ PortID 0x%06x", portid); continue; } - isp_prt(isp, ISP_LOGDEBUG0, "Fabric Port 0x%06x", portid); + isp_prt(isp, ISP_LOGSANCFG, + "Checking Fabric Port 0x%06x", portid); /* * We now search our Port Database for any - * probational entries with this PortID. + * probational entries with this PortID. We don't + * look for zombies here- only probational + * entries (we've already logged out of zombies). */ for (dbidx = 0; dbidx < MAX_FC_TARG; dbidx++) { lp = &fcp->portdb[dbidx]; @@ -3402,12 +3426,15 @@ r = isp_getpdb(isp, lp->handle, &pdb, 0); if (fcp->isp_loopstate != LOOP_SCANNING_FABRIC) { FC_SCRATCH_RELEASE(isp); - isp_mark_portdb(isp, 1); + ISP_MARK_PORTDB(isp, 1); return (-1); } if (r != 0) { lp->new_portid = portid; lp->state = FC_PORTDB_STATE_DEAD; + isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, + "Fabric Port 0x%06x considered dead", + portid); continue; } @@ -3424,8 +3451,8 @@ pdb.portid != portid || wwpn != lp->port_wwn || wwnn != lp->node_wwn) { - isp_prt(isp, ISP_LOGDEBUG0, fconf, dbidx, - pdb.handle, pdb.portid, + isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, + fconf, dbidx, pdb.handle, pdb.portid, (uint32_t) (wwnn >> 32), (uint32_t) wwnn, (uint32_t) (wwpn >> 32), (uint32_t) wwpn, lp->handle, portid, @@ -3448,7 +3475,7 @@ if (fcp->isp_loopstate != LOOP_SCANNING_FABRIC) { FC_SCRATCH_RELEASE(isp); - isp_mark_portdb(isp, 1); + ISP_MARK_PORTDB(isp, 1); return (-1); } continue; @@ -3486,8 +3513,13 @@ lp->new_roles = nr; if (pdb.portid != lp->portid || nr != lp->roles || handle_changed) { + isp_prt(isp, ISP_LOGSANCFG, + "Fabric Port 0x%06x changed", portid); lp->state = FC_PORTDB_STATE_CHANGED; } else { + isp_prt(isp, ISP_LOGSANCFG, + "Fabric Port 0x%06x Now Pending Valid", + portid); lp->state = FC_PORTDB_STATE_PENDING_VALID; } continue; @@ -3495,49 +3527,54 @@ /* * Ah- a new entry. Search the database again for all non-NIL - * entries to make sure we never ever make a database entry - * with the same port id. + * entries to make sure we never ever make a new database entry + * with the same port id. While we're at it, mark where the + * last free entry was. */ - for (dbidx = 0; dbidx < MAX_FC_TARG; dbidx++) { - if (dbidx >= FL_ID && dbidx <= SNS_ID) { + + dbidx = MAX_FC_TARG; + for (lp = fcp->portdb; lp < &fcp->portdb[MAX_FC_TARG]; lp++) { + if (lp >= &fcp->portdb[FL_ID] && + lp <= &fcp->portdb[SNS_ID]) { + continue; + } + if (lp->state == FC_PORTDB_STATE_NIL) { + if (dbidx == MAX_FC_TARG) { + dbidx = lp - fcp->portdb; + } continue; } - if (fcp->portdb[dbidx].state == FC_PORTDB_STATE_NIL) { + if (lp->state == FC_PORTDB_STATE_ZOMBIE) { continue; } - if (fcp->portdb[dbidx].portid == portid) { + if (lp->portid == portid) { break; } } - if (dbidx != MAX_FC_TARG) { + if (lp < &fcp->portdb[MAX_FC_TARG]) { isp_prt(isp, ISP_LOGWARN, "PortID 0x%06x already at %d handle %d state %d", - portid, dbidx, fcp->portdb[dbidx].handle, - fcp->portdb[dbidx].state); + portid, dbidx, lp->handle, lp->state); continue; } /* - * Find an empty database entry for it. + * We should have the index of the first free entry seen. */ - for (dbidx = 0; dbidx < MAX_FC_TARG; dbidx++) { - if (dbidx >= FL_ID && dbidx <= SNS_ID) { - continue; - } - if (fcp->portdb[dbidx].state == FC_PORTDB_STATE_NIL) { - break; - } - } - if (dbidx == MAX_FC_TARG) { isp_prt(isp, ISP_LOGERR, - "port database too small to login fabric device" - "- increase MAX_FC_TARG"); + "port database too small to login PortID 0x%06x" + "- increase MAX_FC_TARG", portid); continue; } /* + * Otherwise, point to our new home. + */ + lp = &fcp->portdb[dbidx]; + + /* * Try to see if we are logged into this device, * and maybe log into it. * @@ -3547,7 +3584,7 @@ if (isp_login_device(isp, portid, &pdb, &oldhandle)) { if (fcp->isp_loopstate != LOOP_SCANNING_FABRIC) { FC_SCRATCH_RELEASE(isp); - isp_mark_portdb(isp, 1); + ISP_MARK_PORTDB(isp, 1); return (-1); } continue; @@ -3563,13 +3600,11 @@ * that we do not make more than one entry that has the same * WWNN/WWPN duple */ - lp = &fcp->portdb[dbidx]; - for (dbidx = 0; dbidx < MAX_FC_TARG; dbidx++) { - if (fcp->portdb[dbidx].state == FC_PORTDB_STATE_NIL) { + if (dbidx >= FL_ID && dbidx <= SNS_ID) { continue; } - if (dbidx >= FL_ID && dbidx <= SNS_ID) { + if (fcp->portdb[dbidx].state == FC_PORTDB_STATE_NIL) { continue; } if (fcp->portdb[dbidx].node_wwn == wwnn && @@ -3578,33 +3613,61 @@ } } - if (dbidx != MAX_FC_TARG) { + if (dbidx == MAX_FC_TARG) { + MEMZERO(lp, sizeof (fcportdb_t)); + lp->handle = handle; + lp->node_wwn = wwnn; + lp->port_wwn = wwpn; + lp->new_portid = portid; + lp->new_roles = nr; + lp->state = FC_PORTDB_STATE_NEW; + isp_prt(isp, ISP_LOGSANCFG, + "Fabric Port 0x%06x is New Entry", portid); + continue; + } + + if (fcp->portdb[dbidx].state != FC_PORTDB_STATE_ZOMBIE) { isp_prt(isp, ISP_LOGWARN, "PortID 0x%x 0x%08x%08x/0x%08x%08x %ld already at " - "idx %d", portid, + "idx %d, state 0x%x", portid, (uint32_t) (wwnn >> 32), (uint32_t) wwnn, (uint32_t) (wwpn >> 32), (uint32_t) wwpn, - (long) (lp - fcp->portdb), dbidx); + (long) (lp - fcp->portdb), dbidx, + fcp->portdb[dbidx].state); continue; } + /* + * We found a zombie entry that matches us. + * Revive it. We know that WWN and WWPN + * are the same. For fabric devices, we + * don't care that handle is different + * as we assign that. If role or portid + * are different, it maybe a changed device. + */ + lp = &fcp->portdb[dbidx]; lp->handle = handle; - lp->ini_map_idx = 0; - lp->node_wwn = wwnn; - lp->port_wwn = wwpn; lp->new_portid = portid; lp->new_roles = nr; - lp->state = FC_PORTDB_STATE_NEW; + if (lp->portid != portid || lp->roles != nr) { + isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, + "Zombie Fabric Port 0x%06x Now Changed", portid); + lp->state = FC_PORTDB_STATE_CHANGED; + } else { + isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, + "Zombie Fabric Port 0x%06x Now Pending Valid", + portid); + lp->state = FC_PORTDB_STATE_PENDING_VALID; + } } - FC_SCRATCH_RELEASE(isp); if (fcp->isp_loopstate != LOOP_SCANNING_FABRIC) { - isp_mark_portdb(isp, 1); + ISP_MARK_PORTDB(isp, 1); return (-1); } fcp->isp_loopstate = LOOP_FSCAN_DONE; - isp_prt(isp, ISP_LOGDEBUG0, "FC Scan Fabric Done"); + isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "FC Scan Fabric Done"); return (0); } @@ -3674,7 +3737,7 @@ } if (i == lim) { - isp_prt(isp, ISP_LOGINFO, "PLOGI 0x%06x failed", portid); + isp_prt(isp, ISP_LOGWARN, "PLOGI 0x%06x failed", portid); return (-1); } @@ -3832,14 +3895,16 @@ FC_SCRATCH_RELEASE(isp); if (ct->ct_cmd_resp == LS_RJT) { - isp_prt(isp, ISP_LOGWARN, "Register FC4 Type rejected"); + isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, + "Register FC4 Type rejected"); return (-1); } else if (ct->ct_cmd_resp == LS_ACC) { - isp_prt(isp, ISP_LOGDEBUG0, "Register FC4 Type accepted"); + isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, + "Register FC4 Type accepted"); return(0); } else { isp_prt(isp, ISP_LOGWARN, - "Register FC4 Type: %x", ct->ct_cmd_resp); + "Register FC4 Type: 0x%x", ct->ct_cmd_resp); return (-1); } } @@ -3934,9 +3999,12 @@ if (IS_FC(isp)) { fcparam *fcp = isp->isp_param; + /* + * Try again later. + */ if (fcp->isp_fwstate != FW_READY || fcp->isp_loopstate != LOOP_READY) { - return (CMD_RQLATER); + return (CMD_EAGAIN); } if (XS_TGT(xs) >= MAX_FC_TARG) { @@ -3951,6 +4019,13 @@ XS_SETERR(xs, HBA_SELTIMEOUT); return (CMD_COMPLETE); } + if (fcp->portdb[hdlidx].state == FC_PORTDB_STATE_ZOMBIE) { + return (CMD_RQLATER); + } + if (fcp->portdb[hdlidx].state != FC_PORTDB_STATE_VALID) { + XS_SETERR(xs, HBA_SELTIMEOUT); + return (CMD_COMPLETE); + } target = fcp->portdb[hdlidx].handle; } @@ -5111,7 +5186,7 @@ FCPARAM(isp)->isp_fwstate = FW_CONFIG_WAIT; FCPARAM(isp)->isp_loopstate = LOOP_LIP_RCVD; isp->isp_sendmarker = 1; - isp_mark_portdb(isp, 1); + ISP_MARK_PORTDB(isp, 1); isp_async(isp, ISPASYNC_LIP, NULL); #ifdef ISP_TARGET_MODE if (isp_target_async(isp, bus, mbox)) { @@ -5147,7 +5222,7 @@ isp->isp_sendmarker = 1; FCPARAM(isp)->isp_fwstate = FW_CONFIG_WAIT; FCPARAM(isp)->isp_loopstate = LOOP_LIP_RCVD; - isp_mark_portdb(isp, 1); + ISP_MARK_PORTDB(isp, 1); isp_async(isp, ISPASYNC_LOOP_UP, NULL); #ifdef ISP_TARGET_MODE if (isp_target_async(isp, bus, mbox)) { @@ -5160,7 +5235,7 @@ isp->isp_sendmarker = 1; FCPARAM(isp)->isp_fwstate = FW_CONFIG_WAIT; FCPARAM(isp)->isp_loopstate = LOOP_NIL; - isp_mark_portdb(isp, 1); + ISP_MARK_PORTDB(isp, 1); isp_async(isp, ISPASYNC_LOOP_DOWN, NULL); #ifdef ISP_TARGET_MODE if (isp_target_async(isp, bus, mbox)) { @@ -5173,7 +5248,7 @@ isp->isp_sendmarker = 1; FCPARAM(isp)->isp_fwstate = FW_CONFIG_WAIT; FCPARAM(isp)->isp_loopstate = LOOP_NIL; - isp_mark_portdb(isp, 1); + ISP_MARK_PORTDB(isp, 1); isp_async(isp, ISPASYNC_LOOP_RESET, NULL); #ifdef ISP_TARGET_MODE if (isp_target_async(isp, bus, mbox)) { @@ -5185,7 +5260,7 @@ case ASYNC_PDB_CHANGED: isp->isp_sendmarker = 1; FCPARAM(isp)->isp_loopstate = LOOP_PDB_RCVD; - isp_mark_portdb(isp, 1); + ISP_MARK_PORTDB(isp, 1); isp_async(isp, ISPASYNC_CHANGE_NOTIFY, ISPASYNC_CHANGE_PDB); break; @@ -5195,12 +5270,12 @@ } else { FCPARAM(isp)->isp_loopstate = LOOP_PDB_RCVD; } - isp_mark_portdb(isp, 1); + ISP_MARK_PORTDB(isp, 1); isp_async(isp, ISPASYNC_CHANGE_NOTIFY, ISPASYNC_CHANGE_SNS); break; case ASYNC_PTPMODE: - isp_mark_portdb(isp, 1); + ISP_MARK_PORTDB(isp, 1); isp->isp_sendmarker = 1; FCPARAM(isp)->isp_fwstate = FW_CONFIG_WAIT; FCPARAM(isp)->isp_loopstate = LOOP_LIP_RCVD; @@ -5215,7 +5290,7 @@ case ASYNC_CONNMODE: mbox = ISP_READ(isp, OUTMAILBOX1); - isp_mark_portdb(isp, 1); + ISP_MARK_PORTDB(isp, 1); switch (mbox) { case ISP_CONN_LOOP: isp_prt(isp, ISP_LOGINFO, @@ -5707,14 +5782,6 @@ mbs.logval = MBLOGALL; isp_mboxcmd_qnw(isp, &mbs, 1); } - - /* - * Probably overkill. - */ - isp->isp_sendmarker = 1; - FCPARAM(isp)->isp_loopstate = LOOP_PDB_RCVD; - isp_mark_portdb(isp, 1); - isp_async(isp, ISPASYNC_CHANGE_NOTIFY, ISPASYNC_CHANGE_OTHER); if (XS_NOERR(xs)) { XS_SETERR(xs, HBA_SELTIMEOUT); } @@ -5865,14 +5932,6 @@ mbs.logval = MBLOGALL; isp_mboxcmd_qnw(isp, &mbs, 1); } - - /* - * Probably overkill. - */ - isp->isp_sendmarker = 1; - FCPARAM(isp)->isp_loopstate = LOOP_PDB_RCVD; - isp_mark_portdb(isp, 1); - isp_async(isp, ISPASYNC_CHANGE_NOTIFY, ISPASYNC_CHANGE_OTHER); if (XS_NOERR(xs)) { XS_SETERR(xs, HBA_SELTIMEOUT); } @@ -7104,7 +7163,7 @@ uint32_t tmp; if (IS_FC(isp)) { - isp_mark_portdb(isp, 0); + ISP_MARK_PORTDB(isp, 0); } isp_reset(isp); if (isp->isp_state != ISP_RESETSTATE) { ==== //depot/projects/newisp/dev/isp/isp_freebsd.c#23 (text+ko) ==== @@ -41,6 +41,7 @@ #if __FreeBSD_version >= 500000 #include #endif +#include MODULE_VERSION(isp, 1); @@ -50,10 +51,12 @@ int isp_loop_down_limit = 300; /* default loop down limit */ int isp_change_is_bad = 0; /* "changed" devices are bad */ int isp_quickboot_time = 5; /* don't wait more than N secs for loop up */ -int isp_lost_device_time = 60; /* grace time before reporting device lost */ +int isp_gone_device_time = 60; /* grace time before reporting device lost */ static const char *roles[4] = { "(none)", "Target", "Initiator", "Target/Initiator" }; +static const char prom3[] = + "PortID 0x%06x Departed from Target %u because of %s"; static d_ioctl_t ispioctl; static void isp_intr_enable(void *); @@ -657,16 +660,20 @@ "wwpn", CTLFLAG_RD, isp->isp_osinfo.sysctl_info.fc.wwpn, 0, "World Wide Port Name"); - SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "loop_down_time", + SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, + "loop_down_time", CTLFLAG_RD, &isp->isp_osinfo.loop_down_time, 0, "How long Loop has been down"); - SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "loop_down_limit", + SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, + "loop_down_limit", CTLFLAG_RW, &isp->isp_osinfo.loop_down_limit, 0, "How long to wait for loop to come back up"); - printf("loop_down %d loop_down_limit %d\n", - isp->isp_osinfo.loop_down_time, isp->isp_osinfo.loop_down_limit); + SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, + "gone_device_time", + CTLFLAG_RW, &isp->isp_osinfo.gone_device_time, 0, + "How long to wait for a device to reappear"); } #endif @@ -2070,7 +2077,9 @@ if (XS_CMD_DONE_P(xs)) { isp_prt(isp, ISP_LOGDEBUG2, "watchdog cleanup for handle 0x%x", handle); + ISPLOCK_2_CAMLOCK(isp); xpt_done((union ccb *) xs); + CAMLOCK_2_ISPLOCK(isp); } else if (XS_CMD_GRACE_P(xs)) { /* * Make sure the command is *really* dead before we @@ -2090,7 +2099,9 @@ "watchdog timeout for handle 0x%x", handle); XS_SETERR(xs, CAM_CMD_TIMEOUT); XS_CMD_C_WDOG(xs); + ISPLOCK_2_CAMLOCK(isp); isp_done(xs); + CAMLOCK_2_ISPLOCK(isp); } else { XS_CMD_C_WDOG(xs); xs->ccb_h.timeout_ch = timeout(isp_watchdog, xs, hz); @@ -2098,20 +2109,103 @@ isp->isp_sendmarker |= 1 << XS_CHANNEL(xs); } } else { - isp_prt(isp, ISP_LOGDEBUG2, "watchdog with no command"); + isp_prt(isp, ISP_LOGWARN, "watchdog with no command"); + } + ISP_UNLOCK(isp); +} + +#if __FreeBSD_version >= 500000 +#define isp_make_here(isp, tgt) isp_announce(isp, tgt, AC_FOUND_DEVICE) +#define isp_make_gone(isp, tgt) isp_announce(isp, tgt, AC_LOST_DEVICE) + +/* + * Support function for Announcement + */ +static void +isp_announce(ispsoftc_t *isp, int tgt, int action) +{ + struct cam_path *tmppath; + ISPLOCK_2_CAMLOCK(isp); + if (xpt_create_path(&tmppath, NULL, cam_sim_path(isp->isp_sim), tgt, + CAM_LUN_WILDCARD) == CAM_REQ_CMP) { + xpt_async(action, tmppath, NULL); + xpt_free_path(tmppath); + } + CAMLOCK_2_ISPLOCK(isp); +} +#else +#define isp_make_here(isp, tgt) do { ; } while (0) +#define isp_make_gone(isp, tgt) do { ; } while (0) +#endif + + +/* + * Gone Device Timer Function- when we have decided that a device has gone + * away, we wait a specific period of time prior to telling the OS it has + * gone away. + * + * This timer function fires once a second and then scans the port database + * for devices that are marked dead but still have a virtual target assigned. + * We decrement a counter for that port database entry, and when it hits zero, + * we tell the OS the device has gone away. + */ +static void +isp_gdt(void *arg) +{ + ispsoftc_t *isp = arg; + fcportdb_t *lp; + int dbidx, tgt, more_to_do = 0; + + isp_prt(isp, ISP_LOGDEBUG0, "GDT timer expired"); + ISP_LOCK(isp); + for (dbidx = 0; dbidx < MAX_FC_TARG; dbidx++) { + lp = &FCPARAM(isp)->portdb[dbidx]; + + if (lp->state != FC_PORTDB_STATE_ZOMBIE) { >>> TRUNCATED FOR MAIL (1000 lines) <<<