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