Filter out duplicate AC_PATH_REGISTERED async events.

Queued async events handling in CAM opened race, that may lead to duplicate
AC_PATH_REGISTERED events delivery during boot.  That was not happening
before r272935 because the driver was initialized later.  After that change
it started create duplicate ports in CTL.
This commit is contained in:
Alexander Motin 2014-10-11 10:19:37 +00:00
parent bb829be508
commit 7d9cb4d9ab
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=272938

View File

@ -271,11 +271,19 @@ ctlfeperiphinit(void)
static void
ctlfeasync(void *callback_arg, uint32_t code, struct cam_path *path, void *arg)
{
struct ctlfe_softc *softc;
#ifdef CTLFEDEBUG
printf("%s: entered\n", __func__);
#endif
mtx_lock(&ctlfe_list_mtx);
STAILQ_FOREACH(softc, &ctlfe_softc_list, links) {
if (softc->path_id == xpt_path_path_id(path))
break;
}
mtx_unlock(&ctlfe_list_mtx);
/*
* When a new path gets registered, and it is capable of target
* mode, go ahead and attach. Later on, we may need to be more
@ -284,7 +292,6 @@ ctlfeasync(void *callback_arg, uint32_t code, struct cam_path *path, void *arg)
switch (code) {
case AC_PATH_REGISTERED: {
struct ctl_port *port;
struct ctlfe_softc *bus_softc;
struct ccb_pathinq *cpi;
int retval;
@ -299,6 +306,14 @@ ctlfeasync(void *callback_arg, uint32_t code, struct cam_path *path, void *arg)
break;
}
if (softc != NULL) {
#ifdef CTLFEDEBUG
printf("%s: CTL port for CAM path %u already exists\n",
__func__, xpt_path_path_id(path));
#endif
break;
}
#ifdef CTLFE_INIT_ENABLE
if (ctlfe_num_targets >= ctlfe_max_targets) {
union ccb *ccb;
@ -347,25 +362,23 @@ ctlfeasync(void *callback_arg, uint32_t code, struct cam_path *path, void *arg)
* use M_NOWAIT. Of course this means trouble if we
* can't allocate memory.
*/
bus_softc = malloc(sizeof(*bus_softc), M_CTLFE,
M_NOWAIT | M_ZERO);
if (bus_softc == NULL) {
softc = malloc(sizeof(*softc), M_CTLFE, M_NOWAIT | M_ZERO);
if (softc == NULL) {
printf("%s: unable to malloc %zd bytes for softc\n",
__func__, sizeof(*bus_softc));
__func__, sizeof(*softc));
return;
}
bus_softc->path_id = cpi->ccb_h.path_id;
bus_softc->sim = xpt_path_sim(path);
softc->path_id = cpi->ccb_h.path_id;
softc->sim = xpt_path_sim(path);
if (cpi->maxio != 0)
bus_softc->maxio = cpi->maxio;
softc->maxio = cpi->maxio;
else
bus_softc->maxio = DFLTPHYS;
mtx_init(&bus_softc->lun_softc_mtx, "LUN softc mtx", NULL,
MTX_DEF);
STAILQ_INIT(&bus_softc->lun_softc_list);
softc->maxio = DFLTPHYS;
mtx_init(&softc->lun_softc_mtx, "LUN softc mtx", NULL, MTX_DEF);
STAILQ_INIT(&softc->lun_softc_list);
port = &bus_softc->port;
port = &softc->port;
port->frontend = &ctlfe_frontend;
/*
@ -380,21 +393,21 @@ ctlfeasync(void *callback_arg, uint32_t code, struct cam_path *path, void *arg)
/* XXX KDM what should the real number be here? */
port->num_requested_ctl_io = 4096;
snprintf(bus_softc->port_name, sizeof(bus_softc->port_name),
snprintf(softc->port_name, sizeof(softc->port_name),
"%s%d", cpi->dev_name, cpi->unit_number);
/*
* XXX KDM it would be nice to allocate storage in the
* frontend structure itself.
*/
port->port_name = bus_softc->port_name;
port->port_name = softc->port_name;
port->physical_port = cpi->unit_number;
port->virtual_port = cpi->bus_id;
port->port_online = ctlfe_online;
port->port_offline = ctlfe_offline;
port->onoff_arg = bus_softc;
port->onoff_arg = softc;
port->lun_enable = ctlfe_lun_enable;
port->lun_disable = ctlfe_lun_disable;
port->targ_lun_arg = bus_softc;
port->targ_lun_arg = softc;
port->fe_datamove = ctlfe_datamove_done;
port->fe_done = ctlfe_datamove_done;
/*
@ -416,35 +429,28 @@ ctlfeasync(void *callback_arg, uint32_t code, struct cam_path *path, void *arg)
if (retval != 0) {
printf("%s: ctl_port_register() failed with "
"error %d!\n", __func__, retval);
mtx_destroy(&bus_softc->lun_softc_mtx);
free(bus_softc, M_CTLFE);
mtx_destroy(&softc->lun_softc_mtx);
free(softc, M_CTLFE);
break;
} else {
mtx_lock(&ctlfe_list_mtx);
STAILQ_INSERT_TAIL(&ctlfe_softc_list, bus_softc, links);
STAILQ_INSERT_TAIL(&ctlfe_softc_list, softc, links);
mtx_unlock(&ctlfe_list_mtx);
}
break;
}
case AC_PATH_DEREGISTERED: {
struct ctlfe_softc *softc = NULL;
mtx_lock(&ctlfe_list_mtx);
STAILQ_FOREACH(softc, &ctlfe_softc_list, links) {
if (softc->path_id == xpt_path_path_id(path)) {
STAILQ_REMOVE(&ctlfe_softc_list, softc,
ctlfe_softc, links);
break;
}
}
mtx_unlock(&ctlfe_list_mtx);
if (softc != NULL) {
/*
* XXX KDM are we certain at this point that there
* are no outstanding commands for this frontend?
*/
mtx_lock(&ctlfe_list_mtx);
STAILQ_REMOVE(&ctlfe_softc_list, softc, ctlfe_softc,
links);
mtx_unlock(&ctlfe_list_mtx);
ctl_port_deregister(&softc->port);
mtx_destroy(&softc->lun_softc_mtx);
free(softc, M_CTLFE);
@ -459,8 +465,7 @@ ctlfeasync(void *callback_arg, uint32_t code, struct cam_path *path, void *arg)
switch (ac->contract_number) {
case AC_CONTRACT_DEV_CHG: {
struct ac_device_changed *dev_chg;
struct ctlfe_softc *softc;
int retval, found;
int retval;
dev_chg = (struct ac_device_changed *)ac->contract_data;
@ -469,18 +474,7 @@ ctlfeasync(void *callback_arg, uint32_t code, struct cam_path *path, void *arg)
xpt_path_path_id(path), dev_chg->target,
(dev_chg->arrived == 0) ? "left" : "arrived");
found = 0;
mtx_lock(&ctlfe_list_mtx);
STAILQ_FOREACH(softc, &ctlfe_softc_list, links) {
if (softc->path_id == xpt_path_path_id(path)) {
found = 1;
break;
}
}
mtx_unlock(&ctlfe_list_mtx);
if (found == 0) {
if (softc == NULL) {
printf("%s: CTL port for CAM path %u not "
"found!\n", __func__,
xpt_path_path_id(path));