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

Cache object: d24d60826af0e2249a00f7ed74dd98f5


[ 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.