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/nvme/nvme_da.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  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 2015 Netflix, Inc
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following disclaimer,
   11  *    without modification, immediately at the beginning of the file.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   26  *
   27  * Derived from ata_da.c:
   28  * Copyright (c) 2009 Alexander Motin <mav@FreeBSD.org>
   29  */
   30 
   31 #include <sys/cdefs.h>
   32 __FBSDID("$FreeBSD: releng/12.0/sys/cam/nvme/nvme_da.c 337583 2018-08-10 19:19:07Z cem $");
   33 
   34 #include <sys/param.h>
   35 
   36 #ifdef _KERNEL
   37 #include <sys/systm.h>
   38 #include <sys/kernel.h>
   39 #include <sys/bio.h>
   40 #include <sys/sysctl.h>
   41 #include <sys/taskqueue.h>
   42 #include <sys/lock.h>
   43 #include <sys/mutex.h>
   44 #include <sys/conf.h>
   45 #include <sys/devicestat.h>
   46 #include <sys/eventhandler.h>
   47 #include <sys/malloc.h>
   48 #include <sys/cons.h>
   49 #include <sys/proc.h>
   50 #include <sys/reboot.h>
   51 #include <geom/geom_disk.h>
   52 #endif /* _KERNEL */
   53 
   54 #ifndef _KERNEL
   55 #include <stdio.h>
   56 #include <string.h>
   57 #endif /* _KERNEL */
   58 
   59 #include <cam/cam.h>
   60 #include <cam/cam_ccb.h>
   61 #include <cam/cam_periph.h>
   62 #include <cam/cam_xpt_periph.h>
   63 #include <cam/cam_sim.h>
   64 #include <cam/cam_iosched.h>
   65 
   66 #include <cam/nvme/nvme_all.h>
   67 
   68 typedef enum {
   69         NDA_STATE_NORMAL
   70 } nda_state;
   71 
   72 typedef enum {
   73         NDA_FLAG_OPEN           = 0x0001,
   74         NDA_FLAG_DIRTY          = 0x0002,
   75         NDA_FLAG_SCTX_INIT      = 0x0004,
   76 } nda_flags;
   77 
   78 typedef enum {
   79         NDA_Q_4K   = 0x01,
   80         NDA_Q_NONE = 0x00,
   81 } nda_quirks;
   82         
   83 #define NDA_Q_BIT_STRING        \
   84         "\020"                  \
   85         "\001Bit 0"
   86 
   87 typedef enum {
   88         NDA_CCB_BUFFER_IO       = 0x01,
   89         NDA_CCB_DUMP            = 0x02,
   90         NDA_CCB_TRIM            = 0x03,
   91         NDA_CCB_TYPE_MASK       = 0x0F,
   92 } nda_ccb_state;
   93 
   94 /* Offsets into our private area for storing information */
   95 #define ccb_state       ccb_h.ppriv_field0
   96 #define ccb_bp          ccb_h.ppriv_ptr1        /* For NDA_CCB_BUFFER_IO */
   97 #define ccb_trim        ccb_h.ppriv_ptr1        /* For NDA_CCB_TRIM */
   98 
   99 struct nda_softc {
  100         struct   cam_iosched_softc *cam_iosched;
  101         int                     outstanding_cmds;       /* Number of active commands */
  102         int                     refcount;               /* Active xpt_action() calls */
  103         nda_state               state;
  104         nda_flags               flags;
  105         nda_quirks              quirks;
  106         int                     unmappedio;
  107         quad_t                  deletes;
  108         quad_t                  dsm_req;
  109         uint32_t                nsid;                   /* Namespace ID for this nda device */
  110         struct disk             *disk;
  111         struct task             sysctl_task;
  112         struct sysctl_ctx_list  sysctl_ctx;
  113         struct sysctl_oid       *sysctl_tree;
  114 #ifdef CAM_TEST_FAILURE
  115         int                     force_read_error;
  116         int                     force_write_error;
  117         int                     periodic_read_error;
  118         int                     periodic_read_count;
  119 #endif
  120 #ifdef CAM_IO_STATS
  121         struct sysctl_ctx_list  sysctl_stats_ctx;
  122         struct sysctl_oid       *sysctl_stats_tree;
  123         u_int                   timeouts;
  124         u_int                   errors;
  125         u_int                   invalidations;
  126 #endif
  127 };
  128 
  129 struct nda_trim_request {
  130         union {
  131                 struct nvme_dsm_range dsm;
  132                 uint8_t         data[NVME_MAX_DSM_TRIM];
  133         };
  134         TAILQ_HEAD(, bio) bps;
  135 };
  136 
  137 /* Need quirk table */
  138 
  139 static  disk_strategy_t ndastrategy;
  140 static  dumper_t        ndadump;
  141 static  periph_init_t   ndainit;
  142 static  void            ndaasync(void *callback_arg, u_int32_t code,
  143                                 struct cam_path *path, void *arg);
  144 static  void            ndasysctlinit(void *context, int pending);
  145 static  periph_ctor_t   ndaregister;
  146 static  periph_dtor_t   ndacleanup;
  147 static  periph_start_t  ndastart;
  148 static  periph_oninv_t  ndaoninvalidate;
  149 static  void            ndadone(struct cam_periph *periph,
  150                                union ccb *done_ccb);
  151 static  int             ndaerror(union ccb *ccb, u_int32_t cam_flags,
  152                                 u_int32_t sense_flags);
  153 static void             ndashutdown(void *arg, int howto);
  154 static void             ndasuspend(void *arg);
  155 
  156 #ifndef NDA_DEFAULT_SEND_ORDERED
  157 #define NDA_DEFAULT_SEND_ORDERED        1
  158 #endif
  159 #ifndef NDA_DEFAULT_TIMEOUT
  160 #define NDA_DEFAULT_TIMEOUT 30  /* Timeout in seconds */
  161 #endif
  162 #ifndef NDA_DEFAULT_RETRY
  163 #define NDA_DEFAULT_RETRY       4
  164 #endif
  165 #ifndef NDA_MAX_TRIM_ENTRIES
  166 #define NDA_MAX_TRIM_ENTRIES  (NVME_MAX_DSM_TRIM / sizeof(struct nvme_dsm_range))/* Number of DSM trims to use, max 256 */
  167 #endif
  168 
  169 static SYSCTL_NODE(_kern_cam, OID_AUTO, nda, CTLFLAG_RD, 0,
  170             "CAM Direct Access Disk driver");
  171 
  172 //static int nda_retry_count = NDA_DEFAULT_RETRY;
  173 static int nda_send_ordered = NDA_DEFAULT_SEND_ORDERED;
  174 static int nda_default_timeout = NDA_DEFAULT_TIMEOUT;
  175 static int nda_max_trim_entries = NDA_MAX_TRIM_ENTRIES;
  176 SYSCTL_INT(_kern_cam_nda, OID_AUTO, max_trim, CTLFLAG_RDTUN,
  177     &nda_max_trim_entries, NDA_MAX_TRIM_ENTRIES,
  178     "Maximum number of BIO_DELETE to send down as a DSM TRIM.");
  179 
  180 /*
  181  * All NVMe media is non-rotational, so all nvme device instances
  182  * share this to implement the sysctl.
  183  */
  184 static int nda_rotating_media = 0;
  185 
  186 static struct periph_driver ndadriver =
  187 {
  188         ndainit, "nda",
  189         TAILQ_HEAD_INITIALIZER(ndadriver.units), /* generation */ 0
  190 };
  191 
  192 PERIPHDRIVER_DECLARE(nda, ndadriver);
  193 
  194 static MALLOC_DEFINE(M_NVMEDA, "nvme_da", "nvme_da buffers");
  195 
  196 /*
  197  * nice wrappers. Maybe these belong in nvme_all.c instead of
  198  * here, but this is the only place that uses these. Should
  199  * we ever grow another NVME periph, we should move them
  200  * all there wholesale.
  201  */
  202 
  203 static void
  204 nda_nvme_flush(struct nda_softc *softc, struct ccb_nvmeio *nvmeio)
  205 {
  206         cam_fill_nvmeio(nvmeio,
  207             0,                  /* retries */
  208             ndadone,            /* cbfcnp */
  209             CAM_DIR_NONE,       /* flags */
  210             NULL,               /* data_ptr */
  211             0,                  /* dxfer_len */
  212             nda_default_timeout * 1000); /* timeout 30s */
  213         nvme_ns_flush_cmd(&nvmeio->cmd, softc->nsid);
  214 }
  215 
  216 static void
  217 nda_nvme_trim(struct nda_softc *softc, struct ccb_nvmeio *nvmeio,
  218     void *payload, uint32_t num_ranges)
  219 {
  220         cam_fill_nvmeio(nvmeio,
  221             0,                  /* retries */
  222             ndadone,            /* cbfcnp */
  223             CAM_DIR_OUT,        /* flags */
  224             payload,            /* data_ptr */
  225             num_ranges * sizeof(struct nvme_dsm_range), /* dxfer_len */
  226             nda_default_timeout * 1000); /* timeout 30s */
  227         nvme_ns_trim_cmd(&nvmeio->cmd, softc->nsid, num_ranges);
  228 }
  229 
  230 static void
  231 nda_nvme_write(struct nda_softc *softc, struct ccb_nvmeio *nvmeio,
  232     void *payload, uint64_t lba, uint32_t len, uint32_t count)
  233 {
  234         cam_fill_nvmeio(nvmeio,
  235             0,                  /* retries */
  236             ndadone,            /* cbfcnp */
  237             CAM_DIR_OUT,        /* flags */
  238             payload,            /* data_ptr */
  239             len,                /* dxfer_len */
  240             nda_default_timeout * 1000); /* timeout 30s */
  241         nvme_ns_write_cmd(&nvmeio->cmd, softc->nsid, lba, count);
  242 }
  243 
  244 static void
  245 nda_nvme_rw_bio(struct nda_softc *softc, struct ccb_nvmeio *nvmeio,
  246     struct bio *bp, uint32_t rwcmd)
  247 {
  248         int flags = rwcmd == NVME_OPC_READ ? CAM_DIR_IN : CAM_DIR_OUT;
  249         void *payload;
  250         uint64_t lba;
  251         uint32_t count;
  252 
  253         if (bp->bio_flags & BIO_UNMAPPED) {
  254                 flags |= CAM_DATA_BIO;
  255                 payload = bp;
  256         } else {
  257                 payload = bp->bio_data;
  258         }
  259 
  260         lba = bp->bio_pblkno;
  261         count = bp->bio_bcount / softc->disk->d_sectorsize;
  262 
  263         cam_fill_nvmeio(nvmeio,
  264             0,                  /* retries */
  265             ndadone,            /* cbfcnp */
  266             flags,              /* flags */
  267             payload,            /* data_ptr */
  268             bp->bio_bcount,     /* dxfer_len */
  269             nda_default_timeout * 1000); /* timeout 30s */
  270         nvme_ns_rw_cmd(&nvmeio->cmd, rwcmd, softc->nsid, lba, count);
  271 }
  272 
  273 static int
  274 ndaopen(struct disk *dp)
  275 {
  276         struct cam_periph *periph;
  277         struct nda_softc *softc;
  278         int error;
  279 
  280         periph = (struct cam_periph *)dp->d_drv1;
  281         if (cam_periph_acquire(periph) != 0) {
  282                 return(ENXIO);
  283         }
  284 
  285         cam_periph_lock(periph);
  286         if ((error = cam_periph_hold(periph, PRIBIO|PCATCH)) != 0) {
  287                 cam_periph_unlock(periph);
  288                 cam_periph_release(periph);
  289                 return (error);
  290         }
  291 
  292         CAM_DEBUG(periph->path, CAM_DEBUG_TRACE | CAM_DEBUG_PERIPH,
  293             ("ndaopen\n"));
  294 
  295         softc = (struct nda_softc *)periph->softc;
  296         softc->flags |= NDA_FLAG_OPEN;
  297 
  298         cam_periph_unhold(periph);
  299         cam_periph_unlock(periph);
  300         return (0);
  301 }
  302 
  303 static int
  304 ndaclose(struct disk *dp)
  305 {
  306         struct  cam_periph *periph;
  307         struct  nda_softc *softc;
  308         union ccb *ccb;
  309         int error;
  310 
  311         periph = (struct cam_periph *)dp->d_drv1;
  312         softc = (struct nda_softc *)periph->softc;
  313         cam_periph_lock(periph);
  314 
  315         CAM_DEBUG(periph->path, CAM_DEBUG_TRACE | CAM_DEBUG_PERIPH,
  316             ("ndaclose\n"));
  317 
  318         if ((softc->flags & NDA_FLAG_DIRTY) != 0 &&
  319             (periph->flags & CAM_PERIPH_INVALID) == 0 &&
  320             cam_periph_hold(periph, PRIBIO) == 0) {
  321 
  322                 ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL);
  323                 nda_nvme_flush(softc, &ccb->nvmeio);
  324                 error = cam_periph_runccb(ccb, ndaerror, /*cam_flags*/0,
  325                     /*sense_flags*/0, softc->disk->d_devstat);
  326 
  327                 if (error != 0)
  328                         xpt_print(periph->path, "Synchronize cache failed\n");
  329                 else
  330                         softc->flags &= ~NDA_FLAG_DIRTY;
  331                 xpt_release_ccb(ccb);
  332                 cam_periph_unhold(periph);
  333         }
  334 
  335         softc->flags &= ~NDA_FLAG_OPEN;
  336 
  337         while (softc->refcount != 0)
  338                 cam_periph_sleep(periph, &softc->refcount, PRIBIO, "ndaclose", 1);
  339         KASSERT(softc->outstanding_cmds == 0,
  340             ("nda %d outstanding commands", softc->outstanding_cmds));
  341         cam_periph_unlock(periph);
  342         cam_periph_release(periph);
  343         return (0);     
  344 }
  345 
  346 static void
  347 ndaschedule(struct cam_periph *periph)
  348 {
  349         struct nda_softc *softc = (struct nda_softc *)periph->softc;
  350 
  351         if (softc->state != NDA_STATE_NORMAL)
  352                 return;
  353 
  354         cam_iosched_schedule(softc->cam_iosched, periph);
  355 }
  356 
  357 /*
  358  * Actually translate the requested transfer into one the physical driver
  359  * can understand.  The transfer is described by a buf and will include
  360  * only one physical transfer.
  361  */
  362 static void
  363 ndastrategy(struct bio *bp)
  364 {
  365         struct cam_periph *periph;
  366         struct nda_softc *softc;
  367         
  368         periph = (struct cam_periph *)bp->bio_disk->d_drv1;
  369         softc = (struct nda_softc *)periph->softc;
  370 
  371         cam_periph_lock(periph);
  372 
  373         CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("ndastrategy(%p)\n", bp));
  374 
  375         /*
  376          * If the device has been made invalid, error out
  377          */
  378         if ((periph->flags & CAM_PERIPH_INVALID) != 0) {
  379                 cam_periph_unlock(periph);
  380                 biofinish(bp, NULL, ENXIO);
  381                 return;
  382         }
  383         
  384         if (bp->bio_cmd == BIO_DELETE)
  385                 softc->deletes++;
  386 
  387         /*
  388          * Place it in the queue of disk activities for this disk
  389          */
  390         cam_iosched_queue_work(softc->cam_iosched, bp);
  391 
  392         /*
  393          * Schedule ourselves for performing the work.
  394          */
  395         ndaschedule(periph);
  396         cam_periph_unlock(periph);
  397 
  398         return;
  399 }
  400 
  401 static int
  402 ndadump(void *arg, void *virtual, vm_offset_t physical, off_t offset, size_t length)
  403 {
  404         struct      cam_periph *periph;
  405         struct      nda_softc *softc;
  406         u_int       secsize;
  407         struct ccb_nvmeio nvmeio;
  408         struct      disk *dp;
  409         uint64_t    lba;
  410         uint32_t    count;
  411         int         error = 0;
  412 
  413         dp = arg;
  414         periph = dp->d_drv1;
  415         softc = (struct nda_softc *)periph->softc;
  416         secsize = softc->disk->d_sectorsize;
  417         lba = offset / secsize;
  418         count = length / secsize;
  419         
  420         if ((periph->flags & CAM_PERIPH_INVALID) != 0)
  421                 return (ENXIO);
  422 
  423         /* xpt_get_ccb returns a zero'd allocation for the ccb, mimic that here */
  424         memset(&nvmeio, 0, sizeof(nvmeio));
  425         if (length > 0) {
  426                 xpt_setup_ccb(&nvmeio.ccb_h, periph->path, CAM_PRIORITY_NORMAL);
  427                 nvmeio.ccb_state = NDA_CCB_DUMP;
  428                 nda_nvme_write(softc, &nvmeio, virtual, lba, length, count);
  429                 error = cam_periph_runccb((union ccb *)&nvmeio, cam_periph_error,
  430                     0, SF_NO_RECOVERY | SF_NO_RETRY, NULL);
  431                 if (error != 0)
  432                         printf("Aborting dump due to I/O error %d.\n", error);
  433 
  434                 return (error);
  435         }
  436         
  437         /* Flush */
  438         xpt_setup_ccb(&nvmeio.ccb_h, periph->path, CAM_PRIORITY_NORMAL);
  439 
  440         nvmeio.ccb_state = NDA_CCB_DUMP;
  441         nda_nvme_flush(softc, &nvmeio);
  442         error = cam_periph_runccb((union ccb *)&nvmeio, cam_periph_error,
  443             0, SF_NO_RECOVERY | SF_NO_RETRY, NULL);
  444         if (error != 0)
  445                 xpt_print(periph->path, "flush cmd failed\n");
  446         return (error);
  447 }
  448 
  449 static void
  450 ndainit(void)
  451 {
  452         cam_status status;
  453 
  454         /*
  455          * Install a global async callback.  This callback will
  456          * receive async callbacks like "new device found".
  457          */
  458         status = xpt_register_async(AC_FOUND_DEVICE, ndaasync, NULL, NULL);
  459 
  460         if (status != CAM_REQ_CMP) {
  461                 printf("nda: Failed to attach master async callback "
  462                        "due to status 0x%x!\n", status);
  463         } else if (nda_send_ordered) {
  464 
  465                 /* Register our event handlers */
  466                 if ((EVENTHANDLER_REGISTER(power_suspend, ndasuspend,
  467                                            NULL, EVENTHANDLER_PRI_LAST)) == NULL)
  468                     printf("ndainit: power event registration failed!\n");
  469                 if ((EVENTHANDLER_REGISTER(shutdown_post_sync, ndashutdown,
  470                                            NULL, SHUTDOWN_PRI_DEFAULT)) == NULL)
  471                     printf("ndainit: shutdown event registration failed!\n");
  472         }
  473 }
  474 
  475 /*
  476  * Callback from GEOM, called when it has finished cleaning up its
  477  * resources.
  478  */
  479 static void
  480 ndadiskgonecb(struct disk *dp)
  481 {
  482         struct cam_periph *periph;
  483 
  484         periph = (struct cam_periph *)dp->d_drv1;
  485 
  486         cam_periph_release(periph);
  487 }
  488 
  489 static void
  490 ndaoninvalidate(struct cam_periph *periph)
  491 {
  492         struct nda_softc *softc;
  493 
  494         softc = (struct nda_softc *)periph->softc;
  495 
  496         /*
  497          * De-register any async callbacks.
  498          */
  499         xpt_register_async(0, ndaasync, periph, periph->path);
  500 #ifdef CAM_IO_STATS
  501         softc->invalidations++;
  502 #endif
  503 
  504         /*
  505          * Return all queued I/O with ENXIO.
  506          * XXX Handle any transactions queued to the card
  507          *     with XPT_ABORT_CCB.
  508          */
  509         cam_iosched_flush(softc->cam_iosched, NULL, ENXIO);
  510 
  511         disk_gone(softc->disk);
  512 }
  513 
  514 static void
  515 ndacleanup(struct cam_periph *periph)
  516 {
  517         struct nda_softc *softc;
  518 
  519         softc = (struct nda_softc *)periph->softc;
  520 
  521         cam_periph_unlock(periph);
  522 
  523         cam_iosched_fini(softc->cam_iosched);
  524 
  525         /*
  526          * If we can't free the sysctl tree, oh well...
  527          */
  528         if ((softc->flags & NDA_FLAG_SCTX_INIT) != 0) {
  529 #ifdef CAM_IO_STATS
  530                 if (sysctl_ctx_free(&softc->sysctl_stats_ctx) != 0)
  531                         xpt_print(periph->path,
  532                             "can't remove sysctl stats context\n");
  533 #endif
  534                 if (sysctl_ctx_free(&softc->sysctl_ctx) != 0)
  535                         xpt_print(periph->path,
  536                             "can't remove sysctl context\n");
  537         }
  538 
  539         disk_destroy(softc->disk);
  540         free(softc, M_DEVBUF);
  541         cam_periph_lock(periph);
  542 }
  543 
  544 static void
  545 ndaasync(void *callback_arg, u_int32_t code,
  546         struct cam_path *path, void *arg)
  547 {
  548         struct cam_periph *periph;
  549 
  550         periph = (struct cam_periph *)callback_arg;
  551         switch (code) {
  552         case AC_FOUND_DEVICE:
  553         {
  554                 struct ccb_getdev *cgd;
  555                 cam_status status;
  556  
  557                 cgd = (struct ccb_getdev *)arg;
  558                 if (cgd == NULL)
  559                         break;
  560 
  561                 if (cgd->protocol != PROTO_NVME)
  562                         break;
  563 
  564                 /*
  565                  * Allocate a peripheral instance for
  566                  * this device and start the probe
  567                  * process.
  568                  */
  569                 status = cam_periph_alloc(ndaregister, ndaoninvalidate,
  570                                           ndacleanup, ndastart,
  571                                           "nda", CAM_PERIPH_BIO,
  572                                           path, ndaasync,
  573                                           AC_FOUND_DEVICE, cgd);
  574 
  575                 if (status != CAM_REQ_CMP
  576                  && status != CAM_REQ_INPROG)
  577                         printf("ndaasync: Unable to attach to new device "
  578                                 "due to status 0x%x\n", status);
  579                 break;
  580         }
  581         case AC_ADVINFO_CHANGED:
  582         {
  583                 uintptr_t buftype;
  584 
  585                 buftype = (uintptr_t)arg;
  586                 if (buftype == CDAI_TYPE_PHYS_PATH) {
  587                         struct nda_softc *softc;
  588 
  589                         softc = periph->softc;
  590                         disk_attr_changed(softc->disk, "GEOM::physpath",
  591                                           M_NOWAIT);
  592                 }
  593                 break;
  594         }
  595         case AC_LOST_DEVICE:
  596         default:
  597                 cam_periph_async(periph, code, path, arg);
  598                 break;
  599         }
  600 }
  601 
  602 static void
  603 ndasysctlinit(void *context, int pending)
  604 {
  605         struct cam_periph *periph;
  606         struct nda_softc *softc;
  607         char tmpstr[32], tmpstr2[16];
  608 
  609         periph = (struct cam_periph *)context;
  610 
  611         /* periph was held for us when this task was enqueued */
  612         if ((periph->flags & CAM_PERIPH_INVALID) != 0) {
  613                 cam_periph_release(periph);
  614                 return;
  615         }
  616 
  617         softc = (struct nda_softc *)periph->softc;
  618         snprintf(tmpstr, sizeof(tmpstr), "CAM NDA unit %d", periph->unit_number);
  619         snprintf(tmpstr2, sizeof(tmpstr2), "%d", periph->unit_number);
  620 
  621         sysctl_ctx_init(&softc->sysctl_ctx);
  622         softc->flags |= NDA_FLAG_SCTX_INIT;
  623         softc->sysctl_tree = SYSCTL_ADD_NODE_WITH_LABEL(&softc->sysctl_ctx,
  624                 SYSCTL_STATIC_CHILDREN(_kern_cam_nda), OID_AUTO, tmpstr2,
  625                 CTLFLAG_RD, 0, tmpstr, "device_index");
  626         if (softc->sysctl_tree == NULL) {
  627                 printf("ndasysctlinit: unable to allocate sysctl tree\n");
  628                 cam_periph_release(periph);
  629                 return;
  630         }
  631 
  632         SYSCTL_ADD_INT(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree),
  633             OID_AUTO, "unmapped_io", CTLFLAG_RD,
  634             &softc->unmappedio, 0, "Unmapped I/O leaf");
  635 
  636         SYSCTL_ADD_QUAD(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree),
  637             OID_AUTO, "deletes", CTLFLAG_RD,
  638             &softc->deletes, "Number of BIO_DELETE requests");
  639 
  640         SYSCTL_ADD_QUAD(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree),
  641             OID_AUTO, "dsm_req", CTLFLAG_RD,
  642             &softc->dsm_req, "Number of DSM requests sent to SIM");
  643 
  644         SYSCTL_ADD_INT(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree),
  645             OID_AUTO, "rotating", CTLFLAG_RD, &nda_rotating_media, 1,
  646             "Rotating media");
  647 
  648 #ifdef CAM_IO_STATS
  649         softc->sysctl_stats_tree = SYSCTL_ADD_NODE(&softc->sysctl_stats_ctx,
  650                 SYSCTL_CHILDREN(softc->sysctl_tree), OID_AUTO, "stats",
  651                 CTLFLAG_RD, 0, "Statistics");
  652         if (softc->sysctl_stats_tree == NULL) {
  653                 printf("ndasysctlinit: unable to allocate sysctl tree for stats\n");
  654                 cam_periph_release(periph);
  655                 return;
  656         }
  657         SYSCTL_ADD_INT(&softc->sysctl_stats_ctx,
  658                 SYSCTL_CHILDREN(softc->sysctl_stats_tree),
  659                 OID_AUTO, "timeouts", CTLFLAG_RD,
  660                 &softc->timeouts, 0,
  661                 "Device timeouts reported by the SIM");
  662         SYSCTL_ADD_INT(&softc->sysctl_stats_ctx,
  663                 SYSCTL_CHILDREN(softc->sysctl_stats_tree),
  664                 OID_AUTO, "errors", CTLFLAG_RD,
  665                 &softc->errors, 0,
  666                 "Transport errors reported by the SIM.");
  667         SYSCTL_ADD_INT(&softc->sysctl_stats_ctx,
  668                 SYSCTL_CHILDREN(softc->sysctl_stats_tree),
  669                 OID_AUTO, "pack_invalidations", CTLFLAG_RD,
  670                 &softc->invalidations, 0,
  671                 "Device pack invalidations.");
  672 #endif
  673 
  674 #ifdef CAM_TEST_FAILURE
  675         SYSCTL_ADD_PROC(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree),
  676                 OID_AUTO, "invalidate", CTLTYPE_U64 | CTLFLAG_RW | CTLFLAG_MPSAFE,
  677                 periph, 0, cam_periph_invalidate_sysctl, "I",
  678                 "Write 1 to invalidate the drive immediately");
  679 #endif
  680 
  681         cam_iosched_sysctl_init(softc->cam_iosched, &softc->sysctl_ctx,
  682             softc->sysctl_tree);
  683 
  684         cam_periph_release(periph);
  685 }
  686 
  687 static int
  688 ndagetattr(struct bio *bp)
  689 {
  690         int ret;
  691         struct cam_periph *periph;
  692 
  693         periph = (struct cam_periph *)bp->bio_disk->d_drv1;
  694         cam_periph_lock(periph);
  695         ret = xpt_getattr(bp->bio_data, bp->bio_length, bp->bio_attribute,
  696             periph->path);
  697         cam_periph_unlock(periph);
  698         if (ret == 0)
  699                 bp->bio_completed = bp->bio_length;
  700         return ret;
  701 }
  702 
  703 static cam_status
  704 ndaregister(struct cam_periph *periph, void *arg)
  705 {
  706         struct nda_softc *softc;
  707         struct disk *disk;
  708         struct ccb_pathinq cpi;
  709         const struct nvme_namespace_data *nsd;
  710         const struct nvme_controller_data *cd;
  711         char   announce_buf[80];
  712         uint8_t flbas_fmt, lbads, vwc_present;
  713         u_int maxio;
  714         int quirks;
  715 
  716         nsd = nvme_get_identify_ns(periph);
  717         cd = nvme_get_identify_cntrl(periph);
  718 
  719         softc = (struct nda_softc *)malloc(sizeof(*softc), M_DEVBUF,
  720             M_NOWAIT | M_ZERO);
  721 
  722         if (softc == NULL) {
  723                 printf("ndaregister: Unable to probe new device. "
  724                     "Unable to allocate softc\n");
  725                 return(CAM_REQ_CMP_ERR);
  726         }
  727 
  728         if (cam_iosched_init(&softc->cam_iosched, periph) != 0) {
  729                 printf("ndaregister: Unable to probe new device. "
  730                        "Unable to allocate iosched memory\n");
  731                 free(softc, M_DEVBUF);
  732                 return(CAM_REQ_CMP_ERR);
  733         }
  734 
  735         /* ident_data parsing */
  736 
  737         periph->softc = softc;
  738 
  739         softc->quirks = NDA_Q_NONE;
  740 
  741         xpt_path_inq(&cpi, periph->path);
  742 
  743         TASK_INIT(&softc->sysctl_task, 0, ndasysctlinit, periph);
  744 
  745         /*
  746          * The name space ID is the lun, save it for later I/O
  747          */
  748         softc->nsid = (uint32_t)xpt_path_lun_id(periph->path);
  749 
  750         /*
  751          * Register this media as a disk
  752          */
  753         (void)cam_periph_hold(periph, PRIBIO);
  754         cam_periph_unlock(periph);
  755         snprintf(announce_buf, sizeof(announce_buf),
  756             "kern.cam.nda.%d.quirks", periph->unit_number);
  757         quirks = softc->quirks;
  758         TUNABLE_INT_FETCH(announce_buf, &quirks);
  759         softc->quirks = quirks;
  760         cam_iosched_set_sort_queue(softc->cam_iosched, 0);
  761         softc->disk = disk = disk_alloc();
  762         strlcpy(softc->disk->d_descr, cd->mn,
  763             MIN(sizeof(softc->disk->d_descr), sizeof(cd->mn)));
  764         strlcpy(softc->disk->d_ident, cd->sn,
  765             MIN(sizeof(softc->disk->d_ident), sizeof(cd->sn)));
  766         disk->d_rotation_rate = DISK_RR_NON_ROTATING;
  767         disk->d_open = ndaopen;
  768         disk->d_close = ndaclose;
  769         disk->d_strategy = ndastrategy;
  770         disk->d_getattr = ndagetattr;
  771         disk->d_dump = ndadump;
  772         disk->d_gone = ndadiskgonecb;
  773         disk->d_name = "nda";
  774         disk->d_drv1 = periph;
  775         disk->d_unit = periph->unit_number;
  776         maxio = cpi.maxio;              /* Honor max I/O size of SIM */
  777         if (maxio == 0)
  778                 maxio = DFLTPHYS;       /* traditional default */
  779         else if (maxio > MAXPHYS)
  780                 maxio = MAXPHYS;        /* for safety */
  781         disk->d_maxsize = maxio;
  782         flbas_fmt = (nsd->flbas >> NVME_NS_DATA_FLBAS_FORMAT_SHIFT) &
  783                 NVME_NS_DATA_FLBAS_FORMAT_MASK;
  784         lbads = (nsd->lbaf[flbas_fmt] >> NVME_NS_DATA_LBAF_LBADS_SHIFT) &
  785                 NVME_NS_DATA_LBAF_LBADS_MASK;
  786         disk->d_sectorsize = 1 << lbads;
  787         disk->d_mediasize = (off_t)(disk->d_sectorsize * nsd->nsze);
  788         disk->d_delmaxsize = disk->d_mediasize;
  789         disk->d_flags = DISKFLAG_DIRECT_COMPLETION;
  790 //      if (cd->oncs.dsm) // XXX broken?
  791                 disk->d_flags |= DISKFLAG_CANDELETE;
  792         vwc_present = (cd->vwc >> NVME_CTRLR_DATA_VWC_PRESENT_SHIFT) &
  793                 NVME_CTRLR_DATA_VWC_PRESENT_MASK;
  794         if (vwc_present)
  795                 disk->d_flags |= DISKFLAG_CANFLUSHCACHE;
  796         if ((cpi.hba_misc & PIM_UNMAPPED) != 0) {
  797                 disk->d_flags |= DISKFLAG_UNMAPPED_BIO;
  798                 softc->unmappedio = 1;
  799         }
  800         /*
  801          * d_ident and d_descr are both far bigger than the length of either
  802          *  the serial or model number strings.
  803          */
  804         nvme_strvis(disk->d_descr, cd->mn,
  805             sizeof(disk->d_descr), NVME_MODEL_NUMBER_LENGTH);
  806         nvme_strvis(disk->d_ident, cd->sn,
  807             sizeof(disk->d_ident), NVME_SERIAL_NUMBER_LENGTH);
  808         disk->d_hba_vendor = cpi.hba_vendor;
  809         disk->d_hba_device = cpi.hba_device;
  810         disk->d_hba_subvendor = cpi.hba_subvendor;
  811         disk->d_hba_subdevice = cpi.hba_subdevice;
  812         disk->d_stripesize = disk->d_sectorsize;
  813         disk->d_stripeoffset = 0;
  814         disk->d_devstat = devstat_new_entry(periph->periph_name,
  815             periph->unit_number, disk->d_sectorsize,
  816             DEVSTAT_ALL_SUPPORTED,
  817             DEVSTAT_TYPE_DIRECT | XPORT_DEVSTAT_TYPE(cpi.transport),
  818             DEVSTAT_PRIORITY_DISK);
  819         /*
  820          * Add alias for older nvd drives to ease transition.
  821          */
  822         /* disk_add_alias(disk, "nvd"); Have reports of this causing problems */
  823 
  824         /*
  825          * Acquire a reference to the periph before we register with GEOM.
  826          * We'll release this reference once GEOM calls us back (via
  827          * ndadiskgonecb()) telling us that our provider has been freed.
  828          */
  829         if (cam_periph_acquire(periph) != 0) {
  830                 xpt_print(periph->path, "%s: lost periph during "
  831                           "registration!\n", __func__);
  832                 cam_periph_lock(periph);
  833                 return (CAM_REQ_CMP_ERR);
  834         }
  835         disk_create(softc->disk, DISK_VERSION);
  836         cam_periph_lock(periph);
  837         cam_periph_unhold(periph);
  838 
  839         snprintf(announce_buf, sizeof(announce_buf),
  840                 "%juMB (%ju %u byte sectors)",
  841             (uintmax_t)((uintmax_t)disk->d_mediasize / (1024*1024)),
  842                 (uintmax_t)disk->d_mediasize / disk->d_sectorsize,
  843                 disk->d_sectorsize);
  844         xpt_announce_periph(periph, announce_buf);
  845         xpt_announce_quirks(periph, softc->quirks, NDA_Q_BIT_STRING);
  846 
  847         /*
  848          * Create our sysctl variables, now that we know
  849          * we have successfully attached.
  850          */
  851         if (cam_periph_acquire(periph) == 0)
  852                 taskqueue_enqueue(taskqueue_thread, &softc->sysctl_task);
  853 
  854         /*
  855          * Register for device going away and info about the drive
  856          * changing (though with NVMe, it can't)
  857          */
  858         xpt_register_async(AC_LOST_DEVICE | AC_ADVINFO_CHANGED,
  859             ndaasync, periph, periph->path);
  860 
  861         softc->state = NDA_STATE_NORMAL;
  862         return(CAM_REQ_CMP);
  863 }
  864 
  865 static void
  866 ndastart(struct cam_periph *periph, union ccb *start_ccb)
  867 {
  868         struct nda_softc *softc = (struct nda_softc *)periph->softc;
  869         struct ccb_nvmeio *nvmeio = &start_ccb->nvmeio;
  870 
  871         CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("ndastart\n"));
  872 
  873         switch (softc->state) {
  874         case NDA_STATE_NORMAL:
  875         {
  876                 struct bio *bp;
  877 
  878                 bp = cam_iosched_next_bio(softc->cam_iosched);
  879                 CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("ndastart: bio %p\n", bp));
  880                 if (bp == NULL) {
  881                         xpt_release_ccb(start_ccb);
  882                         break;
  883                 }
  884 
  885                 switch (bp->bio_cmd) {
  886                 case BIO_WRITE:
  887                         softc->flags |= NDA_FLAG_DIRTY;
  888                         /* FALLTHROUGH */
  889                 case BIO_READ:
  890                 {
  891 #ifdef CAM_TEST_FAILURE
  892                         int fail = 0;
  893 
  894                         /*
  895                          * Support the failure ioctls.  If the command is a
  896                          * read, and there are pending forced read errors, or
  897                          * if a write and pending write errors, then fail this
  898                          * operation with EIO.  This is useful for testing
  899                          * purposes.  Also, support having every Nth read fail.
  900                          *
  901                          * This is a rather blunt tool.
  902                          */
  903                         if (bp->bio_cmd == BIO_READ) {
  904                                 if (softc->force_read_error) {
  905                                         softc->force_read_error--;
  906                                         fail = 1;
  907                                 }
  908                                 if (softc->periodic_read_error > 0) {
  909                                         if (++softc->periodic_read_count >=
  910                                             softc->periodic_read_error) {
  911                                                 softc->periodic_read_count = 0;
  912                                                 fail = 1;
  913                                         }
  914                                 }
  915                         } else {
  916                                 if (softc->force_write_error) {
  917                                         softc->force_write_error--;
  918                                         fail = 1;
  919                                 }
  920                         }
  921                         if (fail) {
  922                                 biofinish(bp, NULL, EIO);
  923                                 xpt_release_ccb(start_ccb);
  924                                 ndaschedule(periph);
  925                                 return;
  926                         }
  927 #endif
  928                         KASSERT((bp->bio_flags & BIO_UNMAPPED) == 0 ||
  929                             round_page(bp->bio_bcount + bp->bio_ma_offset) /
  930                             PAGE_SIZE == bp->bio_ma_n,
  931                             ("Short bio %p", bp));
  932                         nda_nvme_rw_bio(softc, &start_ccb->nvmeio, bp, bp->bio_cmd == BIO_READ ?
  933                             NVME_OPC_READ : NVME_OPC_WRITE);
  934                         break;
  935                 }
  936                 case BIO_DELETE:
  937                 {
  938                         struct nvme_dsm_range *dsm_range, *dsm_end;
  939                         struct nda_trim_request *trim;
  940                         struct bio *bp1;
  941                         int ents;
  942 
  943                         trim = malloc(sizeof(*trim), M_NVMEDA, M_ZERO | M_NOWAIT);
  944                         if (trim == NULL) {
  945                                 biofinish(bp, NULL, ENOMEM);
  946                                 xpt_release_ccb(start_ccb);
  947                                 ndaschedule(periph);
  948                                 return;
  949                         }
  950                         TAILQ_INIT(&trim->bps);
  951                         bp1 = bp;
  952                         ents = sizeof(trim->data) / sizeof(struct nvme_dsm_range);
  953                         ents = min(ents, nda_max_trim_entries);
  954                         dsm_range = &trim->dsm;
  955                         dsm_end = dsm_range + ents;
  956                         do {
  957                                 TAILQ_INSERT_TAIL(&trim->bps, bp1, bio_queue);
  958                                 dsm_range->length =
  959                                     htole32(bp1->bio_bcount / softc->disk->d_sectorsize);
  960                                 dsm_range->starting_lba =
  961                                     htole64(bp1->bio_offset / softc->disk->d_sectorsize);
  962                                 dsm_range++;
  963                                 if (dsm_range >= dsm_end)
  964                                         break;
  965                                 bp1 = cam_iosched_next_trim(softc->cam_iosched);
  966                                 /* XXX -- Could collapse adjacent ranges, but we don't for now */
  967                                 /* XXX -- Could limit based on total payload size */
  968                         } while (bp1 != NULL);
  969                         start_ccb->ccb_trim = trim;
  970                         softc->dsm_req++;
  971                         nda_nvme_trim(softc, &start_ccb->nvmeio, &trim->dsm,
  972                             dsm_range - &trim->dsm);
  973                         start_ccb->ccb_state = NDA_CCB_TRIM;
  974                         /*
  975                          * Note: We can have multiple TRIMs in flight, so we don't call
  976                          * cam_iosched_submit_trim(softc->cam_iosched);
  977                          * since that forces the I/O scheduler to only schedule one at a time.
  978                          * On NVMe drives, this is a performance disaster.
  979                          */
  980                         goto out;
  981                 }
  982                 case BIO_FLUSH:
  983                         nda_nvme_flush(softc, nvmeio);
  984                         break;
  985                 }
  986                 start_ccb->ccb_state = NDA_CCB_BUFFER_IO;
  987                 start_ccb->ccb_bp = bp;
  988 out:
  989                 start_ccb->ccb_h.flags |= CAM_UNLOCKED;
  990                 softc->outstanding_cmds++;
  991                 softc->refcount++;                      /* For submission only */
  992                 cam_periph_unlock(periph);
  993                 xpt_action(start_ccb);
  994                 cam_periph_lock(periph);
  995                 softc->refcount--;                      /* Submission done */
  996 
  997                 /* May have more work to do, so ensure we stay scheduled */
  998                 ndaschedule(periph);
  999                 break;
 1000                 }
 1001         }
 1002 }
 1003 
 1004 static void
 1005 ndadone(struct cam_periph *periph, union ccb *done_ccb)
 1006 {
 1007         struct nda_softc *softc;
 1008         struct ccb_nvmeio *nvmeio = &done_ccb->nvmeio;
 1009         struct cam_path *path;
 1010         int state;
 1011 
 1012         softc = (struct nda_softc *)periph->softc;
 1013         path = done_ccb->ccb_h.path;
 1014 
 1015         CAM_DEBUG(path, CAM_DEBUG_TRACE, ("ndadone\n"));
 1016 
 1017         state = nvmeio->ccb_state & NDA_CCB_TYPE_MASK;
 1018         switch (state) {
 1019         case NDA_CCB_BUFFER_IO:
 1020         case NDA_CCB_TRIM:
 1021         {
 1022                 int error;
 1023 
 1024                 cam_periph_lock(periph);
 1025                 if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
 1026                         error = ndaerror(done_ccb, 0, 0);
 1027                         if (error == ERESTART) {
 1028                                 /* A retry was scheduled, so just return. */
 1029                                 cam_periph_unlock(periph);
 1030                                 return;
 1031                         }
 1032                         if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0)
 1033                                 cam_release_devq(path,
 1034                                                  /*relsim_flags*/0,
 1035                                                  /*reduction*/0,
 1036                                                  /*timeout*/0,
 1037                                                  /*getcount_only*/0);
 1038                 } else {
 1039                         if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0)
 1040                                 panic("REQ_CMP with QFRZN");
 1041                         error = 0;
 1042                 }
 1043                 if (state == NDA_CCB_BUFFER_IO) {
 1044                         struct bio *bp;
 1045 
 1046                         bp = (struct bio *)done_ccb->ccb_bp;
 1047                         bp->bio_error = error;
 1048                         if (error != 0) {
 1049                                 bp->bio_resid = bp->bio_bcount;
 1050                                 bp->bio_flags |= BIO_ERROR;
 1051                         } else {
 1052                                 bp->bio_resid = 0;
 1053                         }
 1054                         softc->outstanding_cmds--;
 1055 
 1056                         /*
 1057                          * We need to call cam_iosched before we call biodone so that we
 1058                          * don't measure any activity that happens in the completion
 1059                          * routine, which in the case of sendfile can be quite
 1060                          * extensive.
 1061                          */
 1062                         cam_iosched_bio_complete(softc->cam_iosched, bp, done_ccb);
 1063                         xpt_release_ccb(done_ccb);
 1064                         ndaschedule(periph);
 1065                         cam_periph_unlock(periph);
 1066                         biodone(bp);
 1067                 } else { /* state == NDA_CCB_TRIM */
 1068                         struct nda_trim_request *trim;
 1069                         struct bio *bp1, *bp2;
 1070                         TAILQ_HEAD(, bio) queue;
 1071 
 1072                         trim = nvmeio->ccb_trim;
 1073                         TAILQ_INIT(&queue);
 1074                         TAILQ_CONCAT(&queue, &trim->bps, bio_queue);
 1075                         free(trim, M_NVMEDA);
 1076 
 1077                         /*
 1078                          * Since we can have multiple trims in flight, we don't
 1079                          * need to call this here.
 1080                          * cam_iosched_trim_done(softc->cam_iosched);
 1081                          */
 1082                         /*
 1083                          * The the I/O scheduler that we're finishing the I/O
 1084                          * so we can keep book. The first one we pass in the CCB
 1085                          * which has the timing information. The rest we pass in NULL
 1086                          * so we can keep proper counts.
 1087                          */
 1088                         bp1 = TAILQ_FIRST(&queue);
 1089                         cam_iosched_bio_complete(softc->cam_iosched, bp1, done_ccb);
 1090                         xpt_release_ccb(done_ccb);
 1091                         softc->outstanding_cmds--;
 1092                         ndaschedule(periph);
 1093                         cam_periph_unlock(periph);
 1094                         while ((bp2 = TAILQ_FIRST(&queue)) != NULL) {
 1095                                 TAILQ_REMOVE(&queue, bp2, bio_queue);
 1096                                 bp2->bio_error = error;
 1097                                 if (error != 0) {
 1098                                         bp2->bio_flags |= BIO_ERROR;
 1099                                         bp2->bio_resid = bp1->bio_bcount;
 1100                                 } else
 1101                                         bp2->bio_resid = 0;
 1102                                 if (bp1 != bp2)
 1103                                         cam_iosched_bio_complete(softc->cam_iosched, bp2, NULL);
 1104                                 biodone(bp2);
 1105                         }
 1106                 }
 1107                 return;
 1108         }
 1109         case NDA_CCB_DUMP:
 1110                 /* No-op.  We're polling */
 1111                 return;
 1112         default:
 1113                 break;
 1114         }
 1115         xpt_release_ccb(done_ccb);
 1116 }
 1117 
 1118 static int
 1119 ndaerror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags)
 1120 {
 1121         struct nda_softc *softc;
 1122         struct cam_periph *periph;
 1123 
 1124         periph = xpt_path_periph(ccb->ccb_h.path);
 1125         softc = (struct nda_softc *)periph->softc;
 1126 
 1127         switch (ccb->ccb_h.status & CAM_STATUS_MASK) {
 1128         case CAM_CMD_TIMEOUT:
 1129 #ifdef CAM_IO_STATS
 1130                 softc->timeouts++;
 1131 #endif
 1132                 break;
 1133         case CAM_REQ_ABORTED:
 1134         case CAM_REQ_CMP_ERR:
 1135         case CAM_REQ_TERMIO:
 1136         case CAM_UNREC_HBA_ERROR:
 1137         case CAM_DATA_RUN_ERR:
 1138         case CAM_ATA_STATUS_ERROR:
 1139 #ifdef CAM_IO_STATS
 1140                 softc->errors++;
 1141 #endif
 1142                 break;
 1143         default:
 1144                 break;
 1145         }
 1146 
 1147         return(cam_periph_error(ccb, cam_flags, sense_flags));
 1148 }
 1149 
 1150 /*
 1151  * Step through all NDA peripheral drivers, and if the device is still open,
 1152  * sync the disk cache to physical media.
 1153  */
 1154 static void
 1155 ndaflush(void)
 1156 {
 1157         struct cam_periph *periph;
 1158         struct nda_softc *softc;
 1159         union ccb *ccb;
 1160         int error;
 1161 
 1162         CAM_PERIPH_FOREACH(periph, &ndadriver) {
 1163                 softc = (struct nda_softc *)periph->softc;
 1164 
 1165                 if (SCHEDULER_STOPPED()) {
 1166                         /*
 1167                          * If we paniced with the lock held or the periph is not
 1168                          * open, do not recurse.  Otherwise, call ndadump since
 1169                          * that avoids the sleeping cam_periph_getccb does if no
 1170                          * CCBs are available.
 1171                          */
 1172                         if (!cam_periph_owned(periph) &&
 1173                             (softc->flags & NDA_FLAG_OPEN)) {
 1174                                 ndadump(softc->disk, NULL, 0, 0, 0);
 1175                         }
 1176                         continue;
 1177                 }
 1178 
 1179                 /*
 1180                  * We only sync the cache if the drive is still open
 1181                  */
 1182                 cam_periph_lock(periph);
 1183                 if ((softc->flags & NDA_FLAG_OPEN) == 0) {
 1184                         cam_periph_unlock(periph);
 1185                         continue;
 1186                 }
 1187 
 1188                 ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL);
 1189                 nda_nvme_flush(softc, &ccb->nvmeio);
 1190                 error = cam_periph_runccb(ccb, ndaerror, /*cam_flags*/0,
 1191                     /*sense_flags*/ SF_NO_RECOVERY | SF_NO_RETRY,
 1192                     softc->disk->d_devstat);
 1193                 if (error != 0)
 1194                         xpt_print(periph->path, "Synchronize cache failed\n");
 1195                 xpt_release_ccb(ccb);
 1196                 cam_periph_unlock(periph);
 1197         }
 1198 }
 1199 
 1200 static void
 1201 ndashutdown(void *arg, int howto)
 1202 {
 1203 
 1204         ndaflush();
 1205 }
 1206 
 1207 static void
 1208 ndasuspend(void *arg)
 1209 {
 1210 
 1211         ndaflush();
 1212 }

Cache object: 619fcfcb14d5a36b67451e6c583281af


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