Fine-grained malloc statistics - replace some M_DEVBUF with module-specific
[dragonfly.git] / sys / bus / cam / scsi / scsi_targ_bh.c
1 /*
2  * Implementation of the Target Mode 'Black Hole device' for CAM.
3  *
4  * Copyright (c) 1999 Justin T. Gibbs.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions, and the following disclaimer,
12  *    without modification, immediately at the beginning of the file.
13  * 2. The name of the author may not be used to endorse or promote products
14  *    derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
20  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  *
28  * $FreeBSD: src/sys/cam/scsi/scsi_targ_bh.c,v 1.4.2.6 2003/11/14 11:31:25 simokawa Exp $
29  * $DragonFly: src/sys/bus/cam/scsi/scsi_targ_bh.c,v 1.18 2007/12/01 22:21:18 pavalos Exp $
30  */
31 #include <sys/param.h>
32 #include <sys/queue.h>
33 #include <sys/systm.h>
34 #include <sys/kernel.h>
35 #include <sys/types.h>
36 #include <sys/buf.h>
37 #include <sys/conf.h>
38 #include <sys/devicestat.h>
39 #include <sys/malloc.h>
40 #include <sys/thread2.h>
41 #include <sys/uio.h>
42
43 #include "../cam.h"
44 #include "../cam_ccb.h"
45 #include "../cam_extend.h"
46 #include "../cam_periph.h"
47 #include "../cam_queue.h"
48 #include "../cam_xpt_periph.h"
49 #include "../cam_debug.h"
50
51 #include "scsi_all.h"
52 #include "scsi_message.h"
53
54 MALLOC_DEFINE(M_SCSIBH, "SCSI bh", "SCSI blackhole buffers");
55
56 typedef enum {
57         TARGBH_STATE_NORMAL,
58         TARGBH_STATE_EXCEPTION,
59         TARGBH_STATE_TEARDOWN
60 } targbh_state;
61
62 typedef enum {
63         TARGBH_FLAG_NONE         = 0x00,
64         TARGBH_FLAG_LUN_ENABLED  = 0x01
65 } targbh_flags;
66
67 typedef enum {
68         TARGBH_CCB_WORKQ,
69         TARGBH_CCB_WAITING
70 } targbh_ccb_types;
71
72 #define MAX_ACCEPT      8
73 #define MAX_IMMEDIATE   16
74 #define MAX_BUF_SIZE    256     /* Max inquiry/sense/mode page transfer */
75
76 /* Offsets into our private CCB area for storing accept information */
77 #define ccb_type        ppriv_field0
78 #define ccb_descr       ppriv_ptr1
79
80 /* We stick a pointer to the originating accept TIO in each continue I/O CCB */
81 #define ccb_atio        ppriv_ptr1
82
83 TAILQ_HEAD(ccb_queue, ccb_hdr);
84
85 struct targbh_softc {
86         struct          ccb_queue pending_queue;
87         struct          ccb_queue work_queue;
88         struct          ccb_queue unknown_atio_queue;
89         struct          devstat device_stats;
90         targbh_state    state;
91         targbh_flags    flags;  
92         u_int           init_level;
93         u_int           inq_data_len;
94         struct          ccb_accept_tio *accept_tio_list;
95         struct          ccb_hdr_slist immed_notify_slist;
96 };
97
98 struct targbh_cmd_desc {
99         struct    ccb_accept_tio* atio_link;
100         u_int     data_resid;   /* How much left to transfer */
101         u_int     data_increment;/* Amount to send before next disconnect */
102         void*     data;         /* The data. Can be from backing_store or not */
103         void*     backing_store;/* Backing store allocated for this descriptor*/
104         u_int     max_size;     /* Size of backing_store */
105         u_int32_t timeout;      
106         u_int8_t  status;       /* Status to return to initiator */
107 };
108
109 static struct scsi_inquiry_data no_lun_inq_data =
110 {
111         T_NODEVICE | (SID_QUAL_BAD_LU << 5), 0,
112         /* version */2, /* format version */2
113 };
114
115 static struct scsi_sense_data no_lun_sense_data =
116 {
117         SSD_CURRENT_ERROR|SSD_ERRCODE_VALID,
118         0,
119         SSD_KEY_NOT_READY, 
120         { 0, 0, 0, 0 },
121         /*extra_len*/offsetof(struct scsi_sense_data, fru)
122                    - offsetof(struct scsi_sense_data, extra_len),
123         { 0, 0, 0, 0 },
124         /* Logical Unit Not Supported */
125         /*ASC*/0x25, /*ASCQ*/0
126 };
127
128 static const int request_sense_size = offsetof(struct scsi_sense_data, fru);
129
130 static periph_init_t    targbhinit;
131 static void             targbhasync(void *callback_arg, u_int32_t code,
132                                     struct cam_path *path, void *arg);
133 static cam_status       targbhenlun(struct cam_periph *periph);
134 static cam_status       targbhdislun(struct cam_periph *periph);
135 static periph_ctor_t    targbhctor;
136 static periph_dtor_t    targbhdtor;
137 static periph_start_t   targbhstart;
138 static void             targbhdone(struct cam_periph *periph,
139                                    union ccb *done_ccb);
140 #ifdef NOTYET
141 static  int             targbherror(union ccb *ccb, u_int32_t cam_flags,
142                                     u_int32_t sense_flags);
143 #endif
144 static struct targbh_cmd_desc*  targbhallocdescr(void);
145 static void             targbhfreedescr(struct targbh_cmd_desc *buf);
146                                         
147 static struct periph_driver targbhdriver =
148 {
149         targbhinit, "targbh",
150         TAILQ_HEAD_INITIALIZER(targbhdriver.units), /* generation */ 0
151 };
152
153 PERIPHDRIVER_DECLARE(targbh, targbhdriver);
154
155 static void
156 targbhinit(void)
157 {
158         cam_status status;
159         struct cam_path *path;
160
161         /*
162          * Install a global async callback.  This callback will
163          * receive async callbacks like "new path registered".
164          */
165         status = xpt_create_path(&path, /*periph*/NULL, CAM_XPT_PATH_ID,
166                                  CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD);
167
168         if (status == CAM_REQ_CMP) {
169                 struct ccb_setasync csa;
170
171                 xpt_setup_ccb(&csa.ccb_h, path, /*priority*/5);
172                 csa.ccb_h.func_code = XPT_SASYNC_CB;
173                 csa.event_enable = AC_PATH_REGISTERED | AC_PATH_DEREGISTERED;
174                 csa.callback = targbhasync;
175                 csa.callback_arg = NULL;
176                 xpt_action((union ccb *)&csa);
177                 status = csa.ccb_h.status;
178                 xpt_free_path(path);
179         }
180
181         if (status != CAM_REQ_CMP) {
182                 kprintf("targbh: Failed to attach master async callback "
183                        "due to status 0x%x!\n", status);
184         }
185 }
186
187 static void
188 targbhasync(void *callback_arg, u_int32_t code,
189             struct cam_path *path, void *arg)
190 {
191         struct cam_path *new_path;
192         struct ccb_pathinq *cpi;
193         path_id_t bus_path_id;
194         cam_status status;
195
196         cpi = (struct ccb_pathinq *)arg;
197         if (code == AC_PATH_REGISTERED)
198                 bus_path_id = cpi->ccb_h.path_id;
199         else
200                 bus_path_id = xpt_path_path_id(path);
201         /*
202          * Allocate a peripheral instance for
203          * this target instance.
204          */
205         status = xpt_create_path(&new_path, NULL,
206                                  bus_path_id,
207                                  CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD);
208         if (status != CAM_REQ_CMP) {
209                 kprintf("targbhasync: Unable to create path "
210                         "due to status 0x%x\n", status);
211                 return;
212         }
213
214         switch (code) {
215         case AC_PATH_REGISTERED:
216         {
217                 /* Only attach to controllers that support target mode */
218                 if ((cpi->target_sprt & PIT_PROCESSOR) == 0)
219                         break;
220
221                 status = cam_periph_alloc(targbhctor, NULL, targbhdtor,
222                                           targbhstart,
223                                           "targbh", CAM_PERIPH_BIO,
224                                           new_path, targbhasync,
225                                           AC_PATH_REGISTERED,
226                                           cpi);
227                 break;
228         }
229         case AC_PATH_DEREGISTERED:
230         {
231                 struct cam_periph *periph;
232
233                 if ((periph = cam_periph_find(new_path, "targbh")) != NULL)
234                         cam_periph_invalidate(periph);
235                 break;
236         }
237         default:
238                 break;
239         }
240         xpt_free_path(new_path);
241 }
242
243 /* Attempt to enable our lun */
244 static cam_status
245 targbhenlun(struct cam_periph *periph)
246 {
247         union ccb immed_ccb;
248         struct targbh_softc *softc;
249         cam_status status;
250         int i;
251
252         softc = (struct targbh_softc *)periph->softc;
253
254         if ((softc->flags & TARGBH_FLAG_LUN_ENABLED) != 0)
255                 return (CAM_REQ_CMP);
256
257         xpt_setup_ccb(&immed_ccb.ccb_h, periph->path, /*priority*/1);
258         immed_ccb.ccb_h.func_code = XPT_EN_LUN;
259
260         /* Don't need support for any vendor specific commands */
261         immed_ccb.cel.grp6_len = 0;
262         immed_ccb.cel.grp7_len = 0;
263         immed_ccb.cel.enable = 1;
264         xpt_action(&immed_ccb);
265         status = immed_ccb.ccb_h.status;
266         if (status != CAM_REQ_CMP) {
267                 xpt_print_path(periph->path);
268                 kprintf("targbhenlun - Enable Lun Rejected with status 0x%x\n",
269                        status);
270                 return (status);
271         }
272         
273         softc->flags |= TARGBH_FLAG_LUN_ENABLED;
274
275         /*
276          * Build up a buffer of accept target I/O
277          * operations for incoming selections.
278          */
279         for (i = 0; i < MAX_ACCEPT; i++) {
280                 struct ccb_accept_tio *atio;
281
282                 atio = kmalloc(sizeof(*atio), M_SCSIBH, M_INTWAIT);
283
284                 atio->ccb_h.ccb_descr = targbhallocdescr();
285
286                 xpt_setup_ccb(&atio->ccb_h, periph->path, /*priority*/1);
287                 atio->ccb_h.func_code = XPT_ACCEPT_TARGET_IO;
288                 atio->ccb_h.cbfcnp = targbhdone;
289                 xpt_action((union ccb *)atio);
290                 status = atio->ccb_h.status;
291                 if (status != CAM_REQ_INPROG) {
292                         targbhfreedescr(atio->ccb_h.ccb_descr);
293                         kfree(atio, M_SCSIBH);
294                         break;
295                 }
296                 ((struct targbh_cmd_desc*)atio->ccb_h.ccb_descr)->atio_link =
297                     softc->accept_tio_list;
298                 softc->accept_tio_list = atio;
299         }
300
301         if (i == 0) {
302                 xpt_print_path(periph->path);
303                 kprintf("targbhenlun - Could not allocate accept tio CCBs: "
304                        "status = 0x%x\n", status);
305                 targbhdislun(periph);
306                 return (CAM_REQ_CMP_ERR);
307         }
308
309         /*
310          * Build up a buffer of immediate notify CCBs
311          * so the SIM can tell us of asynchronous target mode events.
312          */
313         for (i = 0; i < MAX_ACCEPT; i++) {
314                 struct ccb_immed_notify *inot;
315
316                 inot = kmalloc(sizeof(*inot), M_SCSIBH, M_INTWAIT);
317
318                 xpt_setup_ccb(&inot->ccb_h, periph->path, /*priority*/1);
319                 inot->ccb_h.func_code = XPT_IMMED_NOTIFY;
320                 inot->ccb_h.cbfcnp = targbhdone;
321                 xpt_action((union ccb *)inot);
322                 status = inot->ccb_h.status;
323                 if (status != CAM_REQ_INPROG) {
324                         kfree(inot, M_SCSIBH);
325                         break;
326                 }
327                 SLIST_INSERT_HEAD(&softc->immed_notify_slist, &inot->ccb_h,
328                                   periph_links.sle);
329         }
330
331         if (i == 0) {
332                 xpt_print_path(periph->path);
333                 kprintf("targbhenlun - Could not allocate immediate notify "
334                        "CCBs: status = 0x%x\n", status);
335                 targbhdislun(periph);
336                 return (CAM_REQ_CMP_ERR);
337         }
338
339         return (CAM_REQ_CMP);
340 }
341
342 static cam_status
343 targbhdislun(struct cam_periph *periph)
344 {
345         union ccb ccb;
346         struct targbh_softc *softc;
347         struct ccb_accept_tio* atio;
348         struct ccb_hdr *ccb_h;
349
350         softc = (struct targbh_softc *)periph->softc;
351         if ((softc->flags & TARGBH_FLAG_LUN_ENABLED) == 0)
352                 return CAM_REQ_CMP;
353
354         /* XXX Block for Continue I/O completion */
355
356         /* Kill off all ACCECPT and IMMEDIATE CCBs */
357         while ((atio = softc->accept_tio_list) != NULL) {
358                 
359                 softc->accept_tio_list =
360                     ((struct targbh_cmd_desc*)atio->ccb_h.ccb_descr)->atio_link;
361                 xpt_setup_ccb(&ccb.cab.ccb_h, periph->path, /*priority*/1);
362                 ccb.cab.ccb_h.func_code = XPT_ABORT;
363                 ccb.cab.abort_ccb = (union ccb *)atio;
364                 xpt_action(&ccb);
365         }
366
367         while ((ccb_h = SLIST_FIRST(&softc->immed_notify_slist)) != NULL) {
368                 SLIST_REMOVE_HEAD(&softc->immed_notify_slist, periph_links.sle);
369                 xpt_setup_ccb(&ccb.cab.ccb_h, periph->path, /*priority*/1);
370                 ccb.cab.ccb_h.func_code = XPT_ABORT;
371                 ccb.cab.abort_ccb = (union ccb *)ccb_h;
372                 xpt_action(&ccb);
373         }
374
375         /*
376          * Dissable this lun.
377          */
378         xpt_setup_ccb(&ccb.cel.ccb_h, periph->path, /*priority*/1);
379         ccb.cel.ccb_h.func_code = XPT_EN_LUN;
380         ccb.cel.enable = 0;
381         xpt_action(&ccb);
382
383         if (ccb.cel.ccb_h.status != CAM_REQ_CMP)
384                 kprintf("targbhdislun - Disabling lun on controller failed "
385                        "with status 0x%x\n", ccb.cel.ccb_h.status);
386         else 
387                 softc->flags &= ~TARGBH_FLAG_LUN_ENABLED;
388         return (ccb.cel.ccb_h.status);
389 }
390
391 static cam_status
392 targbhctor(struct cam_periph *periph, void *arg)
393 {
394         struct targbh_softc *softc;
395
396         /* Allocate our per-instance private storage */
397         softc = kmalloc(sizeof(*softc), M_SCSIBH, M_INTWAIT | M_ZERO);
398         TAILQ_INIT(&softc->pending_queue);
399         TAILQ_INIT(&softc->work_queue);
400         softc->accept_tio_list = NULL;
401         SLIST_INIT(&softc->immed_notify_slist);
402         softc->state = TARGBH_STATE_NORMAL;
403         periph->softc = softc;
404         softc->init_level++;
405
406         return (targbhenlun(periph));
407 }
408
409 static void
410 targbhdtor(struct cam_periph *periph)
411 {
412         struct targbh_softc *softc;
413
414         softc = (struct targbh_softc *)periph->softc;
415
416         softc->state = TARGBH_STATE_TEARDOWN;
417
418         targbhdislun(periph);
419
420         switch (softc->init_level) {
421         case 0:
422                 panic("targdtor - impossible init level");
423         case 1:
424                 /* FALLTHROUGH */
425         default:
426                 /* XXX Wait for callback of targbhdislun() */
427                 tsleep(softc, 0, "targbh", hz/2);
428                 kfree(softc, M_SCSIBH);
429                 break;
430         }
431 }
432
433 static void
434 targbhstart(struct cam_periph *periph, union ccb *start_ccb)
435 {
436         struct targbh_softc *softc;
437         struct ccb_hdr *ccbh;
438         struct ccb_accept_tio *atio;
439         struct targbh_cmd_desc *desc;
440         struct ccb_scsiio *csio;
441         ccb_flags flags;
442
443         softc = (struct targbh_softc *)periph->softc;
444         
445         crit_enter();
446         ccbh = TAILQ_FIRST(&softc->work_queue);
447         if (periph->immediate_priority <= periph->pinfo.priority) {
448                 start_ccb->ccb_h.ccb_type = TARGBH_CCB_WAITING;                 
449                 SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h,
450                                   periph_links.sle);
451                 periph->immediate_priority = CAM_PRIORITY_NONE;
452                 crit_exit();
453                 wakeup(&periph->ccb_list);
454         } else if (ccbh == NULL) {
455                 crit_exit();
456                 xpt_release_ccb(start_ccb);     
457         } else {
458                 TAILQ_REMOVE(&softc->work_queue, ccbh, periph_links.tqe);
459                 TAILQ_INSERT_HEAD(&softc->pending_queue, ccbh,
460                                   periph_links.tqe);
461                 crit_exit();
462                 atio = (struct ccb_accept_tio*)ccbh;
463                 desc = (struct targbh_cmd_desc *)atio->ccb_h.ccb_descr;
464
465                 /* Is this a tagged request? */
466                 flags = atio->ccb_h.flags &
467                     (CAM_DIS_DISCONNECT|CAM_TAG_ACTION_VALID|CAM_DIR_MASK);
468
469                 csio = &start_ccb->csio;
470                 /*
471                  * If we are done with the transaction, tell the
472                  * controller to send status and perform a CMD_CMPLT.
473                  * If we have associated sense data, see if we can
474                  * send that too.
475                  */
476                 if (desc->data_resid == desc->data_increment) {
477                         flags |= CAM_SEND_STATUS;
478                         if (atio->sense_len) {
479                                 csio->sense_len = atio->sense_len;
480                                 csio->sense_data = atio->sense_data;
481                                 flags |= CAM_SEND_SENSE;
482                         }
483
484                 }
485
486                 cam_fill_ctio(csio,
487                               /*retries*/2,
488                               targbhdone,
489                               flags,
490                               (flags & CAM_TAG_ACTION_VALID)?
491                                 MSG_SIMPLE_Q_TAG : 0,
492                               atio->tag_id,
493                               atio->init_id,
494                               desc->status,
495                               /*data_ptr*/desc->data_increment == 0
496                                           ? NULL : desc->data,
497                               /*dxfer_len*/desc->data_increment,
498                               /*timeout*/desc->timeout);
499
500                 /* Override our wildcard attachment */
501                 start_ccb->ccb_h.target_id = atio->ccb_h.target_id;
502                 start_ccb->ccb_h.target_lun = atio->ccb_h.target_lun;
503
504                 start_ccb->ccb_h.ccb_type = TARGBH_CCB_WORKQ;
505                 start_ccb->ccb_h.ccb_atio = atio;
506                 CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
507                           ("Sending a CTIO\n"));
508                 xpt_action(start_ccb);
509                 /*
510                  * If the queue was frozen waiting for the response
511                  * to this ATIO (for instance disconnection was disallowed),
512                  * then release it now that our response has been queued.
513                  */
514                 if ((atio->ccb_h.status & CAM_DEV_QFRZN) != 0) {
515                         cam_release_devq(periph->path,
516                                          /*relsim_flags*/0,
517                                          /*reduction*/0,
518                                          /*timeout*/0,
519                                          /*getcount_only*/0);
520                         atio->ccb_h.status &= ~CAM_DEV_QFRZN;
521                 }
522                 crit_enter();
523                 ccbh = TAILQ_FIRST(&softc->work_queue);
524                 crit_exit();
525         }
526         if (ccbh != NULL)
527                 xpt_schedule(periph, /*priority*/1);
528 }
529
530 static void
531 targbhdone(struct cam_periph *periph, union ccb *done_ccb)
532 {
533         struct targbh_softc *softc;
534
535         softc = (struct targbh_softc *)periph->softc;
536
537         if (done_ccb->ccb_h.ccb_type == TARGBH_CCB_WAITING) {
538                 /* Caller will release the CCB */
539                 wakeup(&done_ccb->ccb_h.cbfcnp);
540                 return;
541         }
542
543         switch (done_ccb->ccb_h.func_code) {
544         case XPT_ACCEPT_TARGET_IO:
545         {
546                 struct ccb_accept_tio *atio;
547                 struct targbh_cmd_desc *descr;
548                 u_int8_t *cdb;
549                 int priority;
550
551                 atio = &done_ccb->atio;
552                 descr = (struct targbh_cmd_desc*)atio->ccb_h.ccb_descr;
553                 cdb = atio->cdb_io.cdb_bytes;
554                 if (softc->state == TARGBH_STATE_TEARDOWN
555                  || atio->ccb_h.status == CAM_REQ_ABORTED) {
556                         targbhfreedescr(descr);
557                         xpt_free_ccb(done_ccb);
558                         return;
559                 }
560
561                 /*
562                  * Determine the type of incoming command and
563                  * setup our buffer for a response.
564                  */
565                 switch (cdb[0]) {
566                 case INQUIRY:
567                 {
568                         struct scsi_inquiry *inq;
569
570                         inq = (struct scsi_inquiry *)cdb;
571                         CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
572                                   ("Saw an inquiry!\n"));
573                         /*
574                          * Validate the command.  We don't
575                          * support any VPD pages, so complain
576                          * if EVPD is set.
577                          */
578                         if ((inq->byte2 & SI_EVPD) != 0
579                          || inq->page_code != 0) {
580                                 atio->ccb_h.flags &= ~CAM_DIR_MASK;
581                                 atio->ccb_h.flags |= CAM_DIR_NONE;
582                                 /*
583                                  * This needs to have other than a
584                                  * no_lun_sense_data response.
585                                  */
586                                 atio->sense_data = no_lun_sense_data;
587                                 atio->sense_len = sizeof(no_lun_sense_data);
588                                 descr->data_resid = 0;
589                                 descr->data_increment = 0;
590                                 descr->status = SCSI_STATUS_CHECK_COND;
591                                 break;
592                         }
593                         /*
594                          * Direction is always relative
595                          * to the initator.
596                          */
597                         atio->ccb_h.flags &= ~CAM_DIR_MASK;
598                         atio->ccb_h.flags |= CAM_DIR_IN;
599                         descr->data = &no_lun_inq_data;
600                         descr->data_resid = MIN(sizeof(no_lun_inq_data),
601                                                 SCSI_CDB6_LEN(inq->length));
602                         descr->data_increment = descr->data_resid;
603                         descr->timeout = 5 * 1000;
604                         descr->status = SCSI_STATUS_OK;
605                         break;
606                 }
607                 case REQUEST_SENSE:
608                 {
609                         struct scsi_request_sense *rsense;
610
611                         rsense = (struct scsi_request_sense *)cdb;
612                         /* Refer to static sense data */
613                         atio->ccb_h.flags &= ~CAM_DIR_MASK;
614                         atio->ccb_h.flags |= CAM_DIR_IN;
615                         descr->data = &no_lun_sense_data;
616                         descr->data_resid = request_sense_size;
617                         descr->data_resid = MIN(descr->data_resid,
618                                                 SCSI_CDB6_LEN(rsense->length));
619                         descr->data_increment = descr->data_resid;
620                         descr->timeout = 5 * 1000;
621                         descr->status = SCSI_STATUS_OK;
622                         break;
623                 }
624                 default:
625                         /* Constant CA, tell initiator */
626                         /* Direction is always relative to the initator */
627                         atio->ccb_h.flags &= ~CAM_DIR_MASK;
628                         atio->ccb_h.flags |= CAM_DIR_NONE;
629                         atio->sense_data = no_lun_sense_data;
630                         atio->sense_len = sizeof (no_lun_sense_data);
631                         descr->data_resid = 0;
632                         descr->data_increment = 0;
633                         descr->timeout = 5 * 1000;
634                         descr->status = SCSI_STATUS_CHECK_COND;
635                         break;
636                 }
637
638                 /* Queue us up to receive a Continue Target I/O ccb. */
639                 if ((atio->ccb_h.flags & CAM_DIS_DISCONNECT) != 0) {
640                         TAILQ_INSERT_HEAD(&softc->work_queue, &atio->ccb_h,
641                                           periph_links.tqe);
642                         priority = 0;
643                 } else {
644                         TAILQ_INSERT_TAIL(&softc->work_queue, &atio->ccb_h,
645                                           periph_links.tqe);
646                         priority = 1;
647                 }
648                 xpt_schedule(periph, priority);
649                 break;
650         }
651         case XPT_CONT_TARGET_IO:
652         {
653                 struct ccb_accept_tio *atio;
654                 struct targbh_cmd_desc *desc;
655
656                 CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
657                           ("Received completed CTIO\n"));
658                 atio = (struct ccb_accept_tio*)done_ccb->ccb_h.ccb_atio;
659                 desc = (struct targbh_cmd_desc *)atio->ccb_h.ccb_descr;
660
661                 TAILQ_REMOVE(&softc->pending_queue, &atio->ccb_h,
662                              periph_links.tqe);
663
664                 /*
665                  * We could check for CAM_SENT_SENSE bein set here,
666                  * but since we're not maintaining any CA/UA state,
667                  * there's no point.
668                  */
669                 atio->sense_len = 0;
670                 done_ccb->ccb_h.flags &= ~CAM_SEND_SENSE;
671                 done_ccb->ccb_h.status &= ~CAM_SENT_SENSE;
672
673                 /*
674                  * Any errors will not change the data we return,
675                  * so make sure the queue is not left frozen.
676                  * XXX - At some point there may be errors that
677                  *       leave us in a connected state with the
678                  *       initiator...
679                  */
680                 if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
681                         kprintf("Releasing Queue\n");
682                         cam_release_devq(done_ccb->ccb_h.path,
683                                          /*relsim_flags*/0,
684                                          /*reduction*/0,
685                                          /*timeout*/0,
686                                          /*getcount_only*/0); 
687                         done_ccb->ccb_h.status &= ~CAM_DEV_QFRZN;
688                 }
689                 desc->data_resid -= desc->data_increment;
690                 xpt_release_ccb(done_ccb);
691                 if (softc->state != TARGBH_STATE_TEARDOWN) {
692
693                         /*
694                          * Send the original accept TIO back to the
695                          * controller to handle more work.
696                          */
697                         CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
698                                   ("Returning ATIO to target\n"));
699                         /* Restore wildcards */
700                         atio->ccb_h.target_id = CAM_TARGET_WILDCARD;
701                         atio->ccb_h.target_lun = CAM_LUN_WILDCARD;
702                         xpt_action((union ccb *)atio);
703                         break;
704                 } else {
705                         targbhfreedescr(desc);
706                         kfree(atio, M_SCSIBH);
707                 }
708                 break;
709         }
710         case XPT_IMMED_NOTIFY:
711         {
712                 int frozen;
713
714                 frozen = (done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0;
715                 if (softc->state == TARGBH_STATE_TEARDOWN
716                  || done_ccb->ccb_h.status == CAM_REQ_ABORTED) {
717                         kprintf("Freed an immediate notify\n");
718                         xpt_free_ccb(done_ccb);
719                 } else {
720                         /* Requeue for another immediate event */
721                         xpt_action(done_ccb);
722                 }
723                 if (frozen != 0)
724                         cam_release_devq(periph->path,
725                                          /*relsim_flags*/0,
726                                          /*opening reduction*/0,
727                                          /*timeout*/0,
728                                          /*getcount_only*/0);
729                 break;
730         }
731         default:
732                 panic("targbhdone: Unexpected ccb opcode");
733                 break;
734         }
735 }
736
737 #ifdef NOTYET
738 static int
739 targbherror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags)
740 {
741         return 0;
742 }
743 #endif
744
745 static struct targbh_cmd_desc *
746 targbhallocdescr(void)
747 {
748         struct targbh_cmd_desc* descr;
749
750         /* Allocate the targbh_descr structure */
751         descr = kmalloc(sizeof(*descr), M_SCSIBH, M_INTWAIT | M_ZERO);
752
753         /* Allocate buffer backing store */
754         descr->backing_store = kmalloc(MAX_BUF_SIZE, M_SCSIBH, M_INTWAIT);
755         descr->max_size = MAX_BUF_SIZE;
756         return (descr);
757 }
758
759 static void
760 targbhfreedescr(struct targbh_cmd_desc *descr)
761 {
762         kfree(descr->backing_store, M_SCSIBH);
763         kfree(descr, M_SCSIBH);
764 }