Mercurial > illumos > illumos-gate
changeset 10042:c022bae2f0d3
6853590 Reboot stops at ok prompt when domain services cannot be initialized
6855530 Failure to store boot command can lead to unexpected reboot behavior
author | Mike Christensen <Michael.Christensen@Sun.COM> |
---|---|
date | Mon, 06 Jul 2009 17:03:56 -0700 |
parents | b0f22b3cef0c |
children | 397682150a87 |
files | usr/src/uts/sun4v/io/ds_common.c |
diffstat | 1 files changed, 115 insertions(+), 86 deletions(-) [+] |
line wrap: on
line diff
--- a/usr/src/uts/sun4v/io/ds_common.c Mon Jul 06 16:54:01 2009 -0700 +++ b/usr/src/uts/sun4v/io/ds_common.c Mon Jul 06 17:03:56 2009 -0700 @@ -168,6 +168,8 @@ /* service utilities */ static void ds_reset_svc(ds_svc_t *svc, ds_port_t *port); static int ds_svc_register_onport(ds_svc_t *svc, ds_port_t *port); +static int ds_svc_register_onport_walker(ds_svc_t *svc, void *arg); +static void ds_set_port_ready(ds_port_t *port, uint16_t major, uint16_t minor); /* port utilities */ static void ds_port_reset(ds_port_t *port); @@ -195,7 +197,6 @@ static ds_svc_t *ds_find_svc_by_id_port(char *svc_id, int is_client, ds_port_t *port); static ds_svc_t *ds_svc_clone(ds_svc_t *svc); -static void ds_portset_del_active_clients(char *service, ds_portset_t *portsp); static void ds_check_for_dup_services(ds_svc_t *svc); static void ds_delete_svc_entry(ds_svc_t *svc); @@ -691,6 +692,8 @@ __func__, msglen); DS_DUMP_MSG(DS_DBG_FLAG_LDC, msg, msglen); + (void) ds_log_add_msg(DS_LOG_OUT(port->id), (uint8_t *)msg, msglen); + /* * Ensure that no other messages can be sent on this port by holding * the tx_lock mutex in case the write doesn't get sent with one write. @@ -714,9 +717,10 @@ (loopcnt++ < ds_retries)) { drv_usecwait(ds_delay); } else { - cmn_err(CE_WARN, "ds@%lx: send_msg: ldc_write " - "failed (%d), %d bytes remaining" DS_EOL, - PORTID(port), rv, (int)amt_left); + DS_DBG_PRCL(CE_NOTE, "ds@%lx: send_msg: " + "ldc_write failed (%d), %d bytes " + "remaining" DS_EOL, PORTID(port), rv, + (int)amt_left); goto error; } } else { @@ -805,6 +809,10 @@ */ (void) ds_send_msg(port, msg, msglen); DS_FREE(msg, msglen); + + if (match) { + ds_set_port_ready(port, req->major_vers, ack->minor_vers); + } } static void @@ -812,6 +820,8 @@ { ds_init_ack_t *ack; ds_ver_t *ver; + uint16_t major; + uint16_t minor; size_t explen = DS_MSG_LEN(ds_init_ack_t); /* sanity check the incoming message */ @@ -826,6 +836,13 @@ mutex_enter(&port->lock); + if (port->state == DS_PORT_READY) { + DS_DBG_PRCL(CE_NOTE, "ds@%lx: <init_ack: port ready" DS_EOL, + PORTID(port)); + mutex_exit(&port->lock); + return; + } + if (port->state != DS_PORT_INIT_REQ) { DS_DBG_PRCL(CE_NOTE, "ds@%lx: <init_ack: invalid state: %d" DS_EOL, PORTID(port), port->state); @@ -834,49 +851,14 @@ } ver = &(ds_vers[port->ver_idx]); - - /* agreed upon a major version */ - port->ver.major = ver->major; - - /* - * If the returned minor version is larger than - * the requested minor version, use the lower of - * the two, i.e. the requested version. - */ - if (ack->minor_vers >= ver->minor) { - /* - * Use the minor version specified in the - * original request. - */ - port->ver.minor = ver->minor; - } else { - /* - * Use the lower minor version returned in - * the ack. By definition, all lower minor - * versions must be supported. - */ - port->ver.minor = ack->minor_vers; - } - - port->state = DS_PORT_READY; + major = ver->major; + minor = MIN(ver->minor, ack->minor_vers); + mutex_exit(&port->lock); DS_DBG_PRCL(CE_NOTE, "ds@%lx: <init_ack: port ready v%d.%d" DS_EOL, - PORTID(port), port->ver.major, port->ver.minor); - - mutex_exit(&port->lock); - - /* - * The port came up, so update all the services - * with this information. Follow that up with an - * attempt to register any service that is not - * already registered. - */ - mutex_enter(&ds_svcs.lock); - - (void) ds_walk_svcs(ds_svc_port_up, port); - (void) ds_walk_svcs(ds_svc_register, NULL); - - mutex_exit(&ds_svcs.lock); + PORTID(port), major, minor); + + ds_set_port_ready(port, major, minor); } static void @@ -1270,11 +1252,10 @@ /* * Get the ports that haven't been tried yet and are available to try. */ - DS_PORTSET_SETNULL(totry); + DS_PORTSET_DUP(totry, svc->avail); for (i = 0; i < DS_MAX_PORTS; i++) { - if (!DS_PORT_IN_SET(svc->tried, i) && - DS_PORT_IN_SET(svc->avail, i)) - DS_PORTSET_ADD(totry, i); + if (DS_PORT_IN_SET(svc->tried, i)) + DS_PORTSET_DEL(totry, i); } if (DS_PORTSET_ISNULL(totry)) @@ -1351,8 +1332,9 @@ /* make sure the message makes sense */ if (svc->state != DS_SVC_REG_PENDING) { - cmn_err(CE_WARN, "ds@%lx: <reg_nack: invalid state (%d)" DS_EOL, - PORTID(port), svc->state); + DS_DBG_PRCL(CE_NOTE, "ds@%lx: <reg_nack: '%s' handle: 0x%llx " + "invalid state (%d)" DS_EOL, PORTID(port), svc->cap.svc_id, + (u_longlong_t)nack->svc_handle, svc->state); goto done; } @@ -1447,7 +1429,7 @@ mutex_exit(&port->lock); if (!is_up) return; - cmn_err(CE_WARN, "ds@%lx: <unreg_req: invalid handle 0x%llx" + DS_DBG_PRCL(CE_NOTE, "ds@%lx: <unreg_req: invalid handle 0x%llx" DS_EOL, PORTID(port), (u_longlong_t)req->svc_handle); ds_send_unreg_nack(port, req->svc_handle); return; @@ -2103,6 +2085,23 @@ return (0); } +static void +ds_set_svc_port_tried(char *svc_id, ds_port_t *port) +{ + int idx; + ds_svc_t *svc; + + ASSERT(MUTEX_HELD(&ds_svcs.lock)); + + /* walk every table entry */ + for (idx = 0; idx < ds_svcs.maxsvcs; idx++) { + svc = ds_svcs.tbl[idx]; + if (!DS_SVC_ISFREE(svc) && (svc->flags & DSSF_ISCLIENT) != 0 && + strcmp(svc_id, svc->cap.svc_id) == 0) + DS_PORTSET_ADD(svc->tried, PORTID(port)); + } +} + static int ds_svc_register_onport(ds_svc_t *svc, ds_port_t *port) { @@ -2114,7 +2113,23 @@ if (!DS_PORT_IN_SET(svc->avail, PORTID(port))) return (0); - DS_PORTSET_ADD(svc->tried, PORTID(port)); + if (DS_PORT_IN_SET(svc->tried, PORTID(port))) + return (0); + + if ((svc->flags & DSSF_ISCLIENT) == 0) { + DS_PORTSET_ADD(svc->tried, PORTID(port)); + if (svc->state != DS_SVC_INACTIVE) + return (0); + } else { + ds_set_svc_port_tried(svc->cap.svc_id, port); + + /* + * Never send a client reg req to the SP. + */ + if (PORTID(port) == ds_sp_port_id) { + return (0); + } + } if (ds_send_reg_req(svc, port) == 0) { /* register sent successfully */ @@ -2128,6 +2143,18 @@ return (0); } +static int +ds_svc_register_onport_walker(ds_svc_t *svc, void *arg) +{ + ASSERT(MUTEX_HELD(&ds_svcs.lock)); + + if (DS_SVC_ISFREE(svc)) + return (0); + + (void) ds_svc_register_onport(svc, arg); + return (0); +} + int ds_svc_register(ds_svc_t *svc, void *arg) { @@ -2143,7 +2170,10 @@ DS_PORTSET_DUP(ports, svc->avail); if (svc->flags & DSSF_ISCLIENT) { - ds_portset_del_active_clients(svc->cap.svc_id, &ports); + for (idx = 0; idx < DS_MAX_PORTS; idx++) { + if (DS_PORT_IN_SET(svc->tried, idx)) + DS_PORTSET_DEL(ports, idx); + } } else if (svc->state != DS_SVC_INACTIVE) return (0); @@ -2169,7 +2199,6 @@ if (ds_svc_register_onport(svc, port)) { if ((svc->flags & DSSF_ISCLIENT) == 0) break; - DS_PORTSET_DEL(svc->avail, idx); } } @@ -2242,6 +2271,37 @@ return (0); } +static void +ds_set_port_ready(ds_port_t *port, uint16_t major, uint16_t minor) +{ + boolean_t was_ready; + + mutex_enter(&port->lock); + was_ready = (port->state == DS_PORT_READY); + if (!was_ready) { + port->state = DS_PORT_READY; + port->ver.major = major; + port->ver.minor = minor; + } + mutex_exit(&port->lock); + + if (!was_ready) { + + /* + * The port came up, so update all the services + * with this information. Follow that up with an + * attempt to register any service that is not + * already registered. + */ + mutex_enter(&ds_svcs.lock); + + (void) ds_walk_svcs(ds_svc_port_up, port); + (void) ds_walk_svcs(ds_svc_register_onport_walker, port); + + mutex_exit(&ds_svcs.lock); + } +} + ds_svc_t * ds_alloc_svc(void) { @@ -3175,37 +3235,6 @@ return (0); } -static void -ds_portset_del_active_clients(char *service, ds_portset_t *portsp) -{ - ds_portset_t ports; - int idx; - ds_svc_t *svc; - - ASSERT(MUTEX_HELD(&ds_svcs.lock)); - - DS_PORTSET_DUP(ports, *portsp); - for (idx = 0; idx < ds_svcs.maxsvcs; idx++) { - svc = ds_svcs.tbl[idx]; - if (DS_SVC_ISFREE(svc)) - continue; - if (strcmp(svc->cap.svc_id, service) == 0 && - (svc->flags & DSSF_ISCLIENT) != 0 && - svc->state != DS_SVC_INACTIVE && - svc->port != NULL) { - DS_PORTSET_DEL(ports, PORTID(svc->port)); - } - } - - /* - * Never send a client reg req to the SP. - */ - if (ds_sp_port_id != DS_PORTID_INVALID) { - DS_PORTSET_DEL(ports, ds_sp_port_id); - } - DS_PORTSET_DUP(*portsp, ports); -} - /* * After an UNREG REQ, check if this is a client service with multiple * handles. If it is, then we can eliminate this entry.