aboutsummaryrefslogtreecommitdiff
path: root/sys/cam/ctl/scsi_ctl.c
diff options
context:
space:
mode:
authorAlexander Motin <mav@FreeBSD.org>2014-11-04 07:44:24 +0000
committerAlexander Motin <mav@FreeBSD.org>2014-11-04 07:44:24 +0000
commit3134cce0ad7a8bcbbdccccb32b4774218a8c4f5f (patch)
tree09285f3e12ff9d05aebc897bbaec093c675529d6 /sys/cam/ctl/scsi_ctl.c
parent068ebf32749921b35beda31c860e2e084da2f7d2 (diff)
downloadsrc-3134cce0ad7a8bcbbdccccb32b4774218a8c4f5f.tar.gz
src-3134cce0ad7a8bcbbdccccb32b4774218a8c4f5f.zip
Improve error handling around duplicate lun and port enable.
This fixes kernel panic if port enabled twice and then disabled. MFC after: 1 week
Notes
Notes: svn path=/head/; revision=274080
Diffstat (limited to 'sys/cam/ctl/scsi_ctl.c')
-rw-r--r--sys/cam/ctl/scsi_ctl.c41
1 files changed, 30 insertions, 11 deletions
diff --git a/sys/cam/ctl/scsi_ctl.c b/sys/cam/ctl/scsi_ctl.c
index fbd20a353909..934ad75be849 100644
--- a/sys/cam/ctl/scsi_ctl.c
+++ b/sys/cam/ctl/scsi_ctl.c
@@ -1796,6 +1796,7 @@ ctlfe_online(void *arg)
struct cam_path *path;
cam_status status;
struct ctlfe_lun_softc *lun_softc;
+ struct cam_periph *periph;
bus_softc = (struct ctlfe_softc *)arg;
@@ -1821,13 +1822,17 @@ ctlfe_online(void *arg)
}
xpt_path_lock(path);
+ periph = cam_periph_find(path, "ctl");
+ if (periph != NULL) {
+ /* We've already got a periph, no need to alloc a new one. */
+ xpt_path_unlock(path);
+ xpt_free_path(path);
+ free(lun_softc, M_CTLFE);
+ return;
+ }
lun_softc->parent_softc = bus_softc;
lun_softc->flags |= CTLFE_LUN_WILDCARD;
- mtx_lock(&bus_softc->lun_softc_mtx);
- STAILQ_INSERT_TAIL(&bus_softc->lun_softc_list, lun_softc, links);
- mtx_unlock(&bus_softc->lun_softc_mtx);
-
status = cam_periph_alloc(ctlferegister,
ctlfeoninvalidate,
ctlfecleanup,
@@ -1843,14 +1848,17 @@ ctlfe_online(void *arg)
const struct cam_status_entry *entry;
entry = cam_fetch_status_entry(status);
-
printf("%s: CAM error %s (%#x) returned from "
"cam_periph_alloc()\n", __func__, (entry != NULL) ?
entry->status_text : "Unknown", status);
+ free(lun_softc, M_CTLFE);
+ } else {
+ mtx_lock(&bus_softc->lun_softc_mtx);
+ STAILQ_INSERT_TAIL(&bus_softc->lun_softc_list, lun_softc, links);
+ mtx_unlock(&bus_softc->lun_softc_mtx);
+ ctlfe_onoffline(arg, /*online*/ 1);
}
- ctlfe_onoffline(arg, /*online*/ 1);
-
xpt_path_unlock(path);
xpt_free_path(path);
}
@@ -1924,11 +1932,7 @@ ctlfe_lun_enable(void *arg, struct ctl_id targ_id, int lun_id)
free(softc, M_CTLFE);
return (0);
}
-
softc->parent_softc = bus_softc;
- mtx_lock(&bus_softc->lun_softc_mtx);
- STAILQ_INSERT_TAIL(&bus_softc->lun_softc_list, softc, links);
- mtx_unlock(&bus_softc->lun_softc_mtx);
status = cam_periph_alloc(ctlferegister,
ctlfeoninvalidate,
@@ -1941,6 +1945,21 @@ ctlfe_lun_enable(void *arg, struct ctl_id targ_id, int lun_id)
0,
softc);
+ if ((status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
+ const struct cam_status_entry *entry;
+
+ entry = cam_fetch_status_entry(status);
+ printf("%s: CAM error %s (%#x) returned from "
+ "cam_periph_alloc()\n", __func__, (entry != NULL) ?
+ entry->status_text : "Unknown", status);
+ free(softc, M_CTLFE);
+ } else {
+ mtx_lock(&bus_softc->lun_softc_mtx);
+ STAILQ_INSERT_TAIL(&bus_softc->lun_softc_list, softc, links);
+ mtx_unlock(&bus_softc->lun_softc_mtx);
+ ctlfe_onoffline(arg, /*online*/ 1);
+ }
+
xpt_path_unlock(path);
xpt_free_path(path);
return (0);