]> CyberLeo.Net >> Repos - FreeBSD/stable/8.git/blob - sys/cam/scsi/scsi_target.c
MFC r236712:
[FreeBSD/stable/8.git] / sys / cam / scsi / scsi_target.c
1 /*-
2  * Generic SCSI Target Kernel Mode Driver
3  *
4  * Copyright (c) 2002 Nate Lawson.
5  * Copyright (c) 1998, 1999, 2001, 2002 Justin T. Gibbs.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions, and the following disclaimer,
13  *    without modification, immediately at the beginning of the file.
14  * 2. The name of the author may not be used to endorse or promote products
15  *    derived from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
21  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32
33
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/kernel.h>
37 #include <sys/conf.h>
38 #include <sys/malloc.h>
39 #include <sys/poll.h>
40 #include <sys/vnode.h>
41 #include <sys/lock.h>
42 #include <sys/mutex.h>
43 #include <sys/devicestat.h>
44 #include <sys/proc.h>
45 /* Includes to support callout */
46 #include <sys/types.h>
47 #include <sys/systm.h>
48
49 #include <cam/cam.h>
50 #include <cam/cam_ccb.h>
51 #include <cam/cam_periph.h>
52 #include <cam/cam_xpt_periph.h>
53 #include <cam/cam_sim.h>
54 #include <cam/scsi/scsi_targetio.h>
55
56
57 /* Transaction information attached to each CCB sent by the user */
58 struct targ_cmd_descr {
59         struct cam_periph_map_info  mapinfo;
60         TAILQ_ENTRY(targ_cmd_descr) tqe;
61         union ccb *user_ccb;
62         int        priority;
63         int        func_code;
64 };
65
66 /* Offset into the private CCB area for storing our descriptor */
67 #define targ_descr      periph_priv.entries[1].ptr
68
69 TAILQ_HEAD(descr_queue, targ_cmd_descr);
70
71 typedef enum {
72         TARG_STATE_RESV         = 0x00, /* Invalid state */
73         TARG_STATE_OPENED       = 0x01, /* Device opened, softc initialized */
74         TARG_STATE_LUN_ENABLED  = 0x02  /* Device enabled for a path */
75 } targ_state;
76
77 /* Per-instance device software context */
78 struct targ_softc {
79         /* CCBs (CTIOs, ATIOs, INOTs) pending on the controller */
80         struct ccb_queue         pending_ccb_queue;
81
82         /* Command descriptors awaiting CTIO resources from the XPT */
83         struct descr_queue       work_queue;
84
85         /* Command descriptors that have been aborted back to the user. */
86         struct descr_queue       abort_queue;
87
88         /*
89          * Queue of CCBs that have been copied out to userland, but our
90          * userland daemon has not yet seen.
91          */
92         struct ccb_queue         user_ccb_queue;
93
94         struct cam_periph       *periph;
95         struct cam_path         *path;
96         targ_state               state;
97         struct selinfo           read_select;
98         struct devstat           device_stats;
99         struct callout          destroy_dev_callout;
100         struct mtx              destroy_mtx;
101 };
102
103 static d_open_t         targopen;
104 static d_close_t        targclose;
105 static d_read_t         targread;
106 static d_write_t        targwrite;
107 static d_ioctl_t        targioctl;
108 static d_poll_t         targpoll;
109 static d_kqfilter_t     targkqfilter;
110 static void             targreadfiltdetach(struct knote *kn);
111 static int              targreadfilt(struct knote *kn, long hint);
112 static struct filterops targread_filtops =
113         { 1, NULL, targreadfiltdetach, targreadfilt };
114
115 static struct cdevsw targ_cdevsw = {
116         .d_version =    D_VERSION,
117         .d_flags =      D_NEEDGIANT,
118         .d_open =       targopen,
119         .d_close =      targclose,
120         .d_read =       targread,
121         .d_write =      targwrite,
122         .d_ioctl =      targioctl,
123         .d_poll =       targpoll,
124         .d_name =       "targ",
125         .d_kqfilter =   targkqfilter
126 };
127
128 static cam_status       targendislun(struct cam_path *path, int enable,
129                                      int grp6_len, int grp7_len);
130 static cam_status       targenable(struct targ_softc *softc,
131                                    struct cam_path *path,
132                                    int grp6_len, int grp7_len);
133 static cam_status       targdisable(struct targ_softc *softc);
134 static periph_ctor_t    targctor;
135 static periph_dtor_t    targdtor;
136 static periph_start_t   targstart;
137 static int              targusermerge(struct targ_softc *softc,
138                                       struct targ_cmd_descr *descr,
139                                       union ccb *ccb);
140 static int              targsendccb(struct targ_softc *softc, union ccb *ccb,
141                                     struct targ_cmd_descr *descr);
142 static void             targdone(struct cam_periph *periph,
143                                  union  ccb *done_ccb);
144 static int              targreturnccb(struct targ_softc *softc,
145                                       union  ccb *ccb);
146 static union ccb *      targgetccb(struct targ_softc *softc, xpt_opcode type,
147                                    int priority);
148 static void             targfreeccb(struct targ_softc *softc, union ccb *ccb);
149 static struct targ_cmd_descr *
150                         targgetdescr(struct targ_softc *softc);
151 static periph_init_t    targinit;
152 static void             targclone(void *arg, struct ucred *cred, char *name,
153                                   int namelen, struct cdev **dev);
154 static void             targasync(void *callback_arg, u_int32_t code,
155                                   struct cam_path *path, void *arg);
156 static void             abort_all_pending(struct targ_softc *softc);
157 static void             notify_user(struct targ_softc *softc);
158 static int              targcamstatus(cam_status status);
159 static size_t           targccblen(xpt_opcode func_code);
160 static void             targdestroy(void *);
161
162 static struct periph_driver targdriver =
163 {
164         targinit, "targ",
165         TAILQ_HEAD_INITIALIZER(targdriver.units), /* generation */ 0
166 };
167 PERIPHDRIVER_DECLARE(targ, targdriver);
168
169 static MALLOC_DEFINE(M_TARG, "TARG", "TARG data");
170
171 /*
172  * Create softc and initialize it. Only one proc can open each targ device.
173  * There is no locking here because a periph doesn't get created until an
174  * ioctl is issued to do so, and that can't happen until this method returns.
175  */
176 static int
177 targopen(struct cdev *dev, int flags, int fmt, struct thread *td)
178 {
179         struct targ_softc *softc;
180
181         if (dev->si_drv1 != 0) {
182                 return (EBUSY);
183         }
184         
185         /* Mark device busy before any potentially blocking operations */
186         dev->si_drv1 = (void *)~0;
187
188         /* Create the targ device, allocate its softc, initialize it */
189         if ((dev->si_flags & SI_NAMED) == 0) {
190                 make_dev(&targ_cdevsw, dev2unit(dev), UID_ROOT, GID_WHEEL, 0600,
191                          "targ%d", dev2unit(dev));
192         }
193         softc = malloc(sizeof(*softc), M_TARG,
194                M_WAITOK | M_ZERO);
195         dev->si_drv1 = softc;
196         softc->state = TARG_STATE_OPENED;
197         softc->periph = NULL;
198         softc->path = NULL;
199
200         TAILQ_INIT(&softc->pending_ccb_queue);
201         TAILQ_INIT(&softc->work_queue);
202         TAILQ_INIT(&softc->abort_queue);
203         TAILQ_INIT(&softc->user_ccb_queue);
204         knlist_init_mtx(&softc->read_select.si_note, NULL);
205
206         return (0);
207 }
208
209 /* Disable LUN if enabled and teardown softc */
210 static int
211 targclose(struct cdev *dev, int flag, int fmt, struct thread *td)
212 {
213         struct targ_softc     *softc;
214         struct cam_periph     *periph;
215         int    error;
216
217         softc = (struct targ_softc *)dev->si_drv1;
218         mtx_init(&softc->destroy_mtx, "targ_destroy", "SCSI Target dev destroy", MTX_DEF);
219         callout_init_mtx(&softc->destroy_dev_callout, &softc->destroy_mtx, CALLOUT_RETURNUNLOCKED);
220         if (softc->periph == NULL) {
221 #if 0
222                 destroy_dev(dev);
223                 free(softc, M_TARG);
224 #endif
225                 printf("%s: destroying non-enabled target\n", __func__);
226                 mtx_lock(&softc->destroy_mtx);
227                 callout_reset(&softc->destroy_dev_callout, hz / 2,
228                         (void *)targdestroy, (void *)dev);
229                 mtx_unlock(&softc->destroy_mtx);
230                 return (0);
231         }
232
233         /*
234          * Acquire a hold on the periph so that it doesn't go away before
235          * we are ready at the end of the function.
236          */
237         periph = softc->periph;
238         cam_periph_acquire(periph);
239         cam_periph_lock(periph);
240         error = targdisable(softc);
241         if (softc->periph != NULL) {
242                 cam_periph_invalidate(softc->periph);
243                 softc->periph = NULL;
244         }
245         cam_periph_unlock(periph);
246         cam_periph_release(periph);
247
248 #if 0
249         destroy_dev(dev);
250         free(softc, M_TARG);
251 #endif
252
253         printf("%s: close finished error(%d)\n", __func__, error);
254         mtx_lock(&softc->destroy_mtx);
255         callout_reset(&softc->destroy_dev_callout, hz / 2,
256                 (void *)targdestroy, (void *)dev);
257         mtx_unlock(&softc->destroy_mtx);
258         return (error);
259 }
260
261 /* Enable/disable LUNs, set debugging level */
262 static int
263 targioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td)
264 {
265         struct targ_softc *softc;
266         cam_status         status;
267
268         softc = (struct targ_softc *)dev->si_drv1;
269
270         switch (cmd) {
271         case TARGIOCENABLE:
272         {
273                 struct ioc_enable_lun   *new_lun;
274                 struct cam_path         *path;
275                 struct cam_sim          *sim;
276
277                 new_lun = (struct ioc_enable_lun *)addr;
278                 status = xpt_create_path_unlocked(&path, /*periph*/NULL,
279                                                   new_lun->path_id,
280                                                   new_lun->target_id,
281                                                   new_lun->lun_id);
282                 if (status != CAM_REQ_CMP) {
283                         printf("Couldn't create path, status %#x\n", status);
284                         break;
285                 }
286                 sim = xpt_path_sim(path);
287                 mtx_lock(sim->mtx);
288                 status = targenable(softc, path, new_lun->grp6_len,
289                                     new_lun->grp7_len);
290                 xpt_free_path(path);
291                 mtx_unlock(sim->mtx);
292                 break;
293         }
294         case TARGIOCDISABLE:
295                 if (softc->periph == NULL) {
296                         status = CAM_DEV_NOT_THERE;
297                         break;
298                 }
299                 cam_periph_lock(softc->periph);
300                 status = targdisable(softc);
301                 cam_periph_unlock(softc->periph);
302                 break;
303         case TARGIOCDEBUG:
304         {
305                 struct ccb_debug cdbg;
306
307                 /* If no periph available, disallow debugging changes */
308                 if ((softc->state & TARG_STATE_LUN_ENABLED) == 0) {
309                         status = CAM_DEV_NOT_THERE;
310                         break;
311                 }
312                 bzero(&cdbg, sizeof cdbg);
313                 if (*((int *)addr) != 0)
314                         cdbg.flags = CAM_DEBUG_PERIPH;
315                 else
316                         cdbg.flags = CAM_DEBUG_NONE;
317                 cam_periph_lock(softc->periph);
318                 xpt_setup_ccb(&cdbg.ccb_h, softc->path, CAM_PRIORITY_NORMAL);
319                 cdbg.ccb_h.func_code = XPT_DEBUG;
320                 cdbg.ccb_h.cbfcnp = targdone;
321
322                 xpt_action((union ccb *)&cdbg);
323                 cam_periph_unlock(softc->periph);
324                 status = cdbg.ccb_h.status & CAM_STATUS_MASK;
325                 break;
326         }
327         default:
328                 status = CAM_PROVIDE_FAIL;
329                 break;
330         }
331
332         return (targcamstatus(status));
333 }
334
335 /* Writes are always ready, reads wait for user_ccb_queue or abort_queue */
336 static int
337 targpoll(struct cdev *dev, int poll_events, struct thread *td)
338 {
339         struct targ_softc *softc;
340         int     revents;
341
342         softc = (struct targ_softc *)dev->si_drv1;
343
344         /* Poll for write() is always ok. */
345         revents = poll_events & (POLLOUT | POLLWRNORM);
346         if ((poll_events & (POLLIN | POLLRDNORM)) != 0) {
347                 /* Poll for read() depends on user and abort queues. */
348                 cam_periph_lock(softc->periph);
349                 if (!TAILQ_EMPTY(&softc->user_ccb_queue) ||
350                     !TAILQ_EMPTY(&softc->abort_queue)) {
351                         revents |= poll_events & (POLLIN | POLLRDNORM);
352                 }
353                 cam_periph_unlock(softc->periph);
354                 /* Only sleep if the user didn't poll for write. */
355                 if (revents == 0)
356                         selrecord(td, &softc->read_select);
357         }
358
359         return (revents);
360 }
361
362 static int
363 targkqfilter(struct cdev *dev, struct knote *kn)
364 {
365         struct  targ_softc *softc;
366
367         softc = (struct targ_softc *)dev->si_drv1;
368         kn->kn_hook = (caddr_t)softc;
369         kn->kn_fop = &targread_filtops;
370         knlist_add(&softc->read_select.si_note, kn, 0);
371         return (0);
372 }
373
374 static void
375 targreadfiltdetach(struct knote *kn)
376 {
377         struct  targ_softc *softc;
378
379         softc = (struct targ_softc *)kn->kn_hook;
380         knlist_remove(&softc->read_select.si_note, kn, 0);
381 }
382
383 /* Notify the user's kqueue when the user queue or abort queue gets a CCB */
384 static int
385 targreadfilt(struct knote *kn, long hint)
386 {
387         struct targ_softc *softc;
388         int     retval;
389
390         softc = (struct targ_softc *)kn->kn_hook;
391         cam_periph_lock(softc->periph);
392         retval = !TAILQ_EMPTY(&softc->user_ccb_queue) ||
393                  !TAILQ_EMPTY(&softc->abort_queue);
394         cam_periph_unlock(softc->periph);
395         return (retval);
396 }
397
398 /* Send the HBA the enable/disable message */
399 static cam_status
400 targendislun(struct cam_path *path, int enable, int grp6_len, int grp7_len)
401 {
402         struct ccb_en_lun en_ccb;
403         cam_status        status;
404
405         /* Tell the lun to begin answering selects */
406         xpt_setup_ccb(&en_ccb.ccb_h, path, CAM_PRIORITY_NORMAL);
407         en_ccb.ccb_h.func_code = XPT_EN_LUN;
408         /* Don't need support for any vendor specific commands */
409         en_ccb.grp6_len = grp6_len;
410         en_ccb.grp7_len = grp7_len;
411         en_ccb.enable = enable ? 1 : 0;
412         xpt_action((union ccb *)&en_ccb);
413         status = en_ccb.ccb_h.status & CAM_STATUS_MASK;
414         if (status != CAM_REQ_CMP) {
415                 xpt_print(path, "%sable lun CCB rejected, status %#x\n",
416                     enable ? "en" : "dis", status);
417         }
418         return (status);
419 }
420
421 /* Enable target mode on a LUN, given its path */
422 static cam_status
423 targenable(struct targ_softc *softc, struct cam_path *path, int grp6_len,
424            int grp7_len)
425 {
426         struct cam_periph *periph;
427         struct ccb_pathinq cpi;
428         cam_status         status;
429
430         if ((softc->state & TARG_STATE_LUN_ENABLED) != 0)
431                 return (CAM_LUN_ALRDY_ENA);
432
433         /* Make sure SIM supports target mode */
434         xpt_setup_ccb(&cpi.ccb_h, path, CAM_PRIORITY_NORMAL);
435         cpi.ccb_h.func_code = XPT_PATH_INQ;
436         xpt_action((union ccb *)&cpi);
437         status = cpi.ccb_h.status & CAM_STATUS_MASK;
438         if (status != CAM_REQ_CMP) {
439                 printf("pathinq failed, status %#x\n", status);
440                 goto enable_fail;
441         }
442         if ((cpi.target_sprt & PIT_PROCESSOR) == 0) {
443                 printf("controller does not support target mode\n");
444                 status = CAM_FUNC_NOTAVAIL;
445                 goto enable_fail;
446         }
447
448         /* Destroy any periph on our path if it is disabled */
449         periph = cam_periph_find(path, "targ");
450         if (periph != NULL) {
451                 struct targ_softc *del_softc;
452
453                 del_softc = (struct targ_softc *)periph->softc;
454                 if ((del_softc->state & TARG_STATE_LUN_ENABLED) == 0) {
455                         cam_periph_invalidate(del_softc->periph);
456                         del_softc->periph = NULL;
457                 } else {
458                         printf("Requested path still in use by targ%d\n",
459                                periph->unit_number);
460                         status = CAM_LUN_ALRDY_ENA;
461                         goto enable_fail;
462                 }
463         }
464
465         /* Create a periph instance attached to this path */
466         status = cam_periph_alloc(targctor, NULL, targdtor, targstart,
467                         "targ", CAM_PERIPH_BIO, path, targasync, 0, softc);
468         if (status != CAM_REQ_CMP) {
469                 printf("cam_periph_alloc failed, status %#x\n", status);
470                 goto enable_fail;
471         }
472
473         /* Ensure that the periph now exists. */
474         if (cam_periph_find(path, "targ") == NULL) {
475                 panic("targenable: succeeded but no periph?");
476                 /* NOTREACHED */
477         }
478
479         /* Send the enable lun message */
480         status = targendislun(path, /*enable*/1, grp6_len, grp7_len);
481         if (status != CAM_REQ_CMP) {
482                 printf("enable lun failed, status %#x\n", status);
483                 goto enable_fail;
484         }
485         softc->state |= TARG_STATE_LUN_ENABLED;
486
487 enable_fail:
488         return (status);
489 }
490
491 /* Disable this softc's target instance if enabled */
492 static cam_status
493 targdisable(struct targ_softc *softc)
494 {
495         cam_status status;
496
497         if ((softc->state & TARG_STATE_LUN_ENABLED) == 0)
498                 return (CAM_REQ_CMP);
499
500         CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, ("targdisable\n"));
501
502         /* Abort any ccbs pending on the controller */
503         abort_all_pending(softc);
504
505         /* Disable this lun */
506         status = targendislun(softc->path, /*enable*/0,
507                               /*grp6_len*/0, /*grp7_len*/0);
508         if (status == CAM_REQ_CMP)
509                 softc->state &= ~TARG_STATE_LUN_ENABLED;
510         else
511                 printf("Disable lun failed, status %#x\n", status);
512
513         return (status);
514 }
515
516 /* Initialize a periph (called from cam_periph_alloc) */
517 static cam_status
518 targctor(struct cam_periph *periph, void *arg)
519 {
520         struct targ_softc *softc;
521
522         /* Store pointer to softc for periph-driven routines */
523         softc = (struct targ_softc *)arg;
524         periph->softc = softc;
525         softc->periph = periph;
526         softc->path = periph->path;
527         return (CAM_REQ_CMP);
528 }
529
530 static void
531 targdtor(struct cam_periph *periph)
532 {
533         struct targ_softc     *softc;
534         struct ccb_hdr        *ccb_h;
535         struct targ_cmd_descr *descr;
536
537         softc = (struct targ_softc *)periph->softc;
538
539         /* 
540          * targdisable() aborts CCBs back to the user and leaves them
541          * on user_ccb_queue and abort_queue in case the user is still
542          * interested in them.  We free them now.
543          */
544         while ((ccb_h = TAILQ_FIRST(&softc->user_ccb_queue)) != NULL) {
545                 TAILQ_REMOVE(&softc->user_ccb_queue, ccb_h, periph_links.tqe);
546                 targfreeccb(softc, (union ccb *)ccb_h);
547         }
548         while ((descr = TAILQ_FIRST(&softc->abort_queue)) != NULL) {
549                 TAILQ_REMOVE(&softc->abort_queue, descr, tqe);
550                 free(descr, M_TARG);
551         }
552
553         softc->periph = NULL;
554         softc->path = NULL;
555         periph->softc = NULL;
556 }
557
558 /* Receive CCBs from user mode proc and send them to the HBA */
559 static int
560 targwrite(struct cdev *dev, struct uio *uio, int ioflag)
561 {
562         union ccb *user_ccb;
563         struct targ_softc *softc;
564         struct targ_cmd_descr *descr;
565         int write_len, error;
566         int func_code, priority;
567
568         softc = (struct targ_softc *)dev->si_drv1;
569         write_len = error = 0;
570         CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH,
571                   ("write - uio_resid %zd\n", uio->uio_resid));
572         while (uio->uio_resid >= sizeof(user_ccb) && error == 0) {
573                 union ccb *ccb;
574
575                 error = uiomove((caddr_t)&user_ccb, sizeof(user_ccb), uio);
576                 if (error != 0) {
577                         CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH,
578                                   ("write - uiomove failed (%d)\n", error));
579                         break;
580                 }
581                 priority = fuword32(&user_ccb->ccb_h.pinfo.priority);
582                 if (priority == CAM_PRIORITY_NONE) {
583                         error = EINVAL;
584                         break;
585                 }
586                 func_code = fuword32(&user_ccb->ccb_h.func_code);
587                 switch (func_code) {
588                 case XPT_ACCEPT_TARGET_IO:
589                 case XPT_IMMED_NOTIFY:
590                         cam_periph_lock(softc->periph);
591                         ccb = targgetccb(softc, func_code, priority);
592                         descr = (struct targ_cmd_descr *)ccb->ccb_h.targ_descr;
593                         descr->user_ccb = user_ccb;
594                         descr->func_code = func_code;
595                         CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH,
596                                   ("Sent ATIO/INOT (%p)\n", user_ccb));
597                         xpt_action(ccb);
598                         TAILQ_INSERT_TAIL(&softc->pending_ccb_queue,
599                                           &ccb->ccb_h,
600                                           periph_links.tqe);
601                         cam_periph_unlock(softc->periph);
602                         break;
603                 default:
604                         cam_periph_lock(softc->periph);
605                         if ((func_code & XPT_FC_QUEUED) != 0) {
606                                 CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH,
607                                           ("Sending queued ccb %#x (%p)\n",
608                                           func_code, user_ccb));
609                                 descr = targgetdescr(softc);
610                                 descr->user_ccb = user_ccb;
611                                 descr->priority = priority;
612                                 descr->func_code = func_code;
613                                 TAILQ_INSERT_TAIL(&softc->work_queue,
614                                                   descr, tqe);
615                                 xpt_schedule(softc->periph, priority);
616                         } else {
617                                 CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH,
618                                           ("Sending inline ccb %#x (%p)\n",
619                                           func_code, user_ccb));
620                                 ccb = targgetccb(softc, func_code, priority);
621                                 descr = (struct targ_cmd_descr *)
622                                          ccb->ccb_h.targ_descr;
623                                 descr->user_ccb = user_ccb;
624                                 descr->priority = priority;
625                                 descr->func_code = func_code;
626                                 if (targusermerge(softc, descr, ccb) != EFAULT)
627                                         targsendccb(softc, ccb, descr);
628                                 targreturnccb(softc, ccb);
629                         }
630                         cam_periph_unlock(softc->periph);
631                         break;
632                 }
633                 write_len += sizeof(user_ccb);
634         }
635         
636         /*
637          * If we've successfully taken in some amount of
638          * data, return success for that data first.  If
639          * an error is persistent, it will be reported
640          * on the next write.
641          */
642         if (error != 0 && write_len == 0)
643                 return (error);
644         if (write_len == 0 && uio->uio_resid != 0)
645                 return (ENOSPC);
646         return (0);
647 }
648
649 /* Process requests (descrs) via the periph-supplied CCBs */
650 static void
651 targstart(struct cam_periph *periph, union ccb *start_ccb)
652 {
653         struct targ_softc *softc;
654         struct targ_cmd_descr *descr, *next_descr;
655         int error;
656
657         softc = (struct targ_softc *)periph->softc;
658         CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, ("targstart %p\n", start_ccb));
659
660         descr = TAILQ_FIRST(&softc->work_queue);
661         if (descr == NULL) {
662                 xpt_release_ccb(start_ccb);
663         } else {
664                 TAILQ_REMOVE(&softc->work_queue, descr, tqe);
665                 next_descr = TAILQ_FIRST(&softc->work_queue);
666
667                 /* Initiate a transaction using the descr and supplied CCB */
668                 error = targusermerge(softc, descr, start_ccb);
669                 if (error == 0)
670                         error = targsendccb(softc, start_ccb, descr);
671                 if (error != 0) {
672                         xpt_print(periph->path,
673                             "targsendccb failed, err %d\n", error);
674                         xpt_release_ccb(start_ccb);
675                         suword(&descr->user_ccb->ccb_h.status,
676                                CAM_REQ_CMP_ERR);
677                         TAILQ_INSERT_TAIL(&softc->abort_queue, descr, tqe);
678                         notify_user(softc);
679                 }
680
681                 /* If we have more work to do, stay scheduled */
682                 if (next_descr != NULL)
683                         xpt_schedule(periph, next_descr->priority);
684         }
685 }
686
687 static int
688 targusermerge(struct targ_softc *softc, struct targ_cmd_descr *descr,
689               union ccb *ccb)
690 {
691         struct ccb_hdr *u_ccbh, *k_ccbh;
692         size_t ccb_len;
693         int error;
694
695         u_ccbh = &descr->user_ccb->ccb_h;
696         k_ccbh = &ccb->ccb_h;
697
698         /*
699          * There are some fields in the CCB header that need to be
700          * preserved, the rest we get from the user ccb. (See xpt_merge_ccb)
701          */
702         xpt_setup_ccb(k_ccbh, softc->path, descr->priority);
703         k_ccbh->retry_count = fuword32(&u_ccbh->retry_count);
704         k_ccbh->func_code = descr->func_code;
705         k_ccbh->flags = fuword32(&u_ccbh->flags);
706         k_ccbh->timeout = fuword32(&u_ccbh->timeout);
707         ccb_len = targccblen(k_ccbh->func_code) - sizeof(struct ccb_hdr);
708         error = copyin(u_ccbh + 1, k_ccbh + 1, ccb_len);
709         if (error != 0) {
710                 k_ccbh->status = CAM_REQ_CMP_ERR;
711                 return (error);
712         }
713
714         /* Translate usermode abort_ccb pointer to its kernel counterpart */
715         if (k_ccbh->func_code == XPT_ABORT) {
716                 struct ccb_abort *cab;
717                 struct ccb_hdr *ccb_h;
718
719                 cab = (struct ccb_abort *)ccb;
720                 TAILQ_FOREACH(ccb_h, &softc->pending_ccb_queue,
721                     periph_links.tqe) {
722                         struct targ_cmd_descr *ab_descr;
723
724                         ab_descr = (struct targ_cmd_descr *)ccb_h->targ_descr;
725                         if (ab_descr->user_ccb == cab->abort_ccb) {
726                                 CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH,
727                                           ("Changing abort for %p to %p\n",
728                                           cab->abort_ccb, ccb_h));
729                                 cab->abort_ccb = (union ccb *)ccb_h;
730                                 break;
731                         }
732                 }
733                 /* CCB not found, set appropriate status */
734                 if (ccb_h == NULL) {
735                         k_ccbh->status = CAM_PATH_INVALID;
736                         error = ESRCH;
737                 }
738         }
739
740         return (error);
741 }
742
743 /* Build and send a kernel CCB formed from descr->user_ccb */
744 static int
745 targsendccb(struct targ_softc *softc, union ccb *ccb,
746             struct targ_cmd_descr *descr)
747 {
748         struct cam_periph_map_info *mapinfo;
749         struct ccb_hdr *ccb_h;
750         int error;
751
752         ccb_h = &ccb->ccb_h;
753         mapinfo = &descr->mapinfo;
754         mapinfo->num_bufs_used = 0;
755
756         /*
757          * There's no way for the user to have a completion
758          * function, so we put our own completion function in here.
759          * We also stash in a reference to our descriptor so targreturnccb()
760          * can find our mapping info.
761          */
762         ccb_h->cbfcnp = targdone;
763         ccb_h->targ_descr = descr;
764
765         /*
766          * We only attempt to map the user memory into kernel space
767          * if they haven't passed in a physical memory pointer,
768          * and if there is actually an I/O operation to perform.
769          * Right now cam_periph_mapmem() only supports SCSI and device
770          * match CCBs.  For the SCSI CCBs, we only pass the CCB in if
771          * there's actually data to map.  cam_periph_mapmem() will do the
772          * right thing, even if there isn't data to map, but since CCBs
773          * without data are a reasonably common occurance (e.g. test unit
774          * ready), it will save a few cycles if we check for it here.
775          */
776         if (((ccb_h->flags & CAM_DATA_PHYS) == 0)
777          && (((ccb_h->func_code == XPT_CONT_TARGET_IO)
778             && ((ccb_h->flags & CAM_DIR_MASK) != CAM_DIR_NONE))
779           || (ccb_h->func_code == XPT_DEV_MATCH))) {
780
781                 error = cam_periph_mapmem(ccb, mapinfo);
782
783                 /*
784                  * cam_periph_mapmem returned an error, we can't continue.
785                  * Return the error to the user.
786                  */
787                 if (error) {
788                         ccb_h->status = CAM_REQ_CMP_ERR;
789                         mapinfo->num_bufs_used = 0;
790                         return (error);
791                 }
792         }
793
794         /*
795          * Once queued on the pending CCB list, this CCB will be protected
796          * by our error recovery handler.
797          */
798         CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, ("sendccb %p\n", ccb));
799         if (XPT_FC_IS_QUEUED(ccb)) {
800                 TAILQ_INSERT_TAIL(&softc->pending_ccb_queue, ccb_h,
801                                   periph_links.tqe);
802         }
803         xpt_action(ccb);
804
805         return (0);
806 }
807
808 /* Completion routine for CCBs (called at splsoftcam) */
809 static void
810 targdone(struct cam_periph *periph, union ccb *done_ccb)
811 {
812         struct targ_softc *softc;
813         cam_status status;
814
815         CAM_DEBUG(periph->path, CAM_DEBUG_PERIPH, ("targdone %p\n", done_ccb));
816         softc = (struct targ_softc *)periph->softc;
817         TAILQ_REMOVE(&softc->pending_ccb_queue, &done_ccb->ccb_h,
818                      periph_links.tqe);
819         status = done_ccb->ccb_h.status & CAM_STATUS_MASK;
820
821         /* If we're no longer enabled, throw away CCB */
822         if ((softc->state & TARG_STATE_LUN_ENABLED) == 0) {
823                 targfreeccb(softc, done_ccb);
824                 return;
825         }
826         /* abort_all_pending() waits for pending queue to be empty */
827         if (TAILQ_EMPTY(&softc->pending_ccb_queue))
828                 wakeup(&softc->pending_ccb_queue);
829
830         switch (done_ccb->ccb_h.func_code) {
831         /* All FC_*_QUEUED CCBs go back to userland */
832         case XPT_IMMED_NOTIFY:
833         case XPT_ACCEPT_TARGET_IO:
834         case XPT_CONT_TARGET_IO:
835                 TAILQ_INSERT_TAIL(&softc->user_ccb_queue, &done_ccb->ccb_h,
836                                   periph_links.tqe);
837                 cam_periph_unlock(softc->periph);
838                 notify_user(softc);
839                 cam_periph_lock(softc->periph);
840                 break;
841         default:
842                 panic("targdone: impossible xpt opcode %#x",
843                       done_ccb->ccb_h.func_code);
844                 /* NOTREACHED */
845         }
846 }
847
848 /* Return CCBs to the user from the user queue and abort queue */
849 static int
850 targread(struct cdev *dev, struct uio *uio, int ioflag)
851 {
852         struct descr_queue      *abort_queue;
853         struct targ_cmd_descr   *user_descr;
854         struct targ_softc       *softc;
855         struct ccb_queue  *user_queue;
856         struct ccb_hdr    *ccb_h;
857         union  ccb        *user_ccb;
858         int                read_len, error;
859
860         error = 0;
861         read_len = 0;
862         softc = (struct targ_softc *)dev->si_drv1;
863         user_queue = &softc->user_ccb_queue;
864         abort_queue = &softc->abort_queue;
865         CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, ("targread\n"));
866
867         /* If no data is available, wait or return immediately */
868         cam_periph_lock(softc->periph);
869         ccb_h = TAILQ_FIRST(user_queue);
870         user_descr = TAILQ_FIRST(abort_queue);
871         while (ccb_h == NULL && user_descr == NULL) {
872                 if ((ioflag & IO_NDELAY) == 0) {
873                         error = msleep(user_queue, softc->periph->sim->mtx,
874                             PRIBIO | PCATCH, "targrd", 0);
875                         ccb_h = TAILQ_FIRST(user_queue);
876                         user_descr = TAILQ_FIRST(abort_queue);
877                         if (error != 0) {
878                                 if (error == ERESTART) {
879                                         continue;
880                                 } else {
881                                         goto read_fail;
882                                 }
883                         }
884                 } else {
885                         cam_periph_unlock(softc->periph);
886                         return (EAGAIN);
887                 }
888         }
889
890         /* Data is available so fill the user's buffer */
891         while (ccb_h != NULL) {
892                 struct targ_cmd_descr *descr;
893
894                 if (uio->uio_resid < sizeof(user_ccb))
895                         break;
896                 TAILQ_REMOVE(user_queue, ccb_h, periph_links.tqe);
897                 descr = (struct targ_cmd_descr *)ccb_h->targ_descr;
898                 user_ccb = descr->user_ccb;
899                 CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH,
900                           ("targread ccb %p (%p)\n", ccb_h, user_ccb));
901                 error = targreturnccb(softc, (union ccb *)ccb_h);
902                 if (error != 0)
903                         goto read_fail;
904                 cam_periph_unlock(softc->periph);
905                 error = uiomove((caddr_t)&user_ccb, sizeof(user_ccb), uio);
906                 cam_periph_lock(softc->periph);
907                 if (error != 0)
908                         goto read_fail;
909                 read_len += sizeof(user_ccb);
910
911                 ccb_h = TAILQ_FIRST(user_queue);
912         }
913
914         /* Flush out any aborted descriptors */
915         while (user_descr != NULL) {
916                 if (uio->uio_resid < sizeof(user_ccb))
917                         break;
918                 TAILQ_REMOVE(abort_queue, user_descr, tqe);
919                 user_ccb = user_descr->user_ccb;
920                 CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH,
921                           ("targread aborted descr %p (%p)\n",
922                           user_descr, user_ccb));
923                 suword(&user_ccb->ccb_h.status, CAM_REQ_ABORTED);
924                 cam_periph_unlock(softc->periph);
925                 error = uiomove((caddr_t)&user_ccb, sizeof(user_ccb), uio);
926                 cam_periph_lock(softc->periph);
927                 if (error != 0)
928                         goto read_fail;
929                 read_len += sizeof(user_ccb);
930
931                 user_descr = TAILQ_FIRST(abort_queue);
932         }
933
934         /*
935          * If we've successfully read some amount of data, don't report an
936          * error.  If the error is persistent, it will be reported on the
937          * next read().
938          */
939         if (read_len == 0 && uio->uio_resid != 0)
940                 error = ENOSPC;
941
942 read_fail:
943         cam_periph_unlock(softc->periph);
944         return (error);
945 }
946
947 /* Copy completed ccb back to the user */
948 static int
949 targreturnccb(struct targ_softc *softc, union ccb *ccb)
950 {
951         struct targ_cmd_descr *descr;
952         struct ccb_hdr *u_ccbh;
953         size_t ccb_len;
954         int error;
955
956         CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, ("targreturnccb %p\n", ccb));
957         descr = (struct targ_cmd_descr *)ccb->ccb_h.targ_descr;
958         u_ccbh = &descr->user_ccb->ccb_h;
959
960         /* Copy out the central portion of the ccb_hdr */
961         copyout(&ccb->ccb_h.retry_count, &u_ccbh->retry_count,
962                 offsetof(struct ccb_hdr, periph_priv) -
963                 offsetof(struct ccb_hdr, retry_count));
964
965         /* Copy out the rest of the ccb (after the ccb_hdr) */
966         ccb_len = targccblen(ccb->ccb_h.func_code) - sizeof(struct ccb_hdr);
967         if (descr->mapinfo.num_bufs_used != 0)
968                 cam_periph_unmapmem(ccb, &descr->mapinfo);
969         error = copyout(&ccb->ccb_h + 1, u_ccbh + 1, ccb_len);
970         if (error != 0) {
971                 xpt_print(softc->path,
972                     "targreturnccb - CCB copyout failed (%d)\n", error);
973         }
974         /* Free CCB or send back to devq. */
975         targfreeccb(softc, ccb);
976
977         return (error);
978 }
979
980 static union ccb *
981 targgetccb(struct targ_softc *softc, xpt_opcode type, int priority)
982 {
983         union ccb *ccb;
984         int ccb_len;
985
986         ccb_len = targccblen(type);
987         ccb = malloc(ccb_len, M_TARG, M_NOWAIT);
988         CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, ("getccb %p\n", ccb));
989         if (ccb == NULL) {
990                 return (ccb);
991         }
992         xpt_setup_ccb(&ccb->ccb_h, softc->path, priority);
993         ccb->ccb_h.func_code = type;
994         ccb->ccb_h.cbfcnp = targdone;
995         ccb->ccb_h.targ_descr = targgetdescr(softc);
996         if (ccb->ccb_h.targ_descr == NULL) {
997                 free (ccb, M_TARG);
998                 ccb = NULL;
999         }
1000         return (ccb);
1001 }
1002
1003 static void
1004 targfreeccb(struct targ_softc *softc, union ccb *ccb)
1005 {
1006         CAM_DEBUG_PRINT(CAM_DEBUG_PERIPH, ("targfreeccb descr %p and\n",
1007                         ccb->ccb_h.targ_descr));
1008         free(ccb->ccb_h.targ_descr, M_TARG);
1009
1010         switch (ccb->ccb_h.func_code) {
1011         case XPT_ACCEPT_TARGET_IO:
1012         case XPT_IMMED_NOTIFY:
1013                 CAM_DEBUG_PRINT(CAM_DEBUG_PERIPH, ("freeing ccb %p\n", ccb));
1014                 free(ccb, M_TARG);
1015                 break;
1016         default:
1017                 /* Send back CCB if we got it from the periph */
1018                 if (XPT_FC_IS_QUEUED(ccb)) {
1019                         CAM_DEBUG_PRINT(CAM_DEBUG_PERIPH,
1020                                         ("returning queued ccb %p\n", ccb));
1021                         xpt_release_ccb(ccb);
1022                 } else {
1023                         CAM_DEBUG_PRINT(CAM_DEBUG_PERIPH,
1024                                         ("freeing ccb %p\n", ccb));
1025                         free(ccb, M_TARG);
1026                 }
1027                 break;
1028         }
1029 }
1030
1031 static struct targ_cmd_descr *
1032 targgetdescr(struct targ_softc *softc)
1033 {
1034         struct targ_cmd_descr *descr;
1035
1036         descr = malloc(sizeof(*descr), M_TARG,
1037                M_NOWAIT);
1038         if (descr) {
1039                 descr->mapinfo.num_bufs_used = 0;
1040         }
1041         return (descr);
1042 }
1043
1044 static void
1045 targinit(void)
1046 {
1047         EVENTHANDLER_REGISTER(dev_clone, targclone, 0, 1000);
1048 }
1049
1050 static void
1051 targclone(void *arg, struct ucred *cred, char *name, int namelen,
1052     struct cdev **dev)
1053 {
1054         int u;
1055
1056         if (*dev != NULL)
1057                 return;
1058         if (dev_stdclone(name, NULL, "targ", &u) != 1)
1059                 return;
1060         *dev = make_dev(&targ_cdevsw, u, UID_ROOT, GID_WHEEL,
1061                         0600, "targ%d", u);
1062         dev_ref(*dev);
1063         (*dev)->si_flags |= SI_CHEAPCLONE;
1064 }
1065
1066 static void
1067 targasync(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg)
1068 {
1069         /* All events are handled in usermode by INOTs */
1070         panic("targasync() called, should be an INOT instead");
1071 }
1072
1073 /* Cancel all pending requests and CCBs awaiting work. */
1074 static void
1075 abort_all_pending(struct targ_softc *softc)
1076 {
1077         struct targ_cmd_descr   *descr;
1078         struct ccb_abort         cab;
1079         struct ccb_hdr          *ccb_h;
1080         struct cam_sim          *sim;
1081
1082         CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, ("abort_all_pending\n"));
1083
1084         /* First abort the descriptors awaiting resources */
1085         while ((descr = TAILQ_FIRST(&softc->work_queue)) != NULL) {
1086                 CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH,
1087                           ("Aborting descr from workq %p\n", descr));
1088                 TAILQ_REMOVE(&softc->work_queue, descr, tqe);
1089                 TAILQ_INSERT_TAIL(&softc->abort_queue, descr, tqe);
1090         }
1091
1092         /* 
1093          * Then abort all pending CCBs.
1094          * targdone() will return the aborted CCB via user_ccb_queue
1095          */
1096         xpt_setup_ccb(&cab.ccb_h, softc->path, CAM_PRIORITY_NORMAL);
1097         cab.ccb_h.func_code = XPT_ABORT;
1098         cab.ccb_h.status = CAM_REQ_CMP_ERR;
1099         TAILQ_FOREACH(ccb_h, &softc->pending_ccb_queue, periph_links.tqe) {
1100                 CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH,
1101                           ("Aborting pending CCB %p\n", ccb_h));
1102                 cab.abort_ccb = (union ccb *)ccb_h;
1103                 xpt_action((union ccb *)&cab);
1104                 if (cab.ccb_h.status != CAM_REQ_CMP) {
1105                         xpt_print(cab.ccb_h.path,
1106                             "Unable to abort CCB, status %#x\n",
1107                             cab.ccb_h.status);
1108                 }
1109         }
1110
1111         /* If we aborted at least one pending CCB ok, wait for it. */
1112         if (cab.ccb_h.status == CAM_REQ_CMP) {
1113                 sim = xpt_path_sim(softc->path);
1114                 msleep(&softc->pending_ccb_queue, sim->mtx,
1115                        PRIBIO | PCATCH, "tgabrt", 0);
1116         }
1117
1118         /* If we aborted anything from the work queue, wakeup user. */
1119         if (!TAILQ_EMPTY(&softc->user_ccb_queue)
1120          || !TAILQ_EMPTY(&softc->abort_queue)) {
1121                 cam_periph_unlock(softc->periph);
1122                 notify_user(softc);
1123                 cam_periph_lock(softc->periph);
1124         }
1125 }
1126
1127 /* Notify the user that data is ready */
1128 static void
1129 notify_user(struct targ_softc *softc)
1130 {
1131         /*
1132          * Notify users sleeping via poll(), kqueue(), and
1133          * blocking read().
1134          */
1135         selwakeuppri(&softc->read_select, PRIBIO);
1136         KNOTE_UNLOCKED(&softc->read_select.si_note, 0);
1137         wakeup(&softc->user_ccb_queue);
1138 }
1139
1140 /* Convert CAM status to errno values */
1141 static int
1142 targcamstatus(cam_status status)
1143 {
1144         switch (status & CAM_STATUS_MASK) {
1145         case CAM_REQ_CMP:       /* CCB request completed without error */
1146                 return (0);
1147         case CAM_REQ_INPROG:    /* CCB request is in progress */
1148                 return (EINPROGRESS);
1149         case CAM_REQ_CMP_ERR:   /* CCB request completed with an error */
1150                 return (EIO);
1151         case CAM_PROVIDE_FAIL:  /* Unable to provide requested capability */
1152                 return (ENOTTY);
1153         case CAM_FUNC_NOTAVAIL: /* The requested function is not available */
1154                 return (ENOTSUP);
1155         case CAM_LUN_ALRDY_ENA: /* LUN is already enabled for target mode */
1156                 return (EADDRINUSE);
1157         case CAM_PATH_INVALID:  /* Supplied Path ID is invalid */
1158         case CAM_DEV_NOT_THERE: /* SCSI Device Not Installed/there */
1159                 return (ENOENT);
1160         case CAM_REQ_ABORTED:   /* CCB request aborted by the host */
1161                 return (ECANCELED);
1162         case CAM_CMD_TIMEOUT:   /* Command timeout */
1163                 return (ETIMEDOUT);
1164         case CAM_REQUEUE_REQ:   /* Requeue to preserve transaction ordering */
1165                 return (EAGAIN);
1166         case CAM_REQ_INVALID:   /* CCB request was invalid */
1167                 return (EINVAL);
1168         case CAM_RESRC_UNAVAIL: /* Resource Unavailable */
1169                 return (ENOMEM);
1170         case CAM_BUSY:          /* CAM subsystem is busy */
1171         case CAM_UA_ABORT:      /* Unable to abort CCB request */
1172                 return (EBUSY);
1173         default:
1174                 return (ENXIO);
1175         }
1176 }
1177
1178 static size_t
1179 targccblen(xpt_opcode func_code)
1180 {
1181         int len;
1182
1183         /* Codes we expect to see as a target */
1184         switch (func_code) {
1185         case XPT_CONT_TARGET_IO:
1186         case XPT_SCSI_IO:
1187                 len = sizeof(struct ccb_scsiio);
1188                 break;
1189         case XPT_ACCEPT_TARGET_IO:
1190                 len = sizeof(struct ccb_accept_tio);
1191                 break;
1192         case XPT_IMMED_NOTIFY:
1193                 len = sizeof(struct ccb_immed_notify);
1194                 break;
1195         case XPT_REL_SIMQ:
1196                 len = sizeof(struct ccb_relsim);
1197                 break;
1198         case XPT_PATH_INQ:
1199                 len = sizeof(struct ccb_pathinq);
1200                 break;
1201         case XPT_DEBUG:
1202                 len = sizeof(struct ccb_debug);
1203                 break;
1204         case XPT_ABORT:
1205                 len = sizeof(struct ccb_abort);
1206                 break;
1207         case XPT_EN_LUN:
1208                 len = sizeof(struct ccb_en_lun);
1209                 break;
1210         default:
1211                 len = sizeof(union ccb);
1212                 break;
1213         }
1214
1215         return (len);
1216 }
1217
1218 /*
1219  * work around to destroy targ device
1220  * outside of targclose
1221  */
1222 static void
1223 targdestroy(void *dev)
1224 {
1225         struct cdev *device = (struct cdev *)dev;
1226         struct targ_softc *softc = (struct targ_softc *)device->si_drv1;
1227
1228 #if 0
1229         callout_stop(&softc->destroy_dev_callout);
1230 #endif
1231
1232         mtx_unlock(&softc->destroy_mtx);
1233         mtx_destroy(&softc->destroy_mtx);
1234         free(softc, M_TARG);
1235         device->si_drv1 = 0;
1236         destroy_dev(device);
1237         printf("%s: destroyed dev\n", __func__);
1238 }