Mercurial > illumos > illumos-gate
changeset 6724:fe773658dad4
6706799 vsw need to try cleaning up shares at reboot or panic time
author | raghuram |
---|---|
date | Tue, 27 May 2008 14:00:36 -0700 |
parents | 95f33d4e0a04 |
children | 82d79b4b96a6 |
files | usr/src/uts/sun4v/io/vsw_hio.c usr/src/uts/sun4v/io/vsw_ldc.c usr/src/uts/sun4v/sys/vsw.h |
diffstat | 3 files changed, 142 insertions(+), 22 deletions(-) [+] |
line wrap: on
line diff
--- a/usr/src/uts/sun4v/io/vsw_hio.c Tue May 27 13:52:26 2008 -0700 +++ b/usr/src/uts/sun4v/io/vsw_hio.c Tue May 27 14:00:36 2008 -0700 @@ -84,7 +84,7 @@ extern int vsw_send_msg(vsw_ldc_t *, void *, int, boolean_t); extern int vsw_set_hw(vsw_t *, vsw_port_t *, int); extern int vsw_unset_hw(vsw_t *, vsw_port_t *, int); -extern void vsw_hio_port_reset(vsw_port_t *portp); +extern void vsw_hio_port_reset(vsw_port_t *portp, boolean_t immediate); /* Functions exported to other files */ void vsw_hio_init(vsw_t *vswp); @@ -96,6 +96,7 @@ void vsw_hio_stop_port(vsw_port_t *portp); /* Support functions */ +static void vsw_hio_free_all_shares(vsw_t *vswp, boolean_t reboot); static vsw_share_t *vsw_hio_alloc_share(vsw_t *vswp, vsw_ldc_t *ldcp); static void vsw_hio_free_share(vsw_share_t *vsharep); static vsw_share_t *vsw_hio_find_free_share(vsw_t *vswp); @@ -107,6 +108,8 @@ static int vsw_hio_send_delshare_msg(vsw_share_t *vsharep); static int vsw_hio_bind_macaddr(vsw_share_t *vsharep); static void vsw_hio_unbind_macaddr(vsw_share_t *vsharep); +static boolean_t vsw_hio_reboot_callb(void *arg, int code); +static boolean_t vsw_hio_panic_callb(void *arg, int code); /* @@ -152,6 +155,17 @@ hiop->vh_shares[i].vs_vswp = vswp; } vswp->hio_capable = B_TRUE; + + /* + * Register to get reboot and panic events so that + * we can cleanup HybridIO resources gracefully. + */ + vswp->hio_reboot_cb_id = callb_add(vsw_hio_reboot_callb, + (void *)vswp, CB_CL_MDBOOT, "vsw_hio"); + + vswp->hio_panic_cb_id = callb_add(vsw_hio_panic_callb, + (void *)vswp, CB_CL_PANIC, "vsw_hio"); + D2(vswp, "%s: %s is HybridIO capable num_shares=%d\n", __func__, vswp->physname, hiop->vh_num_shares); D1(vswp, "%s:exit\n", __func__); @@ -379,7 +393,29 @@ /* - * vsw_hio_cleanup -- A rountine to free all shares gracefully. + * vsw_hio_cleanup -- Cleanup the HybridIO. It unregisters the callbs + * and frees all shares. + */ +void +vsw_hio_cleanup(vsw_t *vswp) +{ + D1(vswp, "%s:enter\n", __func__); + + /* Unregister reboot and panic callbs. */ + if (vswp->hio_reboot_cb_id) { + (void) callb_delete(vswp->hio_reboot_cb_id); + vswp->hio_reboot_cb_id = 0; + } + if (vswp->hio_panic_cb_id) { + (void) callb_delete(vswp->hio_panic_cb_id); + vswp->hio_panic_cb_id = 0; + } + vsw_hio_free_all_shares(vswp, B_FALSE); + D1(vswp, "%s:exit\n", __func__); +} + +/* + * vsw_hio_free_all_shares -- A routine to free all shares gracefully. * The following are the steps followed to accomplish this: * * - First clear 'hio_capable' to avoid further share allocations. @@ -392,8 +428,8 @@ * to be freed. Give a little delay for the LDC reset code to * free the Share. */ -void -vsw_hio_cleanup(vsw_t *vswp) +static void +vsw_hio_free_all_shares(vsw_t *vswp, boolean_t reboot) { vsw_hio_t *hiop = &vswp->vhio; vsw_port_list_t *plist = &vswp->plist; @@ -443,15 +479,20 @@ * to force the release of Hybrid * resources. */ - vsw_hio_port_reset(vsharep->vs_portp); + vsw_hio_port_reset(vsharep->vs_portp, + B_FALSE); } } if (max_retries == 1) { - /* Last retry, reset the port */ + /* + * Last retry, reset the port. + * If it is reboot case, issue an immediate + * reset. + */ DWARN(vswp, "%s:All retries failed, " " cause a reset to trigger cleanup for " "share(%d)", __func__, vsharep->vs_index); - vsw_hio_port_reset(vsharep->vs_portp); + vsw_hio_port_reset(vsharep->vs_portp, reboot); } } if (free_shares == hiop->vh_num_shares) { @@ -472,10 +513,11 @@ } while ((free_shares < hiop->vh_num_shares) && (max_retries > 0)); /* By now, all shares should be freed */ - ASSERT(free_shares == hiop->vh_num_shares); if (free_shares != hiop->vh_num_shares) { - cmn_err(CE_NOTE, "vsw%d: All physical resources " - "could not be freed", vswp->instance); + if (reboot == B_FALSE) { + cmn_err(CE_NOTE, "vsw%d: All physical resources " + "could not be freed", vswp->instance); + } } kmem_free(hiop->vh_shares, sizeof (vsw_share_t) * hiop->vh_num_shares); @@ -518,7 +560,7 @@ if (reset == B_TRUE) { /* Cause a rest to trigger HybridIO setup */ - vsw_hio_port_reset(portp); + vsw_hio_port_reset(portp, B_FALSE); } } RW_EXIT(&plist->lockrw); @@ -568,6 +610,7 @@ mutex_exit(&vswp->hw_lock); return; } + vsharep->vs_state &= ~VSW_SHARE_DDS_ACKD; vsharep->vs_state |= VSW_SHARE_DDS_SENT; mutex_exit(&vswp->hw_lock); @@ -637,8 +680,13 @@ req_id = VSW_DDS_NEXT_REQID(vsharep); rv = vsw_send_dds_msg(ldcp, DDS_VNET_DEL_SHARE, cookie, macaddr, req_id); + RW_EXIT(&ldcl->lockrw); mutex_enter(&vswp->hw_lock); + if (rv == 0) { + vsharep->vs_state &= ~VSW_SHARE_DDS_ACKD; + vsharep->vs_state |= VSW_SHARE_DDS_SENT; + } return (rv); } @@ -727,21 +775,22 @@ /* A response for DEL_SHARE message */ D1(vswp, "%s:DDS_VNET_DEL_SHARE\n", __func__); if (!(vsharep->vs_state & VSW_SHARE_DDS_SENT)) { - DWARN(vswp, "%s: invalid ADD_SHARE response message " + DWARN(vswp, "%s: invalid DEL_SHARE response message " " share state=0x%X", __func__, vsharep->vs_state); break; } if (dmsg->dds_req_id != vsharep->vs_req_id) { - DWARN(vswp, "%s: invalid req_id in ADD_SHARE response" + DWARN(vswp, "%s: invalid req_id in DEL_SHARE response" " message share req_id=0x%X share's req_id=0x%X", __func__, dmsg->dds_req_id, vsharep->vs_req_id); break; } if (dmsg->tag.vio_subtype == VIO_SUBTYPE_NACK) { - DWARN(vswp, "%s: NACK received for ADD_SHARE", + DWARN(vswp, "%s: NACK received for DEL_SHARE", __func__); } + /* There is nothing we can do, free share now */ vsw_hio_free_share(vsharep); break; @@ -802,13 +851,13 @@ } else { portp->p_hio_enabled = B_TRUE; /* reset the port to initiate HybridIO setup */ - vsw_hio_port_reset(portp); + vsw_hio_port_reset(portp, B_FALSE); } } /* * vsw_hio_stop_port -- Stop HybridIO for a given port. Sequence - * followed is similar to vsw_hio_cleanup(). + * followed is similar to vsw_hio_free_all_shares(). * */ void @@ -845,7 +894,7 @@ * Cause a port reset to trigger * cleanup. */ - vsw_hio_port_reset(vsharep->vs_portp); + vsw_hio_port_reset(vsharep->vs_portp, B_FALSE); } } if (max_retries == 1) { @@ -853,7 +902,7 @@ DWARN(vswp, "%s:All retries failed, " " cause a reset to trigger cleanup for " "share(%d)", __func__, vsharep->vs_index); - vsw_hio_port_reset(vsharep->vs_portp); + vsw_hio_port_reset(vsharep->vs_portp, B_FALSE); } /* Check if the share still assigned to this port */ @@ -882,3 +931,67 @@ mutex_exit(&vswp->hw_lock); D1(vswp, "%s:exit\n", __func__); } + +/* + * vsw_hio_rest_all -- Resets all ports that have shares allocated. + * It is called only in the panic code path, so the LDC channels + * are reset immediately. + */ +static void +vsw_hio_reset_all(vsw_t *vswp) +{ + vsw_hio_t *hiop = &vswp->vhio; + vsw_share_t *vsharep; + int i; + + D1(vswp, "%s:enter\n", __func__); + + if (vswp->hio_capable != B_TRUE) + return; + + for (i = 0; i < hiop->vh_num_shares; i++) { + vsharep = &hiop->vh_shares[i]; + if (vsharep->vs_state == VSW_SHARE_FREE) { + continue; + } + /* + * Reset the port with immediate flag enabled, + * to cause LDC reset immediately. + */ + vsw_hio_port_reset(vsharep->vs_portp, B_TRUE); + } + D1(vswp, "%s:exit\n", __func__); +} + +/* + * vsw_hio_reboot_callb -- Called for reboot event. It tries to + * free all currently allocated shares. + */ +/* ARGSUSED */ +static boolean_t +vsw_hio_reboot_callb(void *arg, int code) +{ + vsw_t *vswp = arg; + + D1(vswp, "%s:enter\n", __func__); + vsw_hio_free_all_shares(vswp, B_TRUE); + D1(vswp, "%s:exit\n", __func__); + return (B_TRUE); +} + +/* + * vsw_hio_panic_callb -- Called from panic event. It resets all + * the ports that have shares allocated. This is done to + * trigger the cleanup in the guest ahead of HV reset. + */ +/* ARGSUSED */ +static boolean_t +vsw_hio_panic_callb(void *arg, int code) +{ + vsw_t *vswp = arg; + + D1(vswp, "%s:enter\n", __func__); + vsw_hio_reset_all(vswp); + D1(vswp, "%s:exit\n", __func__); + return (B_TRUE); +}
--- a/usr/src/uts/sun4v/io/vsw_ldc.c Tue May 27 13:52:26 2008 -0700 +++ b/usr/src/uts/sun4v/io/vsw_ldc.c Tue May 27 14:00:36 2008 -0700 @@ -95,7 +95,7 @@ vsw_port_t *vsw_lookup_port(vsw_t *vswp, int p_instance); void vsw_vlan_unaware_port_reset(vsw_port_t *portp); int vsw_send_msg(vsw_ldc_t *, void *, int, boolean_t); -void vsw_hio_port_reset(vsw_port_t *portp); +void vsw_hio_port_reset(vsw_port_t *portp, boolean_t immediate); /* Interrupt routines */ static uint_t vsw_ldc_cb(uint64_t cb, caddr_t arg); @@ -1232,7 +1232,7 @@ } void -vsw_hio_port_reset(vsw_port_t *portp) +vsw_hio_port_reset(vsw_port_t *portp, boolean_t immediate) { vsw_ldc_list_t *ldclp; vsw_ldc_t *ldcp; @@ -1259,7 +1259,11 @@ */ if ((ldcp->hphase == VSW_MILESTONE4) && (portp->p_hio_capable == B_TRUE)) { - vsw_process_conn_evt(ldcp, VSW_CONN_RESTART); + if (immediate == B_TRUE) { + (void) ldc_down(ldcp->ldc_handle); + } else { + vsw_process_conn_evt(ldcp, VSW_CONN_RESTART); + } } mutex_exit(&ldcp->ldc_cblock); @@ -1583,7 +1587,7 @@ if ((evt == VSW_CONN_RESTART) && (curr_status == LDC_UP)) (void) ldc_down(ldcp->ldc_handle); - if ((vswp->hio_capable) && (portp->p_hio_enabled)) { + if ((portp->p_hio_capable) && (portp->p_hio_enabled)) { vsw_hio_stop(vswp, ldcp); }
--- a/usr/src/uts/sun4v/sys/vsw.h Tue May 27 13:52:26 2008 -0700 +++ b/usr/src/uts/sun4v/sys/vsw.h Tue May 27 14:00:36 2008 -0700 @@ -46,6 +46,7 @@ #include <sys/vgen_stats.h> #include <sys/vsw_ldc.h> #include <sys/vsw_hio.h> +#include <sys/callb.h> #define DRV_NAME "vsw" @@ -222,6 +223,8 @@ /* HybridIO related fields */ boolean_t hio_capable; /* Phys dev HIO capable */ vsw_hio_t vhio; /* HybridIO info */ + callb_id_t hio_reboot_cb_id; /* Reboot callb ID */ + callb_id_t hio_panic_cb_id; /* Panic callb ID */ } vsw_t; /*