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         xpt_setup_ccb(&immed_ccb.ccb_h, periph->path, CAM_PRIORITY_NORMAL);
  245         immed_ccb.ccb_h.func_code = XPT_EN_LUN;
  246 
  247         /* Don't need support for any vendor specific commands */
  248         immed_ccb.cel.grp6_len = 0;
  249         immed_ccb.cel.grp7_len = 0;
  250         immed_ccb.cel.enable = 1;
  251         xpt_action(&immed_ccb);
  252         status = immed_ccb.ccb_h.status;
  253         if (status != CAM_REQ_CMP) {
  254                 xpt_print(periph->path,
  255                     "targbhenlun - Enable Lun Rejected with status 0x%x\n",
  256                     status);
  257                 return (status);
  258         }
  259         
  260         softc->flags |= TARGBH_FLAG_LUN_ENABLED;
  261 
  262         /*
  263          * Build up a buffer of accept target I/O
  264          * operations for incoming selections.
  265          */
  266         for (i = 0; i < MAX_ACCEPT; i++) {
  267                 struct ccb_accept_tio *atio;
  268 
  269                 atio = (struct ccb_accept_tio*)malloc(sizeof(*atio), M_SCSIBH,
  270                                                       M_NOWAIT);
  271                 if (atio == NULL) {
  272                         status = CAM_RESRC_UNAVAIL;
  273                         break;
  274                 }
  275 
  276                 atio->ccb_h.ccb_descr = targbhallocdescr();
  277 
  278                 if (atio->ccb_h.ccb_descr == NULL) {
  279                         free(atio, M_SCSIBH);
  280                         status = CAM_RESRC_UNAVAIL;
  281                         break;
  282                 }
  283 
  284                 xpt_setup_ccb(&atio->ccb_h, periph->path, CAM_PRIORITY_NORMAL);
  285                 atio->ccb_h.func_code = XPT_ACCEPT_TARGET_IO;
  286                 atio->ccb_h.cbfcnp = targbhdone;
  287                 ((struct targbh_cmd_desc*)atio->ccb_h.ccb_descr)->atio_link =
  288                     softc->accept_tio_list;
  289                 softc->accept_tio_list = atio;
  290                 xpt_action((union ccb *)atio);
  291                 status = atio->ccb_h.status;
  292                 if (status != CAM_REQ_INPROG)
  293                         break;
  294         }
  295 
  296         if (i == 0) {
  297                 xpt_print(periph->path,
  298                     "targbhenlun - Could not allocate accept tio CCBs: status "
  299                     "= 0x%x\n", status);
  300                 targbhdislun(periph);
  301                 return (CAM_REQ_CMP_ERR);
  302         }
  303 
  304         /*
  305          * Build up a buffer of immediate notify CCBs
  306          * so the SIM can tell us of asynchronous target mode events.
  307          */
  308         for (i = 0; i < MAX_ACCEPT; i++) {
  309                 struct ccb_immediate_notify *inot;
  310 
  311                 inot = (struct ccb_immediate_notify*)malloc(sizeof(*inot),
  312                             M_SCSIBH, M_NOWAIT);
  313 
  314                 if (inot == NULL) {
  315                         status = CAM_RESRC_UNAVAIL;
  316                         break;
  317                 }
  318 
  319                 xpt_setup_ccb(&inot->ccb_h, periph->path, CAM_PRIORITY_NORMAL);
  320                 inot->ccb_h.func_code = XPT_IMMEDIATE_NOTIFY;
  321                 inot->ccb_h.cbfcnp = targbhdone;
  322                 SLIST_INSERT_HEAD(&softc->immed_notify_slist, &inot->ccb_h,
  323                                   periph_links.sle);
  324                 xpt_action((union ccb *)inot);
  325                 status = inot->ccb_h.status;
  326                 if (status != CAM_REQ_INPROG)
  327                         break;
  328         }
  329 
  330         if (i == 0) {
  331                 xpt_print(periph->path,
  332                     "targbhenlun - Could not allocate immediate notify "
  333                     "CCBs: status = 0x%x\n", status);
  334                 targbhdislun(periph);
  335                 return (CAM_REQ_CMP_ERR);
  336         }
  337 
  338         return (CAM_REQ_CMP);
  339 }
  340 
  341 static cam_status
  342 targbhdislun(struct cam_periph *periph)
  343 {
  344         union ccb ccb;
  345         struct targbh_softc *softc;
  346         struct ccb_accept_tio* atio;
  347         struct ccb_hdr *ccb_h;
  348 
  349         softc = (struct targbh_softc *)periph->softc;
  350         if ((softc->flags & TARGBH_FLAG_LUN_ENABLED) == 0)
  351                 return CAM_REQ_CMP;
  352 
  353         /* XXX Block for Continue I/O completion */
  354 
  355         /* Kill off all ACCECPT and IMMEDIATE CCBs */
  356         while ((atio = softc->accept_tio_list) != NULL) {
  357                 
  358                 softc->accept_tio_list =
  359                     ((struct targbh_cmd_desc*)atio->ccb_h.ccb_descr)->atio_link;
  360                 xpt_setup_ccb(&ccb.cab.ccb_h, periph->path, CAM_PRIORITY_NORMAL);
  361                 ccb.cab.ccb_h.func_code = XPT_ABORT;
  362                 ccb.cab.abort_ccb = (union ccb *)atio;
  363                 xpt_action(&ccb);
  364         }
  365 
  366         while ((ccb_h = SLIST_FIRST(&softc->immed_notify_slist)) != NULL) {
  367                 SLIST_REMOVE_HEAD(&softc->immed_notify_slist, periph_links.sle);
  368                 xpt_setup_ccb(&ccb.cab.ccb_h, periph->path, CAM_PRIORITY_NORMAL);
  369                 ccb.cab.ccb_h.func_code = XPT_ABORT;
  370                 ccb.cab.abort_ccb = (union ccb *)ccb_h;
  371                 xpt_action(&ccb);
  372         }
  373 
  374         /*
  375          * Dissable this lun.
  376          */
  377         xpt_setup_ccb(&ccb.cel.ccb_h, periph->path, CAM_PRIORITY_NORMAL);
  378         ccb.cel.ccb_h.func_code = XPT_EN_LUN;
  379         ccb.cel.enable = 0;
  380         xpt_action(&ccb);
  381 
  382         if (ccb.cel.ccb_h.status != CAM_REQ_CMP)
  383                 printf("targbhdislun - Disabling lun on controller failed "
  384                        "with status 0x%x\n", ccb.cel.ccb_h.status);
  385         else 
  386                 softc->flags &= ~TARGBH_FLAG_LUN_ENABLED;
  387         return (ccb.cel.ccb_h.status);
  388 }
  389 
  390 static cam_status
  391 targbhctor(struct cam_periph *periph, void *arg)
  392 {
  393         struct targbh_softc *softc;
  394 
  395         /* Allocate our per-instance private storage */
  396         softc = (struct targbh_softc *)malloc(sizeof(*softc),
  397                                               M_SCSIBH, M_NOWAIT);
  398         if (softc == NULL) {
  399                 printf("targctor: unable to malloc softc\n");
  400                 return (CAM_REQ_CMP_ERR);
  401         }
  402 
  403         bzero(softc, sizeof(*softc));
  404         TAILQ_INIT(&softc->pending_queue);
  405         TAILQ_INIT(&softc->work_queue);
  406         softc->accept_tio_list = NULL;
  407         SLIST_INIT(&softc->immed_notify_slist);
  408         softc->state = TARGBH_STATE_NORMAL;
  409         periph->softc = softc;
  410         softc->init_level++;
  411 
  412         if (targbhenlun(periph) != CAM_REQ_CMP)
  413                 cam_periph_invalidate(periph);
  414         return (CAM_REQ_CMP);
  415 }
  416 
  417 static void
  418 targbhdtor(struct cam_periph *periph)
  419 {
  420         struct targbh_softc *softc;
  421 
  422         softc = (struct targbh_softc *)periph->softc;
  423 
  424         softc->state = TARGBH_STATE_TEARDOWN;
  425 
  426         targbhdislun(periph);
  427 
  428         switch (softc->init_level) {
  429         case 0:
  430                 panic("targdtor - impossible init level");
  431         case 1:
  432                 /* FALLTHROUGH */
  433         default:
  434                 /* XXX Wait for callback of targbhdislun() */
  435                 cam_periph_sleep(periph, softc, PRIBIO, "targbh", hz/2);
  436                 free(softc, M_SCSIBH);
  437                 break;
  438         }
  439 }
  440 
  441 static void
  442 targbhstart(struct cam_periph *periph, union ccb *start_ccb)
  443 {
  444         struct targbh_softc *softc;
  445         struct ccb_hdr *ccbh;
  446         struct ccb_accept_tio *atio;
  447         struct targbh_cmd_desc *desc;
  448         struct ccb_scsiio *csio;
  449         ccb_flags flags;
  450 
  451         softc = (struct targbh_softc *)periph->softc;
  452         
  453         ccbh = TAILQ_FIRST(&softc->work_queue);
  454         if (ccbh == NULL) {
  455                 xpt_release_ccb(start_ccb);     
  456         } else {
  457                 TAILQ_REMOVE(&softc->work_queue, ccbh, periph_links.tqe);
  458                 TAILQ_INSERT_HEAD(&softc->pending_queue, ccbh,
  459                                   periph_links.tqe);
  460                 atio = (struct ccb_accept_tio*)ccbh;
  461                 desc = (struct targbh_cmd_desc *)atio->ccb_h.ccb_descr;
  462 
  463                 /* Is this a tagged request? */
  464                 flags = atio->ccb_h.flags &
  465                     (CAM_DIS_DISCONNECT|CAM_TAG_ACTION_VALID|CAM_DIR_MASK);
  466 
  467                 csio = &start_ccb->csio;
  468                 /*
  469                  * If we are done with the transaction, tell the
  470                  * controller to send status and perform a CMD_CMPLT.
  471                  * If we have associated sense data, see if we can
  472                  * send that too.
  473                  */
  474                 if (desc->data_resid == desc->data_increment) {
  475                         flags |= CAM_SEND_STATUS;
  476                         if (atio->sense_len) {
  477                                 csio->sense_len = atio->sense_len;
  478                                 csio->sense_data = atio->sense_data;
  479                                 flags |= CAM_SEND_SENSE;
  480                         }
  481 
  482                 }
  483 
  484                 cam_fill_ctio(csio,
  485                               /*retries*/2,
  486                               targbhdone,
  487                               flags,
  488                               (flags & CAM_TAG_ACTION_VALID)?
  489                                 MSG_SIMPLE_Q_TAG : 0,
  490                               atio->tag_id,
  491                               atio->init_id,
  492                               desc->status,
  493                               /*data_ptr*/desc->data_increment == 0
  494                                           ? NULL : desc->data,
  495                               /*dxfer_len*/desc->data_increment,
  496                               /*timeout*/desc->timeout);
  497 
  498                 /* Override our wildcard attachment */
  499                 start_ccb->ccb_h.target_id = atio->ccb_h.target_id;
  500                 start_ccb->ccb_h.target_lun = atio->ccb_h.target_lun;
  501 
  502                 start_ccb->ccb_h.ccb_type = TARGBH_CCB_WORKQ;
  503                 start_ccb->ccb_h.ccb_atio = atio;
  504                 CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
  505                           ("Sending a CTIO\n"));
  506                 xpt_action(start_ccb);
  507                 /*
  508                  * If the queue was frozen waiting for the response
  509                  * to this ATIO (for instance disconnection was disallowed),
  510                  * then release it now that our response has been queued.
  511                  */
  512                 if ((atio->ccb_h.status & CAM_DEV_QFRZN) != 0) {
  513                         cam_release_devq(periph->path,
  514                                          /*relsim_flags*/0,
  515                                          /*reduction*/0,
  516                                          /*timeout*/0,
  517                                          /*getcount_only*/0); 
  518                         atio->ccb_h.status &= ~CAM_DEV_QFRZN;
  519                 }
  520                 ccbh = TAILQ_FIRST(&softc->work_queue);
  521         }
  522         if (ccbh != NULL)
  523                 xpt_schedule(periph, CAM_PRIORITY_NORMAL);
  524 }
  525 
  526 static void
  527 targbhdone(struct cam_periph *periph, union ccb *done_ccb)
  528 {
  529         struct targbh_softc *softc;
  530 
  531         softc = (struct targbh_softc *)periph->softc;
  532 
  533         switch (done_ccb->ccb_h.func_code) {
  534         case XPT_ACCEPT_TARGET_IO:
  535         {
  536                 struct ccb_accept_tio *atio;
  537                 struct targbh_cmd_desc *descr;
  538                 u_int8_t *cdb;
  539                 int priority;
  540 
  541                 atio = &done_ccb->atio;
  542                 descr = (struct targbh_cmd_desc*)atio->ccb_h.ccb_descr;
  543                 cdb = atio->cdb_io.cdb_bytes;
  544                 if (softc->state == TARGBH_STATE_TEARDOWN
  545                  || atio->ccb_h.status == CAM_REQ_ABORTED) {
  546                         targbhfreedescr(descr);
  547                         xpt_free_ccb(done_ccb);
  548                         return;
  549                 }
  550 
  551                 /*
  552                  * Determine the type of incoming command and
  553                  * setup our buffer for a response.
  554                  */
  555                 switch (cdb[0]) {
  556                 case INQUIRY:
  557                 {
  558                         struct scsi_inquiry *inq;
  559 
  560                         inq = (struct scsi_inquiry *)cdb;
  561                         CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
  562                                   ("Saw an inquiry!\n"));
  563                         /*
  564                          * Validate the command.  We don't
  565                          * support any VPD pages, so complain
  566                          * if EVPD is set.
  567                          */
  568                         if ((inq->byte2 & SI_EVPD) != 0
  569                          || inq->page_code != 0) {
  570                                 atio->ccb_h.flags &= ~CAM_DIR_MASK;
  571                                 atio->ccb_h.flags |= CAM_DIR_NONE;
  572                                 /*
  573                                  * This needs to have other than a
  574                                  * no_lun_sense_data response.
  575                                  */
  576                                 bcopy(&no_lun_sense_data, &atio->sense_data,
  577                                       min(sizeof(no_lun_sense_data),
  578                                           sizeof(atio->sense_data)));
  579                                 atio->sense_len = sizeof(no_lun_sense_data);
  580                                 descr->data_resid = 0;
  581                                 descr->data_increment = 0;
  582                                 descr->status = SCSI_STATUS_CHECK_COND;
  583                                 break;
  584                         }
  585                         /*
  586                          * Direction is always relative
  587                          * to the initator.
  588                          */
  589                         atio->ccb_h.flags &= ~CAM_DIR_MASK;
  590                         atio->ccb_h.flags |= CAM_DIR_IN;
  591                         descr->data = &no_lun_inq_data;
  592                         descr->data_resid = MIN(sizeof(no_lun_inq_data),
  593                                                 scsi_2btoul(inq->length));
  594                         descr->data_increment = descr->data_resid;
  595                         descr->timeout = 5 * 1000;
  596                         descr->status = SCSI_STATUS_OK;
  597                         break;
  598                 }
  599                 case REQUEST_SENSE:
  600                 {
  601                         struct scsi_request_sense *rsense;
  602 
  603                         rsense = (struct scsi_request_sense *)cdb;
  604                         /* Refer to static sense data */
  605                         atio->ccb_h.flags &= ~CAM_DIR_MASK;
  606                         atio->ccb_h.flags |= CAM_DIR_IN;
  607                         descr->data = &no_lun_sense_data;
  608                         descr->data_resid = request_sense_size;
  609                         descr->data_resid = MIN(descr->data_resid,
  610                                                 SCSI_CDB6_LEN(rsense->length));
  611                         descr->data_increment = descr->data_resid;
  612                         descr->timeout = 5 * 1000;
  613                         descr->status = SCSI_STATUS_OK;
  614                         break;
  615                 }
  616                 default:
  617                         /* Constant CA, tell initiator */
  618                         /* Direction is always relative to the initator */
  619                         atio->ccb_h.flags &= ~CAM_DIR_MASK;
  620                         atio->ccb_h.flags |= CAM_DIR_NONE;
  621                         bcopy(&no_lun_sense_data, &atio->sense_data,
  622                               min(sizeof(no_lun_sense_data),
  623                                   sizeof(atio->sense_data)));
  624                         atio->sense_len = sizeof (no_lun_sense_data);
  625                         descr->data_resid = 0;
  626                         descr->data_increment = 0;
  627                         descr->timeout = 5 * 1000;
  628                         descr->status = SCSI_STATUS_CHECK_COND;
  629                         break;
  630                 }
  631 
  632                 /* Queue us up to receive a Continue Target I/O ccb. */
  633                 if ((atio->ccb_h.flags & CAM_DIS_DISCONNECT) != 0) {
  634                         TAILQ_INSERT_HEAD(&softc->work_queue, &atio->ccb_h,
  635                                           periph_links.tqe);
  636                         priority = 0;
  637                 } else {
  638                         TAILQ_INSERT_TAIL(&softc->work_queue, &atio->ccb_h,
  639                                           periph_links.tqe);
  640                         priority = CAM_PRIORITY_NORMAL;
  641                 }
  642                 xpt_schedule(periph, priority);
  643                 break;
  644         }
  645         case XPT_CONT_TARGET_IO:
  646         {
  647                 struct ccb_accept_tio *atio;
  648                 struct targbh_cmd_desc *desc;
  649 
  650                 CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
  651                           ("Received completed CTIO\n"));
  652                 atio = (struct ccb_accept_tio*)done_ccb->ccb_h.ccb_atio;
  653                 desc = (struct targbh_cmd_desc *)atio->ccb_h.ccb_descr;
  654 
  655                 TAILQ_REMOVE(&softc->pending_queue, &atio->ccb_h,
  656                              periph_links.tqe);
  657 
  658                 /*
  659                  * We could check for CAM_SENT_SENSE bein set here,
  660                  * but since we're not maintaining any CA/UA state,
  661                  * there's no point.
  662                  */
  663                 atio->sense_len = 0;
  664                 done_ccb->ccb_h.flags &= ~CAM_SEND_SENSE;
  665                 done_ccb->ccb_h.status &= ~CAM_SENT_SENSE;
  666 
  667                 /*
  668                  * Any errors will not change the data we return,
  669                  * so make sure the queue is not left frozen.
  670                  * XXX - At some point there may be errors that
  671                  *       leave us in a connected state with the
  672                  *       initiator...
  673                  */
  674                 if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
  675                         printf("Releasing Queue\n");
  676                         cam_release_devq(done_ccb->ccb_h.path,
  677                                          /*relsim_flags*/0,
  678                                          /*reduction*/0,
  679                                          /*timeout*/0,
  680                                          /*getcount_only*/0); 
  681                         done_ccb->ccb_h.status &= ~CAM_DEV_QFRZN;
  682                 }
  683                 desc->data_resid -= desc->data_increment;
  684                 xpt_release_ccb(done_ccb);
  685                 if (softc->state != TARGBH_STATE_TEARDOWN) {
  686 
  687                         /*
  688                          * Send the original accept TIO back to the
  689                          * controller to handle more work.
  690                          */
  691                         CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
  692                                   ("Returning ATIO to target\n"));
  693                         /* Restore wildcards */
  694                         atio->ccb_h.target_id = CAM_TARGET_WILDCARD;
  695                         atio->ccb_h.target_lun = CAM_LUN_WILDCARD;
  696                         xpt_action((union ccb *)atio);
  697                         break;
  698                 } else {
  699                         targbhfreedescr(desc);
  700                         free(atio, M_SCSIBH);
  701                 }
  702                 break;
  703         }
  704         case XPT_IMMEDIATE_NOTIFY:
  705         {
  706                 int frozen;
  707 
  708                 frozen = (done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0;
  709                 if (softc->state == TARGBH_STATE_TEARDOWN
  710                  || done_ccb->ccb_h.status == CAM_REQ_ABORTED) {
  711                         printf("Freed an immediate notify\n");
  712                         xpt_free_ccb(done_ccb);
  713                 } else {
  714                         /* Requeue for another immediate event */
  715                         xpt_action(done_ccb);
  716                 }
  717                 if (frozen != 0)
  718                         cam_release_devq(periph->path,
  719                                          /*relsim_flags*/0,
  720                                          /*opening reduction*/0,
  721                                          /*timeout*/0,
  722                                          /*getcount_only*/0);
  723                 break;
  724         }
  725         default:
  726                 panic("targbhdone: Unexpected ccb opcode");
  727                 break;
  728         }
  729 }
  730 
  731 #ifdef NOTYET
  732 static int
  733 targbherror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags)
  734 {
  735         return 0;
  736 }
  737 #endif
  738 
  739 static struct targbh_cmd_desc*
  740 targbhallocdescr()
  741 {
  742         struct targbh_cmd_desc* descr;
  743 
  744         /* Allocate the targbh_descr structure */
  745         descr = (struct targbh_cmd_desc *)malloc(sizeof(*descr),
  746                                                M_SCSIBH, M_NOWAIT);
  747         if (descr == NULL)
  748                 return (NULL);
  749 
  750         bzero(descr, sizeof(*descr));
  751 
  752         /* Allocate buffer backing store */
  753         descr->backing_store = malloc(MAX_BUF_SIZE, M_SCSIBH, M_NOWAIT);
  754         if (descr->backing_store == NULL) {
  755                 free(descr, M_SCSIBH);
  756                 return (NULL);
  757         }
  758         descr->max_size = MAX_BUF_SIZE;
  759         return (descr);
  760 }
  761 
  762 static void
  763 targbhfreedescr(struct targbh_cmd_desc *descr)
  764 {
  765         free(descr->backing_store, M_SCSIBH);
  766         free(descr, M_SCSIBH);
  767 }

Cache object: 90a0bb68b242336e21baa57500cfe7bd


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