diff options
author | Alexander Motin <mav@FreeBSD.org> | 2014-11-04 07:44:24 +0000 |
---|---|---|
committer | Alexander Motin <mav@FreeBSD.org> | 2014-11-04 07:44:24 +0000 |
commit | 3134cce0ad7a8bcbbdccccb32b4774218a8c4f5f (patch) | |
tree | 09285f3e12ff9d05aebc897bbaec093c675529d6 /sys/cam/ctl/scsi_ctl.c | |
parent | 068ebf32749921b35beda31c860e2e084da2f7d2 (diff) | |
download | src-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.c | 41 |
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); |