Author: mjacob
Date: Sat Sep 19 20:25:54 2009
New Revision: 197332
URL: http://svn.freebsd.org/changeset/base/197332

Log:
  Remember to unlock the peripheral prior to notifying the user. Make some
  allocations M_NOWAIT so that we don't try and sleep with a nested 
non-sleepable
  lock.
  
  This makes the userland scsi_target begin to function again.
  
  Obtained from:        Sean Bruno
  MFC after:    1 month

Modified:
  head/sys/cam/scsi/scsi_target.c

Modified: head/sys/cam/scsi/scsi_target.c
==============================================================================
--- head/sys/cam/scsi/scsi_target.c     Sat Sep 19 18:01:32 2009        
(r197331)
+++ head/sys/cam/scsi/scsi_target.c     Sat Sep 19 20:25:54 2009        
(r197332)
@@ -42,6 +42,9 @@ __FBSDID("$FreeBSD$");
 #include <sys/mutex.h>
 #include <sys/devicestat.h>
 #include <sys/proc.h>
+/* Includes to support callout */
+#include <sys/types.h>
+#include <sys/systm.h>
 
 #include <cam/cam.h>
 #include <cam/cam_ccb.h>
@@ -50,6 +53,7 @@ __FBSDID("$FreeBSD$");
 #include <cam/cam_sim.h>
 #include <cam/scsi/scsi_targetio.h>
 
+
 /* Transaction information attached to each CCB sent by the user */
 struct targ_cmd_descr {
        struct cam_periph_map_info  mapinfo;
@@ -92,6 +96,8 @@ struct targ_softc {
        targ_state               state;
        struct selinfo           read_select;
        struct devstat           device_stats;
+       struct callout          destroy_dev_callout;
+       struct mtx              destroy_mtx;
 };
 
 static d_open_t                targopen;
@@ -154,6 +160,7 @@ static void         abort_all_pending(struct ta
 static void            notify_user(struct targ_softc *softc);
 static int             targcamstatus(cam_status status);
 static size_t          targccblen(xpt_opcode func_code);
+static void            targdestroy(void *);
 
 static struct periph_driver targdriver =
 {
@@ -211,10 +218,18 @@ targclose(struct cdev *dev, int flag, in
        int    error;
 
        softc = (struct targ_softc *)dev->si_drv1;
-       if ((softc->periph == NULL) ||
-           (softc->state & TARG_STATE_LUN_ENABLED) == 0) {
+       mtx_init(&softc->destroy_mtx, "targ_destroy", "SCSI Target dev 
destroy", MTX_DEF);
+       callout_init_mtx(&softc->destroy_dev_callout, &softc->destroy_mtx, 
CALLOUT_RETURNUNLOCKED);
+       if (softc->periph == NULL) {
+#if 0
                destroy_dev(dev);
                free(softc, M_TARG);
+#endif
+               printf("%s: destroying non-enabled target\n", __func__);
+               mtx_lock(&softc->destroy_mtx);
+                       callout_reset(&softc->destroy_dev_callout, hz / 2,
+                        (void *)targdestroy, (void *)dev);
+               mtx_unlock(&softc->destroy_mtx);
                return (0);
        }
 
@@ -226,18 +241,23 @@ targclose(struct cdev *dev, int flag, in
        cam_periph_acquire(periph);
        cam_periph_lock(periph);
        error = targdisable(softc);
-       if (error == CAM_REQ_CMP) {
-               dev->si_drv1 = 0;
-               if (softc->periph != NULL) {
-                       cam_periph_invalidate(softc->periph);
-                       softc->periph = NULL;
-               }
-               destroy_dev(dev);
-               free(softc, M_TARG);
+       if (softc->periph != NULL) {
+               cam_periph_invalidate(softc->periph);
+               softc->periph = NULL;
        }
        cam_periph_unlock(periph);
        cam_periph_release(periph);
 
+#if 0
+       destroy_dev(dev);
+       free(softc, M_TARG);
+#endif
+
+       printf("%s: close finished error(%d)\n", __func__, error);
+       mtx_lock(&softc->destroy_mtx);
+       callout_reset(&softc->destroy_dev_callout, hz / 2,
+               (void *)targdestroy, (void *)dev);
+       mtx_unlock(&softc->destroy_mtx);
        return (error);
 }
 
@@ -821,7 +841,9 @@ targdone(struct cam_periph *periph, unio
        case XPT_CONT_TARGET_IO:
                TAILQ_INSERT_TAIL(&softc->user_ccb_queue, &done_ccb->ccb_h,
                                  periph_links.tqe);
+               cam_periph_unlock(softc->periph);
                notify_user(softc);
+               cam_periph_lock(softc->periph);
                break;
        default:
                panic("targdone: impossible xpt opcode %#x",
@@ -969,13 +991,19 @@ targgetccb(struct targ_softc *softc, xpt
        int ccb_len;
 
        ccb_len = targccblen(type);
-       ccb = malloc(ccb_len, M_TARG, M_WAITOK);
+       ccb = malloc(ccb_len, M_TARG, M_NOWAIT);
        CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, ("getccb %p\n", ccb));
-
+       if (ccb == NULL) {
+               return (ccb);
+       }
        xpt_setup_ccb(&ccb->ccb_h, softc->path, priority);
        ccb->ccb_h.func_code = type;
        ccb->ccb_h.cbfcnp = targdone;
        ccb->ccb_h.targ_descr = targgetdescr(softc);
+       if (ccb->ccb_h.targ_descr == NULL) {
+               free (ccb, M_TARG);
+               ccb = NULL;
+       }
        return (ccb);
 }
 
@@ -1013,8 +1041,10 @@ targgetdescr(struct targ_softc *softc)
        struct targ_cmd_descr *descr;
 
        descr = malloc(sizeof(*descr), M_TARG,
-              M_WAITOK);
-       descr->mapinfo.num_bufs_used = 0;
+              M_NOWAIT);
+       if (descr) {
+               descr->mapinfo.num_bufs_used = 0;
+       }
        return (descr);
 }
 
@@ -1094,8 +1124,11 @@ abort_all_pending(struct targ_softc *sof
 
        /* If we aborted anything from the work queue, wakeup user. */
        if (!TAILQ_EMPTY(&softc->user_ccb_queue)
-        || !TAILQ_EMPTY(&softc->abort_queue))
+        || !TAILQ_EMPTY(&softc->abort_queue)) {
+               cam_periph_unlock(softc->periph);
                notify_user(softc);
+               cam_periph_lock(softc->periph);
+       }
 }
 
 /* Notify the user that data is ready */
@@ -1188,3 +1221,25 @@ targccblen(xpt_opcode func_code)
 
        return (len);
 }
+
+/*
+ * work around to destroy targ device
+ * outside of targclose
+ */
+static void
+targdestroy(void *dev)
+{
+       struct cdev *device = (struct cdev *)dev;
+       struct targ_softc *softc = (struct targ_softc *)device->si_drv1;
+
+#if 0
+       callout_stop(&softc->destroy_dev_callout);
+#endif
+
+       mtx_unlock(&softc->destroy_mtx);
+       mtx_destroy(&softc->destroy_mtx);
+       free(softc, M_TARG);
+       device->si_drv1 = 0;
+       destroy_dev(device);
+       printf("%s: destroyed dev\n", __func__);
+}
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to