The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/cam/scsi/scsi_targ_bh.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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 
   29 #include <sys/cdefs.h>
   30 __FBSDID("$FreeBSD: releng/6.2/sys/cam/scsi/scsi_targ_bh.c 147723 2005-07-01 15:21:30Z avatar $");
   31 
   32 #include <sys/param.h>
   33 #include <sys/queue.h>
   34 #include <sys/systm.h>
   35 #include <sys/kernel.h>
   36 #include <sys/types.h>
   37 #include <sys/bio.h>
   38 #include <sys/conf.h>
   39 #include <sys/devicestat.h>
   40 #include <sys/malloc.h>
   41 #include <sys/uio.h>
   42 
   43 #include <cam/cam.h>
   44 #include <cam/cam_ccb.h>
   45 #include <cam/cam_periph.h>
   46 #include <cam/cam_queue.h>
   47 #include <cam/cam_xpt_periph.h>
   48 #include <cam/cam_debug.h>
   49 
   50 #include <cam/scsi/scsi_all.h>
   51 #include <cam/scsi/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*/
  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
  155 targbhinit(void)
  156 {
  157         cam_status status;
  158         struct cam_path *path;
  159 
  160         /*
  161          * Install a global async callback.  This callback will
  162          * receive async callbacks like "new path registered".
  163          */
  164         status = xpt_create_path(&path, /*periph*/NULL, CAM_XPT_PATH_ID,
  165                                  CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD);
  166 
  167         if (status == CAM_REQ_CMP) {
  168                 struct ccb_setasync csa;
  169 
  170                 xpt_setup_ccb(&csa.ccb_h, path, /*priority*/5);
  171                 csa.ccb_h.func_code = XPT_SASYNC_CB;
  172                 csa.event_enable = AC_PATH_REGISTERED | AC_PATH_DEREGISTERED;
  173                 csa.callback = targbhasync;
  174                 csa.callback_arg = NULL;
  175                 xpt_action((union ccb *)&csa);
  176                 status = csa.ccb_h.status;
  177                 xpt_free_path(path);
  178         }
  179 
  180         if (status != CAM_REQ_CMP) {
  181                 printf("targbh: Failed to attach master async callback "
  182                        "due to status 0x%x!\n", status);
  183         }
  184 }
  185 
  186 static void
  187 targbhasync(void *callback_arg, u_int32_t code,
  188             struct cam_path *path, void *arg)
  189 {
  190         struct cam_path *new_path;
  191         struct ccb_pathinq *cpi;
  192         path_id_t bus_path_id;
  193         cam_status status;
  194 
  195         cpi = (struct ccb_pathinq *)arg;
  196         if (code == AC_PATH_REGISTERED)
  197                 bus_path_id = cpi->ccb_h.path_id;
  198         else
  199                 bus_path_id = xpt_path_path_id(path);
  200         /*
  201          * Allocate a peripheral instance for
  202          * this target instance.
  203          */
  204         status = xpt_create_path(&new_path, NULL,
  205                                  bus_path_id,
  206                                  CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD);
  207         if (status != CAM_REQ_CMP) {
  208                 printf("targbhasync: Unable to create path "
  209                         "due to status 0x%x\n", status);
  210                 return;
  211         }
  212 
  213         switch (code) {
  214         case AC_PATH_REGISTERED:
  215         {
  216                 /* Only attach to controllers that support target mode */
  217                 if ((cpi->target_sprt & PIT_PROCESSOR) == 0)
  218                         break;
  219 
  220                 status = cam_periph_alloc(targbhctor, NULL, targbhdtor,
  221                                           targbhstart,
  222                                           "targbh", CAM_PERIPH_BIO,
  223                                           new_path, targbhasync,
  224                                           AC_PATH_REGISTERED,
  225                                           cpi);
  226                 break;
  227         }
  228         case AC_PATH_DEREGISTERED:
  229         {
  230                 struct cam_periph *periph;
  231 
  232                 if ((periph = cam_periph_find(new_path, "targbh")) != NULL)
  233                         cam_periph_invalidate(periph);
  234                 break;
  235         }
  236         default:
  237                 break;
  238         }
  239         xpt_free_path(new_path);
  240 }
  241 
  242 /* Attempt to enable our lun */
  243 static cam_status
  244 targbhenlun(struct cam_periph *periph)
  245 {
  246         union ccb immed_ccb;
  247         struct targbh_softc *softc;
  248         cam_status status;
  249         int i;
  250 
  251         softc = (struct targbh_softc *)periph->softc;
  252 
  253         if ((softc->flags & TARGBH_FLAG_LUN_ENABLED) != 0)
  254                 return (CAM_REQ_CMP);
  255 
  256         xpt_setup_ccb(&immed_ccb.ccb_h, periph->path, /*priority*/1);
  257         immed_ccb.ccb_h.func_code = XPT_EN_LUN;
  258 
  259         /* Don't need support for any vendor specific commands */
  260         immed_ccb.cel.grp6_len = 0;
  261         immed_ccb.cel.grp7_len = 0;
  262         immed_ccb.cel.enable = 1;
  263         xpt_action(&immed_ccb);
  264         status = immed_ccb.ccb_h.status;
  265         if (status != CAM_REQ_CMP) {
  266                 xpt_print_path(periph->path);
  267                 printf("targbhenlun - Enable Lun Rejected with status 0x%x\n",
  268                        status);
  269                 return (status);
  270         }
  271         
  272         softc->flags |= TARGBH_FLAG_LUN_ENABLED;
  273 
  274         /*
  275          * Build up a buffer of accept target I/O
  276          * operations for incoming selections.
  277          */
  278         for (i = 0; i < MAX_ACCEPT; i++) {
  279                 struct ccb_accept_tio *atio;
  280 
  281                 atio = (struct ccb_accept_tio*)malloc(sizeof(*atio), M_SCSIBH,
  282                                                       M_NOWAIT);
  283                 if (atio == NULL) {
  284                         status = CAM_RESRC_UNAVAIL;
  285                         break;
  286                 }
  287 
  288                 atio->ccb_h.ccb_descr = targbhallocdescr();
  289 
  290                 if (atio->ccb_h.ccb_descr == NULL) {
  291                         free(atio, M_SCSIBH);
  292                         status = CAM_RESRC_UNAVAIL;
  293                         break;
  294                 }
  295 
  296                 xpt_setup_ccb(&atio->ccb_h, periph->path, /*priority*/1);
  297                 atio->ccb_h.func_code = XPT_ACCEPT_TARGET_IO;
  298                 atio->ccb_h.cbfcnp = targbhdone;
  299                 xpt_action((union ccb *)atio);
  300                 status = atio->ccb_h.status;
  301                 if (status != CAM_REQ_INPROG) {
  302                         targbhfreedescr(atio->ccb_h.ccb_descr);
  303                         free(atio, M_SCSIBH);
  304                         break;
  305                 }
  306                 ((struct targbh_cmd_desc*)atio->ccb_h.ccb_descr)->atio_link =
  307                     softc->accept_tio_list;
  308                 softc->accept_tio_list = atio;
  309         }
  310 
  311         if (i == 0) {
  312                 xpt_print_path(periph->path);
  313                 printf("targbhenlun - Could not allocate accept tio CCBs: "
  314                        "status = 0x%x\n", status);
  315                 targbhdislun(periph);
  316                 return (CAM_REQ_CMP_ERR);
  317         }
  318 
  319         /*
  320          * Build up a buffer of immediate notify CCBs
  321          * so the SIM can tell us of asynchronous target mode events.
  322          */
  323         for (i = 0; i < MAX_ACCEPT; i++) {
  324                 struct ccb_immed_notify *inot;
  325 
  326                 inot = (struct ccb_immed_notify*)malloc(sizeof(*inot), M_SCSIBH,
  327                                                         M_NOWAIT);
  328 
  329                 if (inot == NULL) {
  330                         status = CAM_RESRC_UNAVAIL;
  331                         break;
  332                 }
  333 
  334                 xpt_setup_ccb(&inot->ccb_h, periph->path, /*priority*/1);
  335                 inot->ccb_h.func_code = XPT_IMMED_NOTIFY;
  336                 inot->ccb_h.cbfcnp = targbhdone;
  337                 xpt_action((union ccb *)inot);
  338                 status = inot->ccb_h.status;
  339                 if (status != CAM_REQ_INPROG) {
  340                         free(inot, M_SCSIBH);
  341                         break;
  342                 }
  343                 SLIST_INSERT_HEAD(&softc->immed_notify_slist, &inot->ccb_h,
  344                                   periph_links.sle);
  345         }
  346 
  347         if (i == 0) {
  348                 xpt_print_path(periph->path);
  349                 printf("targbhenlun - Could not allocate immediate notify "
  350                        "CCBs: status = 0x%x\n", status);
  351                 targbhdislun(periph);
  352                 return (CAM_REQ_CMP_ERR);
  353         }
  354 
  355         return (CAM_REQ_CMP);
  356 }
  357 
  358 static cam_status
  359 targbhdislun(struct cam_periph *periph)
  360 {
  361         union ccb ccb;
  362         struct targbh_softc *softc;
  363         struct ccb_accept_tio* atio;
  364         struct ccb_hdr *ccb_h;
  365 
  366         softc = (struct targbh_softc *)periph->softc;
  367         if ((softc->flags & TARGBH_FLAG_LUN_ENABLED) == 0)
  368                 return CAM_REQ_CMP;
  369 
  370         /* XXX Block for Continue I/O completion */
  371 
  372         /* Kill off all ACCECPT and IMMEDIATE CCBs */
  373         while ((atio = softc->accept_tio_list) != NULL) {
  374                 
  375                 softc->accept_tio_list =
  376                     ((struct targbh_cmd_desc*)atio->ccb_h.ccb_descr)->atio_link;
  377                 xpt_setup_ccb(&ccb.cab.ccb_h, periph->path, /*priority*/1);
  378                 ccb.cab.ccb_h.func_code = XPT_ABORT;
  379                 ccb.cab.abort_ccb = (union ccb *)atio;
  380                 xpt_action(&ccb);
  381         }
  382 
  383         while ((ccb_h = SLIST_FIRST(&softc->immed_notify_slist)) != NULL) {
  384                 SLIST_REMOVE_HEAD(&softc->immed_notify_slist, periph_links.sle);
  385                 xpt_setup_ccb(&ccb.cab.ccb_h, periph->path, /*priority*/1);
  386                 ccb.cab.ccb_h.func_code = XPT_ABORT;
  387                 ccb.cab.abort_ccb = (union ccb *)ccb_h;
  388                 xpt_action(&ccb);
  389         }
  390 
  391         /*
  392          * Dissable this lun.
  393          */
  394         xpt_setup_ccb(&ccb.cel.ccb_h, periph->path, /*priority*/1);
  395         ccb.cel.ccb_h.func_code = XPT_EN_LUN;
  396         ccb.cel.enable = 0;
  397         xpt_action(&ccb);
  398 
  399         if (ccb.cel.ccb_h.status != CAM_REQ_CMP)
  400                 printf("targbhdislun - Disabling lun on controller failed "
  401                        "with status 0x%x\n", ccb.cel.ccb_h.status);
  402         else 
  403                 softc->flags &= ~TARGBH_FLAG_LUN_ENABLED;
  404         return (ccb.cel.ccb_h.status);
  405 }
  406 
  407 static cam_status
  408 targbhctor(struct cam_periph *periph, void *arg)
  409 {
  410         struct targbh_softc *softc;
  411 
  412         /* Allocate our per-instance private storage */
  413         softc = (struct targbh_softc *)malloc(sizeof(*softc),
  414                                               M_SCSIBH, M_NOWAIT);
  415         if (softc == NULL) {
  416                 printf("targctor: unable to malloc softc\n");
  417                 return (CAM_REQ_CMP_ERR);
  418         }
  419 
  420         bzero(softc, sizeof(*softc));
  421         TAILQ_INIT(&softc->pending_queue);
  422         TAILQ_INIT(&softc->work_queue);
  423         softc->accept_tio_list = NULL;
  424         SLIST_INIT(&softc->immed_notify_slist);
  425         softc->state = TARGBH_STATE_NORMAL;
  426         periph->softc = softc;
  427         softc->init_level++;
  428 
  429         return (targbhenlun(periph));
  430 }
  431 
  432 static void
  433 targbhdtor(struct cam_periph *periph)
  434 {
  435         struct targbh_softc *softc;
  436 
  437         softc = (struct targbh_softc *)periph->softc;
  438 
  439         softc->state = TARGBH_STATE_TEARDOWN;
  440 
  441         targbhdislun(periph);
  442 
  443         switch (softc->init_level) {
  444         case 0:
  445                 panic("targdtor - impossible init level");;
  446         case 1:
  447                 /* FALLTHROUGH */
  448         default:
  449                 /* XXX Wait for callback of targbhdislun() */
  450                 tsleep(softc, PRIBIO, "targbh", hz/2);
  451                 free(softc, M_SCSIBH);
  452                 break;
  453         }
  454 }
  455 
  456 static void
  457 targbhstart(struct cam_periph *periph, union ccb *start_ccb)
  458 {
  459         struct targbh_softc *softc;
  460         struct ccb_hdr *ccbh;
  461         struct ccb_accept_tio *atio;
  462         struct targbh_cmd_desc *desc;
  463         struct ccb_scsiio *csio;
  464         ccb_flags flags;
  465         int    s;
  466 
  467         softc = (struct targbh_softc *)periph->softc;
  468         
  469         s = splbio();
  470         ccbh = TAILQ_FIRST(&softc->work_queue);
  471         if (periph->immediate_priority <= periph->pinfo.priority) {
  472                 start_ccb->ccb_h.ccb_type = TARGBH_CCB_WAITING;                 
  473                 SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h,
  474                                   periph_links.sle);
  475                 periph->immediate_priority = CAM_PRIORITY_NONE;
  476                 splx(s);
  477                 wakeup(&periph->ccb_list);
  478         } else if (ccbh == NULL) {
  479                 splx(s);
  480                 xpt_release_ccb(start_ccb);     
  481         } else {
  482                 TAILQ_REMOVE(&softc->work_queue, ccbh, periph_links.tqe);
  483                 TAILQ_INSERT_HEAD(&softc->pending_queue, ccbh,
  484                                   periph_links.tqe);
  485                 splx(s);        
  486                 atio = (struct ccb_accept_tio*)ccbh;
  487                 desc = (struct targbh_cmd_desc *)atio->ccb_h.ccb_descr;
  488 
  489                 /* Is this a tagged request? */
  490                 flags = atio->ccb_h.flags &
  491                     (CAM_DIS_DISCONNECT|CAM_TAG_ACTION_VALID|CAM_DIR_MASK);
  492 
  493                 csio = &start_ccb->csio;
  494                 /*
  495                  * If we are done with the transaction, tell the
  496                  * controller to send status and perform a CMD_CMPLT.
  497                  * If we have associated sense data, see if we can
  498                  * send that too.
  499                  */
  500                 if (desc->data_resid == desc->data_increment) {
  501                         flags |= CAM_SEND_STATUS;
  502                         if (atio->sense_len) {
  503                                 csio->sense_len = atio->sense_len;
  504                                 csio->sense_data = atio->sense_data;
  505                                 flags |= CAM_SEND_SENSE;
  506                         }
  507 
  508                 }
  509 
  510                 cam_fill_ctio(csio,
  511                               /*retries*/2,
  512                               targbhdone,
  513                               flags,
  514                               (flags & CAM_TAG_ACTION_VALID)?
  515                                 MSG_SIMPLE_Q_TAG : 0,
  516                               atio->tag_id,
  517                               atio->init_id,
  518                               desc->status,
  519                               /*data_ptr*/desc->data_increment == 0
  520                                           ? NULL : desc->data,
  521                               /*dxfer_len*/desc->data_increment,
  522                               /*timeout*/desc->timeout);
  523 
  524                 /* Override our wildcard attachment */
  525                 start_ccb->ccb_h.target_id = atio->ccb_h.target_id;
  526                 start_ccb->ccb_h.target_lun = atio->ccb_h.target_lun;
  527 
  528                 start_ccb->ccb_h.ccb_type = TARGBH_CCB_WORKQ;
  529                 start_ccb->ccb_h.ccb_atio = atio;
  530                 CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
  531                           ("Sending a CTIO\n"));
  532                 xpt_action(start_ccb);
  533                 /*
  534                  * If the queue was frozen waiting for the response
  535                  * to this ATIO (for instance disconnection was disallowed),
  536                  * then release it now that our response has been queued.
  537                  */
  538                 if ((atio->ccb_h.status & CAM_DEV_QFRZN) != 0) {
  539                         cam_release_devq(periph->path,
  540                                          /*relsim_flags*/0,
  541                                          /*reduction*/0,
  542                                          /*timeout*/0,
  543                                          /*getcount_only*/0); 
  544                         atio->ccb_h.status &= ~CAM_DEV_QFRZN;
  545                 }
  546                 s = splbio();
  547                 ccbh = TAILQ_FIRST(&softc->work_queue);
  548                 splx(s);
  549         }
  550         if (ccbh != NULL)
  551                 xpt_schedule(periph, /*priority*/1);
  552 }
  553 
  554 static void
  555 targbhdone(struct cam_periph *periph, union ccb *done_ccb)
  556 {
  557         struct targbh_softc *softc;
  558 
  559         softc = (struct targbh_softc *)periph->softc;
  560 
  561         if (done_ccb->ccb_h.ccb_type == TARGBH_CCB_WAITING) {
  562                 /* Caller will release the CCB */
  563                 wakeup(&done_ccb->ccb_h.cbfcnp);
  564                 return;
  565         }
  566 
  567         switch (done_ccb->ccb_h.func_code) {
  568         case XPT_ACCEPT_TARGET_IO:
  569         {
  570                 struct ccb_accept_tio *atio;
  571                 struct targbh_cmd_desc *descr;
  572                 u_int8_t *cdb;
  573                 int priority;
  574 
  575                 atio = &done_ccb->atio;
  576                 descr = (struct targbh_cmd_desc*)atio->ccb_h.ccb_descr;
  577                 cdb = atio->cdb_io.cdb_bytes;
  578                 if (softc->state == TARGBH_STATE_TEARDOWN
  579                  || atio->ccb_h.status == CAM_REQ_ABORTED) {
  580                         targbhfreedescr(descr);
  581                         xpt_free_ccb(done_ccb);
  582                         return;
  583                 }
  584 
  585                 /*
  586                  * Determine the type of incoming command and
  587                  * setup our buffer for a response.
  588                  */
  589                 switch (cdb[0]) {
  590                 case INQUIRY:
  591                 {
  592                         struct scsi_inquiry *inq;
  593 
  594                         inq = (struct scsi_inquiry *)cdb;
  595                         CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
  596                                   ("Saw an inquiry!\n"));
  597                         /*
  598                          * Validate the command.  We don't
  599                          * support any VPD pages, so complain
  600                          * if EVPD is set.
  601                          */
  602                         if ((inq->byte2 & SI_EVPD) != 0
  603                          || inq->page_code != 0) {
  604                                 atio->ccb_h.flags &= ~CAM_DIR_MASK;
  605                                 atio->ccb_h.flags |= CAM_DIR_NONE;
  606                                 /*
  607                                  * This needs to have other than a
  608                                  * no_lun_sense_data response.
  609                                  */
  610                                 atio->sense_data = no_lun_sense_data;
  611                                 atio->sense_len = sizeof(no_lun_sense_data);
  612                                 descr->data_resid = 0;
  613                                 descr->data_increment = 0;
  614                                 descr->status = SCSI_STATUS_CHECK_COND;
  615                                 break;
  616                         }
  617                         /*
  618                          * Direction is always relative
  619                          * to the initator.
  620                          */
  621                         atio->ccb_h.flags &= ~CAM_DIR_MASK;
  622                         atio->ccb_h.flags |= CAM_DIR_IN;
  623                         descr->data = &no_lun_inq_data;
  624                         descr->data_resid = MIN(sizeof(no_lun_inq_data),
  625                                                 SCSI_CDB6_LEN(inq->length));
  626                         descr->data_increment = descr->data_resid;
  627                         descr->timeout = 5 * 1000;
  628                         descr->status = SCSI_STATUS_OK;
  629                         break;
  630                 }
  631                 case REQUEST_SENSE:
  632                 {
  633                         struct scsi_request_sense *rsense;
  634 
  635                         rsense = (struct scsi_request_sense *)cdb;
  636                         /* Refer to static sense data */
  637                         atio->ccb_h.flags &= ~CAM_DIR_MASK;
  638                         atio->ccb_h.flags |= CAM_DIR_IN;
  639                         descr->data = &no_lun_sense_data;
  640                         descr->data_resid = request_sense_size;
  641                         descr->data_resid = MIN(descr->data_resid,
  642                                                 SCSI_CDB6_LEN(rsense->length));
  643                         descr->data_increment = descr->data_resid;
  644                         descr->timeout = 5 * 1000;
  645                         descr->status = SCSI_STATUS_OK;
  646                         break;
  647                 }
  648                 default:
  649                         /* Constant CA, tell initiator */
  650                         /* Direction is always relative to the initator */
  651                         atio->ccb_h.flags &= ~CAM_DIR_MASK;
  652                         atio->ccb_h.flags |= CAM_DIR_NONE;
  653                         atio->sense_data = no_lun_sense_data;
  654                         atio->sense_len = sizeof (no_lun_sense_data);
  655                         descr->data_resid = 0;
  656                         descr->data_increment = 0;
  657                         descr->timeout = 5 * 1000;
  658                         descr->status = SCSI_STATUS_CHECK_COND;
  659                         break;
  660                 }
  661 
  662                 /* Queue us up to receive a Continue Target I/O ccb. */
  663                 if ((atio->ccb_h.flags & CAM_DIS_DISCONNECT) != 0) {
  664                         TAILQ_INSERT_HEAD(&softc->work_queue, &atio->ccb_h,
  665                                           periph_links.tqe);
  666                         priority = 0;
  667                 } else {
  668                         TAILQ_INSERT_TAIL(&softc->work_queue, &atio->ccb_h,
  669                                           periph_links.tqe);
  670                         priority = 1;
  671                 }
  672                 xpt_schedule(periph, priority);
  673                 break;
  674         }
  675         case XPT_CONT_TARGET_IO:
  676         {
  677                 struct ccb_accept_tio *atio;
  678                 struct targbh_cmd_desc *desc;
  679 
  680                 CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
  681                           ("Received completed CTIO\n"));
  682                 atio = (struct ccb_accept_tio*)done_ccb->ccb_h.ccb_atio;
  683                 desc = (struct targbh_cmd_desc *)atio->ccb_h.ccb_descr;
  684 
  685                 TAILQ_REMOVE(&softc->pending_queue, &atio->ccb_h,
  686                              periph_links.tqe);
  687 
  688                 /*
  689                  * We could check for CAM_SENT_SENSE bein set here,
  690                  * but since we're not maintaining any CA/UA state,
  691                  * there's no point.
  692                  */
  693                 atio->sense_len = 0;
  694                 done_ccb->ccb_h.flags &= ~CAM_SEND_SENSE;
  695                 done_ccb->ccb_h.status &= ~CAM_SENT_SENSE;
  696 
  697                 /*
  698                  * Any errors will not change the data we return,
  699                  * so make sure the queue is not left frozen.
  700                  * XXX - At some point there may be errors that
  701                  *       leave us in a connected state with the
  702                  *       initiator...
  703                  */
  704                 if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
  705                         printf("Releasing Queue\n");
  706                         cam_release_devq(done_ccb->ccb_h.path,
  707                                          /*relsim_flags*/0,
  708                                          /*reduction*/0,
  709                                          /*timeout*/0,
  710                                          /*getcount_only*/0); 
  711                         done_ccb->ccb_h.status &= ~CAM_DEV_QFRZN;
  712                 }
  713                 desc->data_resid -= desc->data_increment;
  714                 xpt_release_ccb(done_ccb);
  715                 if (softc->state != TARGBH_STATE_TEARDOWN) {
  716 
  717                         /*
  718                          * Send the original accept TIO back to the
  719                          * controller to handle more work.
  720                          */
  721                         CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
  722                                   ("Returning ATIO to target\n"));
  723                         /* Restore wildcards */
  724                         atio->ccb_h.target_id = CAM_TARGET_WILDCARD;
  725                         atio->ccb_h.target_lun = CAM_LUN_WILDCARD;
  726                         xpt_action((union ccb *)atio);
  727                         break;
  728                 } else {
  729                         targbhfreedescr(desc);
  730                         free(atio, M_SCSIBH);
  731                 }
  732                 break;
  733         }
  734         case XPT_IMMED_NOTIFY:
  735         {
  736                 int frozen;
  737 
  738                 frozen = (done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0;
  739                 if (softc->state == TARGBH_STATE_TEARDOWN
  740                  || done_ccb->ccb_h.status == CAM_REQ_ABORTED) {
  741                         printf("Freed an immediate notify\n");
  742                         xpt_free_ccb(done_ccb);
  743                 } else {
  744                         /* Requeue for another immediate event */
  745                         xpt_action(done_ccb);
  746                 }
  747                 if (frozen != 0)
  748                         cam_release_devq(periph->path,
  749                                          /*relsim_flags*/0,
  750                                          /*opening reduction*/0,
  751                                          /*timeout*/0,
  752                                          /*getcount_only*/0);
  753                 break;
  754         }
  755         default:
  756                 panic("targbhdone: Unexpected ccb opcode");
  757                 break;
  758         }
  759 }
  760 
  761 #ifdef NOTYET
  762 static int
  763 targbherror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags)
  764 {
  765         return 0;
  766 }
  767 #endif
  768 
  769 static struct targbh_cmd_desc*
  770 targbhallocdescr()
  771 {
  772         struct targbh_cmd_desc* descr;
  773 
  774         /* Allocate the targbh_descr structure */
  775         descr = (struct targbh_cmd_desc *)malloc(sizeof(*descr),
  776                                                M_SCSIBH, M_NOWAIT);
  777         if (descr == NULL)
  778                 return (NULL);
  779 
  780         bzero(descr, sizeof(*descr));
  781 
  782         /* Allocate buffer backing store */
  783         descr->backing_store = malloc(MAX_BUF_SIZE, M_SCSIBH, M_NOWAIT);
  784         if (descr->backing_store == NULL) {
  785                 free(descr, M_SCSIBH);
  786                 return (NULL);
  787         }
  788         descr->max_size = MAX_BUF_SIZE;
  789         return (descr);
  790 }
  791 
  792 static void
  793 targbhfreedescr(struct targbh_cmd_desc *descr)
  794 {
  795         free(descr->backing_store, M_SCSIBH);
  796         free(descr, M_SCSIBH);
  797 }

Cache object: b011ce33a8ae9691fe33412fab4c619e


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.