1898b0535SWarner Losh /*- 28b8a9b1dSJustin T. Gibbs * Common functions for CAM "type" (peripheral) drivers. 38b8a9b1dSJustin T. Gibbs * 44d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 5bec9534dSPedro F. Giffuni * 68b8a9b1dSJustin T. Gibbs * Copyright (c) 1997, 1998 Justin T. Gibbs. 7501468a5SKenneth D. Merry * Copyright (c) 1997, 1998, 1999, 2000 Kenneth D. Merry. 88b8a9b1dSJustin T. Gibbs * All rights reserved. 98b8a9b1dSJustin T. Gibbs * 108b8a9b1dSJustin T. Gibbs * Redistribution and use in source and binary forms, with or without 118b8a9b1dSJustin T. Gibbs * modification, are permitted provided that the following conditions 128b8a9b1dSJustin T. Gibbs * are met: 138b8a9b1dSJustin T. Gibbs * 1. Redistributions of source code must retain the above copyright 148b8a9b1dSJustin T. Gibbs * notice, this list of conditions, and the following disclaimer, 158b8a9b1dSJustin T. Gibbs * without modification, immediately at the beginning of the file. 168b8a9b1dSJustin T. Gibbs * 2. The name of the author may not be used to endorse or promote products 178b8a9b1dSJustin T. Gibbs * derived from this software without specific prior written permission. 188b8a9b1dSJustin T. Gibbs * 198b8a9b1dSJustin T. Gibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 208b8a9b1dSJustin T. Gibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 218b8a9b1dSJustin T. Gibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 228b8a9b1dSJustin T. Gibbs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 238b8a9b1dSJustin T. Gibbs * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 248b8a9b1dSJustin T. Gibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 258b8a9b1dSJustin T. Gibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 268b8a9b1dSJustin T. Gibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 278b8a9b1dSJustin T. Gibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 288b8a9b1dSJustin T. Gibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 298b8a9b1dSJustin T. Gibbs * SUCH DAMAGE. 308b8a9b1dSJustin T. Gibbs */ 318b8a9b1dSJustin T. Gibbs 328b8a9b1dSJustin T. Gibbs #include <sys/param.h> 338b8a9b1dSJustin T. Gibbs #include <sys/systm.h> 348b8a9b1dSJustin T. Gibbs #include <sys/types.h> 358b8a9b1dSJustin T. Gibbs #include <sys/malloc.h> 36362abc44STai-hwa Liang #include <sys/kernel.h> 379626b608SPoul-Henning Kamp #include <sys/bio.h> 385cf3cd10SWarner Losh #include <sys/conf.h> 39773e541eSWarner Losh #include <sys/devctl.h> 40f34fa851SJohn Baldwin #include <sys/lock.h> 41f34fa851SJohn Baldwin #include <sys/mutex.h> 428b8a9b1dSJustin T. Gibbs #include <sys/buf.h> 438b8a9b1dSJustin T. Gibbs #include <sys/proc.h> 448b8a9b1dSJustin T. Gibbs #include <sys/devicestat.h> 453501942bSJustin T. Gibbs #include <sys/sbuf.h> 46b059686aSAlexander Motin #include <sys/sysctl.h> 478b8a9b1dSJustin T. Gibbs #include <vm/vm.h> 488b8a9b1dSJustin T. Gibbs #include <vm/vm_extern.h> 498b8a9b1dSJustin T. Gibbs 508b8a9b1dSJustin T. Gibbs #include <cam/cam.h> 518b8a9b1dSJustin T. Gibbs #include <cam/cam_ccb.h> 520cd631eeSMark Johnston #include <cam/cam_compat.h> 5352c9ce25SScott Long #include <cam/cam_queue.h> 548b8a9b1dSJustin T. Gibbs #include <cam/cam_xpt_periph.h> 55447b3557SJohn Baldwin #include <cam/cam_xpt_internal.h> 568b8a9b1dSJustin T. Gibbs #include <cam/cam_periph.h> 578b8a9b1dSJustin T. Gibbs #include <cam/cam_debug.h> 582b83592fSScott Long #include <cam/cam_sim.h> 598b8a9b1dSJustin T. Gibbs 608b8a9b1dSJustin T. Gibbs #include <cam/scsi/scsi_all.h> 618b8a9b1dSJustin T. Gibbs #include <cam/scsi/scsi_message.h> 628b8a9b1dSJustin T. Gibbs #include <cam/scsi/scsi_pass.h> 638b8a9b1dSJustin T. Gibbs 648b8a9b1dSJustin T. Gibbs static u_int camperiphnextunit(struct periph_driver *p_drv, 65d836c48eSWarner Losh u_int newunit, bool wired, 66501468a5SKenneth D. Merry path_id_t pathid, target_id_t target, 67501468a5SKenneth D. Merry lun_id_t lun); 688b8a9b1dSJustin T. Gibbs static u_int camperiphunit(struct periph_driver *p_drv, 69501468a5SKenneth D. Merry path_id_t pathid, target_id_t target, 70577f9aa2SWarner Losh lun_id_t lun, 71577f9aa2SWarner Losh const char *sn); 728b8a9b1dSJustin T. Gibbs static void camperiphdone(struct cam_periph *periph, 738b8a9b1dSJustin T. Gibbs union ccb *done_ccb); 748b8a9b1dSJustin T. Gibbs static void camperiphfree(struct cam_periph *periph); 753393f8daSKenneth D. Merry static int camperiphscsistatuserror(union ccb *ccb, 760191d9b3SAlexander Motin union ccb **orig_ccb, 773393f8daSKenneth D. Merry cam_flags camflags, 787af2f2c8SWarner Losh uint32_t sense_flags, 793393f8daSKenneth D. Merry int *openings, 807af2f2c8SWarner Losh uint32_t *relsim_flags, 817af2f2c8SWarner Losh uint32_t *timeout, 827af2f2c8SWarner Losh uint32_t *action, 8383c5d981SAlexander Motin const char **action_string); 843393f8daSKenneth D. Merry static int camperiphscsisenseerror(union ccb *ccb, 850191d9b3SAlexander Motin union ccb **orig_ccb, 863393f8daSKenneth D. Merry cam_flags camflags, 877af2f2c8SWarner Losh uint32_t sense_flags, 883393f8daSKenneth D. Merry int *openings, 897af2f2c8SWarner Losh uint32_t *relsim_flags, 907af2f2c8SWarner Losh uint32_t *timeout, 917af2f2c8SWarner Losh uint32_t *action, 9283c5d981SAlexander Motin const char **action_string); 93a30ecd42SScott Long static void cam_periph_devctl_notify(union ccb *ccb); 948b8a9b1dSJustin T. Gibbs 950b7c27b9SPeter Wemm static int nperiph_drivers; 9683c5d981SAlexander Motin static int initialized = 0; 970b7c27b9SPeter Wemm struct periph_driver **periph_drivers; 980b7c27b9SPeter Wemm 99d745c852SEd Schouten static MALLOC_DEFINE(M_CAMPERIPH, "CAM periph", "CAM peripheral buffers"); 100362abc44STai-hwa Liang 10173cf209fSMatt Jacob static int periph_selto_delay = 1000; 10273cf209fSMatt Jacob TUNABLE_INT("kern.cam.periph_selto_delay", &periph_selto_delay); 10373cf209fSMatt Jacob static int periph_noresrc_delay = 500; 10473cf209fSMatt Jacob TUNABLE_INT("kern.cam.periph_noresrc_delay", &periph_noresrc_delay); 10573cf209fSMatt Jacob static int periph_busy_delay = 500; 10673cf209fSMatt Jacob TUNABLE_INT("kern.cam.periph_busy_delay", &periph_busy_delay); 10773cf209fSMatt Jacob 108b059686aSAlexander Motin static u_int periph_mapmem_thresh = 65536; 109b059686aSAlexander Motin SYSCTL_UINT(_kern_cam, OID_AUTO, mapmem_thresh, CTLFLAG_RWTUN, 110b059686aSAlexander Motin &periph_mapmem_thresh, 0, "Threshold for user-space buffer mapping"); 11173cf209fSMatt Jacob 1120b7c27b9SPeter Wemm void 1130b7c27b9SPeter Wemm periphdriver_register(void *data) 1140b7c27b9SPeter Wemm { 11583c5d981SAlexander Motin struct periph_driver *drv = (struct periph_driver *)data; 1160b7c27b9SPeter Wemm struct periph_driver **newdrivers, **old; 1170b7c27b9SPeter Wemm int ndrivers; 1180b7c27b9SPeter Wemm 1195719711fSEdward Tomasz Napierala again: 1200b7c27b9SPeter Wemm ndrivers = nperiph_drivers + 2; 1210dd50e9bSScott Long newdrivers = malloc(sizeof(*newdrivers) * ndrivers, M_CAMPERIPH, 1220dd50e9bSScott Long M_WAITOK); 1235719711fSEdward Tomasz Napierala xpt_lock_buses(); 1245719711fSEdward Tomasz Napierala if (ndrivers != nperiph_drivers + 2) { 1255719711fSEdward Tomasz Napierala /* 1265719711fSEdward Tomasz Napierala * Lost race against itself; go around. 1275719711fSEdward Tomasz Napierala */ 1285719711fSEdward Tomasz Napierala xpt_unlock_buses(); 1295719711fSEdward Tomasz Napierala free(newdrivers, M_CAMPERIPH); 1305719711fSEdward Tomasz Napierala goto again; 1315719711fSEdward Tomasz Napierala } 1320b7c27b9SPeter Wemm if (periph_drivers) 1330b7c27b9SPeter Wemm bcopy(periph_drivers, newdrivers, 134623db360SKenneth D. Merry sizeof(*newdrivers) * nperiph_drivers); 13583c5d981SAlexander Motin newdrivers[nperiph_drivers] = drv; 1360b7c27b9SPeter Wemm newdrivers[nperiph_drivers + 1] = NULL; 1370b7c27b9SPeter Wemm old = periph_drivers; 1380b7c27b9SPeter Wemm periph_drivers = newdrivers; 1395719711fSEdward Tomasz Napierala nperiph_drivers++; 1405719711fSEdward Tomasz Napierala xpt_unlock_buses(); 1410b7c27b9SPeter Wemm if (old) 1420dd50e9bSScott Long free(old, M_CAMPERIPH); 14383c5d981SAlexander Motin /* If driver marked as early or it is late now, initialize it. */ 14483c5d981SAlexander Motin if (((drv->flags & CAM_PERIPH_DRV_EARLY) != 0 && initialized > 0) || 14583c5d981SAlexander Motin initialized > 1) 14683c5d981SAlexander Motin (*drv->init)(); 14783c5d981SAlexander Motin } 14883c5d981SAlexander Motin 14994173c3cSAlexander Motin int 15094173c3cSAlexander Motin periphdriver_unregister(void *data) 15194173c3cSAlexander Motin { 15294173c3cSAlexander Motin struct periph_driver *drv = (struct periph_driver *)data; 15394173c3cSAlexander Motin int error, n; 15494173c3cSAlexander Motin 15594173c3cSAlexander Motin /* If driver marked as early or it is late now, deinitialize it. */ 15694173c3cSAlexander Motin if (((drv->flags & CAM_PERIPH_DRV_EARLY) != 0 && initialized > 0) || 15794173c3cSAlexander Motin initialized > 1) { 15894173c3cSAlexander Motin if (drv->deinit == NULL) { 15994173c3cSAlexander Motin printf("CAM periph driver '%s' doesn't have deinit.\n", 16094173c3cSAlexander Motin drv->driver_name); 16194173c3cSAlexander Motin return (EOPNOTSUPP); 16294173c3cSAlexander Motin } 16394173c3cSAlexander Motin error = drv->deinit(); 16494173c3cSAlexander Motin if (error != 0) 16594173c3cSAlexander Motin return (error); 16694173c3cSAlexander Motin } 16794173c3cSAlexander Motin 16894173c3cSAlexander Motin xpt_lock_buses(); 16994173c3cSAlexander Motin for (n = 0; n < nperiph_drivers && periph_drivers[n] != drv; n++) 17094173c3cSAlexander Motin ; 17194173c3cSAlexander Motin KASSERT(n < nperiph_drivers, 17294173c3cSAlexander Motin ("Periph driver '%s' was not registered", drv->driver_name)); 17394173c3cSAlexander Motin for (; n + 1 < nperiph_drivers; n++) 17494173c3cSAlexander Motin periph_drivers[n] = periph_drivers[n + 1]; 17594173c3cSAlexander Motin periph_drivers[n + 1] = NULL; 17694173c3cSAlexander Motin nperiph_drivers--; 17794173c3cSAlexander Motin xpt_unlock_buses(); 17894173c3cSAlexander Motin return (0); 17994173c3cSAlexander Motin } 18094173c3cSAlexander Motin 18183c5d981SAlexander Motin void 18283c5d981SAlexander Motin periphdriver_init(int level) 18383c5d981SAlexander Motin { 18483c5d981SAlexander Motin int i, early; 18583c5d981SAlexander Motin 18683c5d981SAlexander Motin initialized = max(initialized, level); 18783c5d981SAlexander Motin for (i = 0; periph_drivers[i] != NULL; i++) { 18883c5d981SAlexander Motin early = (periph_drivers[i]->flags & CAM_PERIPH_DRV_EARLY) ? 1 : 2; 18983c5d981SAlexander Motin if (early == initialized) 19083c5d981SAlexander Motin (*periph_drivers[i]->init)(); 19183c5d981SAlexander Motin } 1920b7c27b9SPeter Wemm } 1930b7c27b9SPeter Wemm 1948b8a9b1dSJustin T. Gibbs cam_status 195ee9c90c7SKenneth D. Merry cam_periph_alloc(periph_ctor_t *periph_ctor, 196ee9c90c7SKenneth D. Merry periph_oninv_t *periph_oninvalidate, 197ee9c90c7SKenneth D. Merry periph_dtor_t *periph_dtor, periph_start_t *periph_start, 198ee9c90c7SKenneth D. Merry char *name, cam_periph_type type, struct cam_path *path, 199ee9c90c7SKenneth D. Merry ac_callback_t *ac_callback, ac_code code, void *arg) 2008b8a9b1dSJustin T. Gibbs { 2018b8a9b1dSJustin T. Gibbs struct periph_driver **p_drv; 2022b83592fSScott Long struct cam_sim *sim; 2038b8a9b1dSJustin T. Gibbs struct cam_periph *periph; 2048b8a9b1dSJustin T. Gibbs struct cam_periph *cur_periph; 2058b8a9b1dSJustin T. Gibbs path_id_t path_id; 2068b8a9b1dSJustin T. Gibbs target_id_t target_id; 2078b8a9b1dSJustin T. Gibbs lun_id_t lun_id; 2088b8a9b1dSJustin T. Gibbs cam_status status; 2098b8a9b1dSJustin T. Gibbs u_int init_level; 2108b8a9b1dSJustin T. Gibbs 2118b8a9b1dSJustin T. Gibbs init_level = 0; 2128b8a9b1dSJustin T. Gibbs /* 2138b8a9b1dSJustin T. Gibbs * Handle Hot-Plug scenarios. If there is already a peripheral 2148b8a9b1dSJustin T. Gibbs * of our type assigned to this path, we are likely waiting for 2158b8a9b1dSJustin T. Gibbs * final close on an old, invalidated, peripheral. If this is 2168b8a9b1dSJustin T. Gibbs * the case, queue up a deferred call to the peripheral's async 21774c91ec5SJustin T. Gibbs * handler. If it looks like a mistaken re-allocation, complain. 2188b8a9b1dSJustin T. Gibbs */ 2198b8a9b1dSJustin T. Gibbs if ((periph = cam_periph_find(path, name)) != NULL) { 2208b8a9b1dSJustin T. Gibbs if ((periph->flags & CAM_PERIPH_INVALID) != 0 2218b8a9b1dSJustin T. Gibbs && (periph->flags & CAM_PERIPH_NEW_DEV_FOUND) == 0) { 2228b8a9b1dSJustin T. Gibbs periph->flags |= CAM_PERIPH_NEW_DEV_FOUND; 2238b8a9b1dSJustin T. Gibbs periph->deferred_callback = ac_callback; 2248b8a9b1dSJustin T. Gibbs periph->deferred_ac = code; 2258b8a9b1dSJustin T. Gibbs return (CAM_REQ_INPROG); 2268b8a9b1dSJustin T. Gibbs } else { 2278b8a9b1dSJustin T. Gibbs printf("cam_periph_alloc: attempt to re-allocate " 2288900f4b8SKenneth D. Merry "valid device %s%d rejected flags %#x " 2298900f4b8SKenneth D. Merry "refcount %d\n", periph->periph_name, 2308900f4b8SKenneth D. Merry periph->unit_number, periph->flags, 2318900f4b8SKenneth D. Merry periph->refcount); 2328b8a9b1dSJustin T. Gibbs } 2338b8a9b1dSJustin T. Gibbs return (CAM_REQ_INVALID); 2348b8a9b1dSJustin T. Gibbs } 2358b8a9b1dSJustin T. Gibbs 236362abc44STai-hwa Liang periph = (struct cam_periph *)malloc(sizeof(*periph), M_CAMPERIPH, 2378900f4b8SKenneth D. Merry M_NOWAIT|M_ZERO); 2388b8a9b1dSJustin T. Gibbs 2398b8a9b1dSJustin T. Gibbs if (periph == NULL) 2408b8a9b1dSJustin T. Gibbs return (CAM_RESRC_UNAVAIL); 2418b8a9b1dSJustin T. Gibbs 2428b8a9b1dSJustin T. Gibbs init_level++; 2438b8a9b1dSJustin T. Gibbs 2442b83592fSScott Long sim = xpt_path_sim(path); 2458b8a9b1dSJustin T. Gibbs path_id = xpt_path_path_id(path); 2468b8a9b1dSJustin T. Gibbs target_id = xpt_path_target_id(path); 2478b8a9b1dSJustin T. Gibbs lun_id = xpt_path_lun_id(path); 2488b8a9b1dSJustin T. Gibbs periph->periph_start = periph_start; 2498b8a9b1dSJustin T. Gibbs periph->periph_dtor = periph_dtor; 250ee9c90c7SKenneth D. Merry periph->periph_oninval = periph_oninvalidate; 2518b8a9b1dSJustin T. Gibbs periph->type = type; 2528b8a9b1dSJustin T. Gibbs periph->periph_name = name; 253227d67aaSAlexander Motin periph->scheduled_priority = CAM_PRIORITY_NONE; 2548b8a9b1dSJustin T. Gibbs periph->immediate_priority = CAM_PRIORITY_NONE; 255d38c0e53SAlexander Motin periph->refcount = 1; /* Dropped by invalidation. */ 2562b83592fSScott Long periph->sim = sim; 2578b8a9b1dSJustin T. Gibbs SLIST_INIT(&periph->ccb_list); 2588b8a9b1dSJustin T. Gibbs status = xpt_create_path(&path, periph, path_id, target_id, lun_id); 2598b8a9b1dSJustin T. Gibbs if (status != CAM_REQ_CMP) 2608b8a9b1dSJustin T. Gibbs goto failure; 2618b8a9b1dSJustin T. Gibbs periph->path = path; 2628b8a9b1dSJustin T. Gibbs 263f1e2546aSMatt Jacob xpt_lock_buses(); 264f1e2546aSMatt Jacob for (p_drv = periph_drivers; *p_drv != NULL; p_drv++) { 265f1e2546aSMatt Jacob if (strcmp((*p_drv)->driver_name, name) == 0) 266f1e2546aSMatt Jacob break; 267f1e2546aSMatt Jacob } 268f1e2546aSMatt Jacob if (*p_drv == NULL) { 269f1e2546aSMatt Jacob printf("cam_periph_alloc: invalid periph name '%s'\n", name); 2709e0d30e2SEdward Tomasz Napierala xpt_unlock_buses(); 271f1e2546aSMatt Jacob xpt_free_path(periph->path); 272f1e2546aSMatt Jacob free(periph, M_CAMPERIPH); 273f1e2546aSMatt Jacob return (CAM_REQ_INVALID); 274f1e2546aSMatt Jacob } 275577f9aa2SWarner Losh periph->unit_number = camperiphunit(*p_drv, path_id, target_id, lun_id, 276577f9aa2SWarner Losh path->device->serial_num); 2778b8a9b1dSJustin T. Gibbs cur_periph = TAILQ_FIRST(&(*p_drv)->units); 2788b8a9b1dSJustin T. Gibbs while (cur_periph != NULL 2798b8a9b1dSJustin T. Gibbs && cur_periph->unit_number < periph->unit_number) 2808b8a9b1dSJustin T. Gibbs cur_periph = TAILQ_NEXT(cur_periph, unit_links); 281f1e2546aSMatt Jacob if (cur_periph != NULL) { 282dbfe5dd3SWarner Losh KASSERT(cur_periph->unit_number != periph->unit_number, 283dbfe5dd3SWarner Losh ("duplicate units on periph list")); 2848b8a9b1dSJustin T. Gibbs TAILQ_INSERT_BEFORE(cur_periph, periph, unit_links); 285f1e2546aSMatt Jacob } else { 2868b8a9b1dSJustin T. Gibbs TAILQ_INSERT_TAIL(&(*p_drv)->units, periph, unit_links); 2878b8a9b1dSJustin T. Gibbs (*p_drv)->generation++; 2888b8a9b1dSJustin T. Gibbs } 289f1e2546aSMatt Jacob xpt_unlock_buses(); 290f1e2546aSMatt Jacob 291f1e2546aSMatt Jacob init_level++; 292f1e2546aSMatt Jacob 293f1e2546aSMatt Jacob status = xpt_add_periph(periph); 294f1e2546aSMatt Jacob if (status != CAM_REQ_CMP) 295f1e2546aSMatt Jacob goto failure; 2968b8a9b1dSJustin T. Gibbs 2978b8a9b1dSJustin T. Gibbs init_level++; 29822c7d606SAlexander Motin CAM_DEBUG(periph->path, CAM_DEBUG_INFO, ("Periph created\n")); 2998b8a9b1dSJustin T. Gibbs 3008b8a9b1dSJustin T. Gibbs status = periph_ctor(periph, arg); 3018b8a9b1dSJustin T. Gibbs 3028b8a9b1dSJustin T. Gibbs if (status == CAM_REQ_CMP) 3038b8a9b1dSJustin T. Gibbs init_level++; 3048b8a9b1dSJustin T. Gibbs 3058b8a9b1dSJustin T. Gibbs failure: 3068b8a9b1dSJustin T. Gibbs switch (init_level) { 3078b8a9b1dSJustin T. Gibbs case 4: 3088b8a9b1dSJustin T. Gibbs /* Initialized successfully */ 3098b8a9b1dSJustin T. Gibbs break; 3108b8a9b1dSJustin T. Gibbs case 3: 31122c7d606SAlexander Motin CAM_DEBUG(periph->path, CAM_DEBUG_INFO, ("Periph destroyed\n")); 312a29779e8SAlexander Motin xpt_remove_periph(periph); 3137379c88fSPoul-Henning Kamp /* FALLTHROUGH */ 3148b8a9b1dSJustin T. Gibbs case 2: 315f1e2546aSMatt Jacob xpt_lock_buses(); 316f1e2546aSMatt Jacob TAILQ_REMOVE(&(*p_drv)->units, periph, unit_links); 317f1e2546aSMatt Jacob xpt_unlock_buses(); 3188b8a9b1dSJustin T. Gibbs xpt_free_path(periph->path); 3197379c88fSPoul-Henning Kamp /* FALLTHROUGH */ 3208b8a9b1dSJustin T. Gibbs case 1: 321362abc44STai-hwa Liang free(periph, M_CAMPERIPH); 3227379c88fSPoul-Henning Kamp /* FALLTHROUGH */ 3238b8a9b1dSJustin T. Gibbs case 0: 3248b8a9b1dSJustin T. Gibbs /* No cleanup to perform. */ 3258b8a9b1dSJustin T. Gibbs break; 3268b8a9b1dSJustin T. Gibbs default: 327905cb85dSKenneth D. Merry panic("%s: Unknown init level", __func__); 3288b8a9b1dSJustin T. Gibbs } 3298b8a9b1dSJustin T. Gibbs return(status); 3308b8a9b1dSJustin T. Gibbs } 3318b8a9b1dSJustin T. Gibbs 3328b8a9b1dSJustin T. Gibbs /* 3338b8a9b1dSJustin T. Gibbs * Find a peripheral structure with the specified path, target, lun, 3348b8a9b1dSJustin T. Gibbs * and (optionally) type. If the name is NULL, this function will return 3358b8a9b1dSJustin T. Gibbs * the first peripheral driver that matches the specified path. 3368b8a9b1dSJustin T. Gibbs */ 3378b8a9b1dSJustin T. Gibbs struct cam_periph * 3388b8a9b1dSJustin T. Gibbs cam_periph_find(struct cam_path *path, char *name) 3398b8a9b1dSJustin T. Gibbs { 3408b8a9b1dSJustin T. Gibbs struct periph_driver **p_drv; 3418b8a9b1dSJustin T. Gibbs struct cam_periph *periph; 3428b8a9b1dSJustin T. Gibbs 34377dc25ccSScott Long xpt_lock_buses(); 3440b7c27b9SPeter Wemm for (p_drv = periph_drivers; *p_drv != NULL; p_drv++) { 3458b8a9b1dSJustin T. Gibbs if (name != NULL && (strcmp((*p_drv)->driver_name, name) != 0)) 3468b8a9b1dSJustin T. Gibbs continue; 3478b8a9b1dSJustin T. Gibbs 34837d40066SPoul-Henning Kamp TAILQ_FOREACH(periph, &(*p_drv)->units, unit_links) { 3498b8a9b1dSJustin T. Gibbs if (xpt_path_comp(periph->path, path) == 0) { 35077dc25ccSScott Long xpt_unlock_buses(); 351227d67aaSAlexander Motin cam_periph_assert(periph, MA_OWNED); 3528b8a9b1dSJustin T. Gibbs return(periph); 3538b8a9b1dSJustin T. Gibbs } 3548b8a9b1dSJustin T. Gibbs } 35577dc25ccSScott Long if (name != NULL) { 35677dc25ccSScott Long xpt_unlock_buses(); 3578b8a9b1dSJustin T. Gibbs return(NULL); 3588b8a9b1dSJustin T. Gibbs } 35977dc25ccSScott Long } 36077dc25ccSScott Long xpt_unlock_buses(); 3618b8a9b1dSJustin T. Gibbs return(NULL); 3628b8a9b1dSJustin T. Gibbs } 3638b8a9b1dSJustin T. Gibbs 3643501942bSJustin T. Gibbs /* 3658900f4b8SKenneth D. Merry * Find peripheral driver instances attached to the specified path. 3663501942bSJustin T. Gibbs */ 3673501942bSJustin T. Gibbs int 3683501942bSJustin T. Gibbs cam_periph_list(struct cam_path *path, struct sbuf *sb) 3693501942bSJustin T. Gibbs { 3708900f4b8SKenneth D. Merry struct sbuf local_sb; 3713501942bSJustin T. Gibbs struct periph_driver **p_drv; 3723501942bSJustin T. Gibbs struct cam_periph *periph; 3733501942bSJustin T. Gibbs int count; 3748900f4b8SKenneth D. Merry int sbuf_alloc_len; 3753501942bSJustin T. Gibbs 3768900f4b8SKenneth D. Merry sbuf_alloc_len = 16; 3778900f4b8SKenneth D. Merry retry: 3788900f4b8SKenneth D. Merry sbuf_new(&local_sb, NULL, sbuf_alloc_len, SBUF_FIXEDLEN); 3793501942bSJustin T. Gibbs count = 0; 3803501942bSJustin T. Gibbs xpt_lock_buses(); 3813501942bSJustin T. Gibbs for (p_drv = periph_drivers; *p_drv != NULL; p_drv++) { 3823501942bSJustin T. Gibbs TAILQ_FOREACH(periph, &(*p_drv)->units, unit_links) { 3833501942bSJustin T. Gibbs if (xpt_path_comp(periph->path, path) != 0) 3843501942bSJustin T. Gibbs continue; 3853501942bSJustin T. Gibbs 3868900f4b8SKenneth D. Merry if (sbuf_len(&local_sb) != 0) 3878900f4b8SKenneth D. Merry sbuf_cat(&local_sb, ","); 3883501942bSJustin T. Gibbs 3898900f4b8SKenneth D. Merry sbuf_printf(&local_sb, "%s%d", periph->periph_name, 3903501942bSJustin T. Gibbs periph->unit_number); 3918900f4b8SKenneth D. Merry 3928900f4b8SKenneth D. Merry if (sbuf_error(&local_sb) == ENOMEM) { 3938900f4b8SKenneth D. Merry sbuf_alloc_len *= 2; 3948900f4b8SKenneth D. Merry xpt_unlock_buses(); 3958900f4b8SKenneth D. Merry sbuf_delete(&local_sb); 3968900f4b8SKenneth D. Merry goto retry; 3978900f4b8SKenneth D. Merry } 3983501942bSJustin T. Gibbs count++; 3993501942bSJustin T. Gibbs } 4003501942bSJustin T. Gibbs } 4013501942bSJustin T. Gibbs xpt_unlock_buses(); 4028900f4b8SKenneth D. Merry sbuf_finish(&local_sb); 40307f7e4c8SAlexander Motin if (sbuf_len(sb) != 0) 40407f7e4c8SAlexander Motin sbuf_cat(sb, ","); 40507f7e4c8SAlexander Motin sbuf_cat(sb, sbuf_data(&local_sb)); 4068900f4b8SKenneth D. Merry sbuf_delete(&local_sb); 4073501942bSJustin T. Gibbs return (count); 4083501942bSJustin T. Gibbs } 4093501942bSJustin T. Gibbs 41099e7a4adSScott Long int 4118b8a9b1dSJustin T. Gibbs cam_periph_acquire(struct cam_periph *periph) 4128b8a9b1dSJustin T. Gibbs { 41399e7a4adSScott Long int status; 4148b8a9b1dSJustin T. Gibbs 4158b8a9b1dSJustin T. Gibbs if (periph == NULL) 41699e7a4adSScott Long return (EINVAL); 4178b8a9b1dSJustin T. Gibbs 41899e7a4adSScott Long status = ENOENT; 4192b83592fSScott Long xpt_lock_buses(); 4208900f4b8SKenneth D. Merry if ((periph->flags & CAM_PERIPH_INVALID) == 0) { 4218b8a9b1dSJustin T. Gibbs periph->refcount++; 42299e7a4adSScott Long status = 0; 4238900f4b8SKenneth D. Merry } 4242b83592fSScott Long xpt_unlock_buses(); 4258b8a9b1dSJustin T. Gibbs 4268900f4b8SKenneth D. Merry return (status); 4278900f4b8SKenneth D. Merry } 4288900f4b8SKenneth D. Merry 4298900f4b8SKenneth D. Merry void 430c33e4029SAlexander Motin cam_periph_doacquire(struct cam_periph *periph) 431c33e4029SAlexander Motin { 432c33e4029SAlexander Motin 433c33e4029SAlexander Motin xpt_lock_buses(); 434c33e4029SAlexander Motin KASSERT(periph->refcount >= 1, 435c33e4029SAlexander Motin ("cam_periph_doacquire() with refcount == %d", periph->refcount)); 436c33e4029SAlexander Motin periph->refcount++; 437c33e4029SAlexander Motin xpt_unlock_buses(); 438c33e4029SAlexander Motin } 439c33e4029SAlexander Motin 440c33e4029SAlexander Motin void 4418900f4b8SKenneth D. Merry cam_periph_release_locked_buses(struct cam_periph *periph) 4428900f4b8SKenneth D. Merry { 443dcdf6e74SAlexander Motin 444227d67aaSAlexander Motin cam_periph_assert(periph, MA_OWNED); 445dcdf6e74SAlexander Motin KASSERT(periph->refcount >= 1, ("periph->refcount >= 1")); 446d38c0e53SAlexander Motin if (--periph->refcount == 0) 4478900f4b8SKenneth D. Merry camperiphfree(periph); 4488900f4b8SKenneth D. Merry } 4498b8a9b1dSJustin T. Gibbs 4508b8a9b1dSJustin T. Gibbs void 45124ebf566SEdward Tomasz Napierala cam_periph_release_locked(struct cam_periph *periph) 4528b8a9b1dSJustin T. Gibbs { 4538b8a9b1dSJustin T. Gibbs 4548b8a9b1dSJustin T. Gibbs if (periph == NULL) 4558b8a9b1dSJustin T. Gibbs return; 4568b8a9b1dSJustin T. Gibbs 4572b83592fSScott Long xpt_lock_buses(); 4588900f4b8SKenneth D. Merry cam_periph_release_locked_buses(periph); 4592b83592fSScott Long xpt_unlock_buses(); 46024ebf566SEdward Tomasz Napierala } 4618b8a9b1dSJustin T. Gibbs 46224ebf566SEdward Tomasz Napierala void 46324ebf566SEdward Tomasz Napierala cam_periph_release(struct cam_periph *periph) 46424ebf566SEdward Tomasz Napierala { 465227d67aaSAlexander Motin struct mtx *mtx; 46624ebf566SEdward Tomasz Napierala 46724ebf566SEdward Tomasz Napierala if (periph == NULL) 46824ebf566SEdward Tomasz Napierala return; 46924ebf566SEdward Tomasz Napierala 470227d67aaSAlexander Motin cam_periph_assert(periph, MA_NOTOWNED); 471227d67aaSAlexander Motin mtx = cam_periph_mtx(periph); 472227d67aaSAlexander Motin mtx_lock(mtx); 47324ebf566SEdward Tomasz Napierala cam_periph_release_locked(periph); 474227d67aaSAlexander Motin mtx_unlock(mtx); 4758b8a9b1dSJustin T. Gibbs } 4768b8a9b1dSJustin T. Gibbs 4779385e92bSWarner Losh /* 4789385e92bSWarner Losh * hold/unhold act as mutual exclusion for sections of the code that 4799385e92bSWarner Losh * need to sleep and want to make sure that other sections that 4809385e92bSWarner Losh * will interfere are held off. This only protects exclusive sections 4819385e92bSWarner Losh * from each other. 4829385e92bSWarner Losh */ 4832b83592fSScott Long int 4842b83592fSScott Long cam_periph_hold(struct cam_periph *periph, int priority) 4852b83592fSScott Long { 4862b83592fSScott Long int error; 4872b83592fSScott Long 4882b83592fSScott Long /* 4892b83592fSScott Long * Increment the reference count on the peripheral 4902b83592fSScott Long * while we wait for our lock attempt to succeed 4912b83592fSScott Long * to ensure the peripheral doesn't disappear out 4922b83592fSScott Long * from user us while we sleep. 4932b83592fSScott Long */ 4942b83592fSScott Long 49599e7a4adSScott Long if (cam_periph_acquire(periph) != 0) 4962b83592fSScott Long return (ENXIO); 4972b83592fSScott Long 498227d67aaSAlexander Motin cam_periph_assert(periph, MA_OWNED); 4992b83592fSScott Long while ((periph->flags & CAM_PERIPH_LOCKED) != 0) { 5002b83592fSScott Long periph->flags |= CAM_PERIPH_LOCK_WANTED; 501227d67aaSAlexander Motin if ((error = cam_periph_sleep(periph, periph, priority, 5021fa738c2SJohn Baldwin "caplck", 0)) != 0) { 50324ebf566SEdward Tomasz Napierala cam_periph_release_locked(periph); 5042b83592fSScott Long return (error); 5052b83592fSScott Long } 506aed9c88cSAlexander Motin if (periph->flags & CAM_PERIPH_INVALID) { 507aed9c88cSAlexander Motin cam_periph_release_locked(periph); 508aed9c88cSAlexander Motin return (ENXIO); 509aed9c88cSAlexander Motin } 5102b83592fSScott Long } 5112b83592fSScott Long 5122b83592fSScott Long periph->flags |= CAM_PERIPH_LOCKED; 5132b83592fSScott Long return (0); 5142b83592fSScott Long } 5152b83592fSScott Long 5162b83592fSScott Long void 5172b83592fSScott Long cam_periph_unhold(struct cam_periph *periph) 5182b83592fSScott Long { 5192b83592fSScott Long 520227d67aaSAlexander Motin cam_periph_assert(periph, MA_OWNED); 5212b83592fSScott Long 5222b83592fSScott Long periph->flags &= ~CAM_PERIPH_LOCKED; 5232b83592fSScott Long if ((periph->flags & CAM_PERIPH_LOCK_WANTED) != 0) { 5242b83592fSScott Long periph->flags &= ~CAM_PERIPH_LOCK_WANTED; 5252b83592fSScott Long wakeup(periph); 5262b83592fSScott Long } 5272b83592fSScott Long 52824ebf566SEdward Tomasz Napierala cam_periph_release_locked(periph); 5292b83592fSScott Long } 5302b83592fSScott Long 53190bcc81bSAlexander Motin void 53290bcc81bSAlexander Motin cam_periph_hold_boot(struct cam_periph *periph) 53390bcc81bSAlexander Motin { 53490bcc81bSAlexander Motin 53590bcc81bSAlexander Motin root_mount_hold_token(periph->periph_name, &periph->periph_rootmount); 53690bcc81bSAlexander Motin } 53790bcc81bSAlexander Motin 53890bcc81bSAlexander Motin void 53990bcc81bSAlexander Motin cam_periph_release_boot(struct cam_periph *periph) 54090bcc81bSAlexander Motin { 54190bcc81bSAlexander Motin 54290bcc81bSAlexander Motin root_mount_rel(&periph->periph_rootmount); 54390bcc81bSAlexander Motin } 54490bcc81bSAlexander Motin 5458b8a9b1dSJustin T. Gibbs /* 5468b8a9b1dSJustin T. Gibbs * Look for the next unit number that is not currently in use for this 5478b8a9b1dSJustin T. Gibbs * peripheral type starting at "newunit". Also exclude unit numbers that 5488b8a9b1dSJustin T. Gibbs * are reserved by for future "hardwiring" unless we already know that this 5498b8a9b1dSJustin T. Gibbs * is a potential wired device. Only assume that the device is "wired" the 5508b8a9b1dSJustin T. Gibbs * first time through the loop since after that we'll be looking at unit 5518b8a9b1dSJustin T. Gibbs * numbers that did not match a wiring entry. 5528b8a9b1dSJustin T. Gibbs */ 5538b8a9b1dSJustin T. Gibbs static u_int 554d836c48eSWarner Losh camperiphnextunit(struct periph_driver *p_drv, u_int newunit, bool wired, 555501468a5SKenneth D. Merry path_id_t pathid, target_id_t target, lun_id_t lun) 5568b8a9b1dSJustin T. Gibbs { 5578b8a9b1dSJustin T. Gibbs struct cam_periph *periph; 5582398f0cdSPeter Wemm char *periph_name; 5592398f0cdSPeter Wemm int i, val, dunit, r; 5602398f0cdSPeter Wemm const char *dname, *strval; 5618b8a9b1dSJustin T. Gibbs 5628b8a9b1dSJustin T. Gibbs periph_name = p_drv->driver_name; 5638b8a9b1dSJustin T. Gibbs for (;;newunit++) { 5648b8a9b1dSJustin T. Gibbs for (periph = TAILQ_FIRST(&p_drv->units); 5658b8a9b1dSJustin T. Gibbs periph != NULL && periph->unit_number != newunit; 5668b8a9b1dSJustin T. Gibbs periph = TAILQ_NEXT(periph, unit_links)) 5678b8a9b1dSJustin T. Gibbs ; 5688b8a9b1dSJustin T. Gibbs 5698b8a9b1dSJustin T. Gibbs if (periph != NULL && periph->unit_number == newunit) { 570d836c48eSWarner Losh if (wired) { 571f0d9af51SMatt Jacob xpt_print(periph->path, "Duplicate Wired " 572f0d9af51SMatt Jacob "Device entry!\n"); 573f0d9af51SMatt Jacob xpt_print(periph->path, "Second device (%s " 574f0d9af51SMatt Jacob "device at scbus%d target %d lun %d) will " 575f0d9af51SMatt Jacob "not be wired\n", periph_name, pathid, 576f0d9af51SMatt Jacob target, lun); 577d836c48eSWarner Losh wired = false; 5788b8a9b1dSJustin T. Gibbs } 5798b8a9b1dSJustin T. Gibbs continue; 5808b8a9b1dSJustin T. Gibbs } 58175f51904SPeter Wemm if (wired) 58275f51904SPeter Wemm break; 5838b8a9b1dSJustin T. Gibbs 5848b8a9b1dSJustin T. Gibbs /* 58500f79c97SWarner Losh * Don't allow the mere presence of any attributes of a device 58600f79c97SWarner Losh * means that it is for a wired down entry. Instead, insist that 58700f79c97SWarner Losh * one of the matching criteria from camperiphunit be present 58800f79c97SWarner Losh * for the device. 5898b8a9b1dSJustin T. Gibbs */ 5902398f0cdSPeter Wemm i = 0; 5912398f0cdSPeter Wemm dname = periph_name; 5922398f0cdSPeter Wemm for (;;) { 5932398f0cdSPeter Wemm r = resource_find_dev(&i, dname, &dunit, NULL, NULL); 5942398f0cdSPeter Wemm if (r != 0) 5952398f0cdSPeter Wemm break; 596bee0133fSWarner Losh 597bee0133fSWarner Losh if (newunit != dunit) 59875f51904SPeter Wemm continue; 599577f9aa2SWarner Losh if (resource_string_value(dname, dunit, "sn", &strval) == 0 || 600577f9aa2SWarner Losh resource_int_value(dname, dunit, "lun", &val) == 0 || 601710a519eSWarner Losh resource_int_value(dname, dunit, "target", &val) == 0 || 602bee0133fSWarner Losh resource_string_value(dname, dunit, "at", &strval) == 0) 6038b8a9b1dSJustin T. Gibbs break; 6048b8a9b1dSJustin T. Gibbs } 6052398f0cdSPeter Wemm if (r != 0) 6068b8a9b1dSJustin T. Gibbs break; 6078b8a9b1dSJustin T. Gibbs } 6088b8a9b1dSJustin T. Gibbs return (newunit); 6098b8a9b1dSJustin T. Gibbs } 6108b8a9b1dSJustin T. Gibbs 6118b8a9b1dSJustin T. Gibbs static u_int 6128b8a9b1dSJustin T. Gibbs camperiphunit(struct periph_driver *p_drv, path_id_t pathid, 613577f9aa2SWarner Losh target_id_t target, lun_id_t lun, const char *sn) 6148b8a9b1dSJustin T. Gibbs { 6153846662dSWarner Losh bool wired = false; 6168b8a9b1dSJustin T. Gibbs u_int unit; 617d836c48eSWarner Losh int i, val, dunit; 6182398f0cdSPeter Wemm const char *dname, *strval; 6192398f0cdSPeter Wemm char pathbuf[32], *periph_name; 6208b8a9b1dSJustin T. Gibbs 62175f51904SPeter Wemm periph_name = p_drv->driver_name; 62275f51904SPeter Wemm snprintf(pathbuf, sizeof(pathbuf), "scbus%d", pathid); 623c1b81613SPeter Wemm unit = 0; 6242398f0cdSPeter Wemm i = 0; 6252398f0cdSPeter Wemm dname = periph_name; 626272e4f53SWarner Losh 627272e4f53SWarner Losh for (wired = false; resource_find_dev(&i, dname, &dunit, NULL, NULL) == 0; 628272e4f53SWarner Losh wired = false) { 62975f51904SPeter Wemm if (resource_string_value(dname, dunit, "at", &strval) == 0) { 63075f51904SPeter Wemm if (strcmp(strval, pathbuf) != 0) 6318b8a9b1dSJustin T. Gibbs continue; 632d836c48eSWarner Losh wired = true; 6338b8a9b1dSJustin T. Gibbs } 63475f51904SPeter Wemm if (resource_int_value(dname, dunit, "target", &val) == 0) { 63575f51904SPeter Wemm if (val != target) 6368b8a9b1dSJustin T. Gibbs continue; 637d836c48eSWarner Losh wired = true; 6388b8a9b1dSJustin T. Gibbs } 63975f51904SPeter Wemm if (resource_int_value(dname, dunit, "lun", &val) == 0) { 64075f51904SPeter Wemm if (val != lun) 6418b8a9b1dSJustin T. Gibbs continue; 642d836c48eSWarner Losh wired = true; 6438b8a9b1dSJustin T. Gibbs } 644577f9aa2SWarner Losh if (resource_string_value(dname, dunit, "sn", &strval) == 0) { 645577f9aa2SWarner Losh if (sn == NULL || strcmp(strval, sn) != 0) 646577f9aa2SWarner Losh continue; 647d836c48eSWarner Losh wired = true; 648577f9aa2SWarner Losh } 649d836c48eSWarner Losh if (wired) { 65075f51904SPeter Wemm unit = dunit; 6518b8a9b1dSJustin T. Gibbs break; 6528b8a9b1dSJustin T. Gibbs } 6538b8a9b1dSJustin T. Gibbs } 6548b8a9b1dSJustin T. Gibbs 6558b8a9b1dSJustin T. Gibbs /* 6568b8a9b1dSJustin T. Gibbs * Either start from 0 looking for the next unit or from 65775f51904SPeter Wemm * the unit number given in the resource config. This way, 6588b8a9b1dSJustin T. Gibbs * if we have wildcard matches, we don't return the same 6598b8a9b1dSJustin T. Gibbs * unit number twice. 6608b8a9b1dSJustin T. Gibbs */ 661c1b81613SPeter Wemm unit = camperiphnextunit(p_drv, unit, wired, pathid, target, lun); 6628b8a9b1dSJustin T. Gibbs 6638b8a9b1dSJustin T. Gibbs return (unit); 6648b8a9b1dSJustin T. Gibbs } 6658b8a9b1dSJustin T. Gibbs 6668b8a9b1dSJustin T. Gibbs void 6678b8a9b1dSJustin T. Gibbs cam_periph_invalidate(struct cam_periph *periph) 6688b8a9b1dSJustin T. Gibbs { 6698b8a9b1dSJustin T. Gibbs 670227d67aaSAlexander Motin cam_periph_assert(periph, MA_OWNED); 671ee9c90c7SKenneth D. Merry /* 6726fda2c54SWarner Losh * We only tear down the device the first time a peripheral is 67377dc25ccSScott Long * invalidated. 674ee9c90c7SKenneth D. Merry */ 675d38c0e53SAlexander Motin if ((periph->flags & CAM_PERIPH_INVALID) != 0) 676d38c0e53SAlexander Motin return; 677ee9c90c7SKenneth D. Merry 678d38c0e53SAlexander Motin CAM_DEBUG(periph->path, CAM_DEBUG_INFO, ("Periph invalidated\n")); 6795d01277fSScott Long if ((periph->flags & CAM_PERIPH_ANNOUNCED) && !rebooting) { 6805d01277fSScott Long struct sbuf sb; 681da0d7209SScott Long char buffer[160]; 6825d01277fSScott Long 683da0d7209SScott Long sbuf_new(&sb, buffer, 160, SBUF_FIXEDLEN); 6845d01277fSScott Long xpt_denounce_periph_sbuf(periph, &sb); 6855d01277fSScott Long sbuf_finish(&sb); 6865d01277fSScott Long sbuf_putbuf(&sb); 6875d01277fSScott Long } 6888b8a9b1dSJustin T. Gibbs periph->flags |= CAM_PERIPH_INVALID; 6898b8a9b1dSJustin T. Gibbs periph->flags &= ~CAM_PERIPH_NEW_DEV_FOUND; 690d38c0e53SAlexander Motin if (periph->periph_oninval != NULL) 691d38c0e53SAlexander Motin periph->periph_oninval(periph); 692d38c0e53SAlexander Motin cam_periph_release_locked(periph); 6938b8a9b1dSJustin T. Gibbs } 6948b8a9b1dSJustin T. Gibbs 6958b8a9b1dSJustin T. Gibbs static void 6968b8a9b1dSJustin T. Gibbs camperiphfree(struct cam_periph *periph) 6978b8a9b1dSJustin T. Gibbs { 6988b8a9b1dSJustin T. Gibbs struct periph_driver **p_drv; 69959fe7664SKenneth D. Merry struct periph_driver *drv; 7008b8a9b1dSJustin T. Gibbs 701227d67aaSAlexander Motin cam_periph_assert(periph, MA_OWNED); 702227d67aaSAlexander Motin KASSERT(periph->periph_allocating == 0, ("%s%d: freed while allocating", 703227d67aaSAlexander Motin periph->periph_name, periph->unit_number)); 7040b7c27b9SPeter Wemm for (p_drv = periph_drivers; *p_drv != NULL; p_drv++) { 7058b8a9b1dSJustin T. Gibbs if (strcmp((*p_drv)->driver_name, periph->periph_name) == 0) 7068b8a9b1dSJustin T. Gibbs break; 7078b8a9b1dSJustin T. Gibbs } 708661658a6SScott Long if (*p_drv == NULL) { 709661658a6SScott Long printf("camperiphfree: attempt to free non-existant periph\n"); 710661658a6SScott Long return; 711661658a6SScott Long } 71259fe7664SKenneth D. Merry /* 71359fe7664SKenneth D. Merry * Cache a pointer to the periph_driver structure. If a 71459fe7664SKenneth D. Merry * periph_driver is added or removed from the array (see 71559fe7664SKenneth D. Merry * periphdriver_register()) while we drop the toplogy lock 71659fe7664SKenneth D. Merry * below, p_drv may change. This doesn't protect against this 71759fe7664SKenneth D. Merry * particular periph_driver going away. That will require full 71859fe7664SKenneth D. Merry * reference counting in the periph_driver infrastructure. 71959fe7664SKenneth D. Merry */ 72059fe7664SKenneth D. Merry drv = *p_drv; 7218b8a9b1dSJustin T. Gibbs 722ea37f519SKenneth D. Merry /* 72333a38f74SKenneth D. Merry * We need to set this flag before dropping the topology lock, to 72433a38f74SKenneth D. Merry * let anyone who is traversing the list that this peripheral is 72533a38f74SKenneth D. Merry * about to be freed, and there will be no more reference count 72633a38f74SKenneth D. Merry * checks. 72733a38f74SKenneth D. Merry */ 72833a38f74SKenneth D. Merry periph->flags |= CAM_PERIPH_FREE; 72933a38f74SKenneth D. Merry 73033a38f74SKenneth D. Merry /* 731ea37f519SKenneth D. Merry * The peripheral destructor semantics dictate calling with only the 732ea37f519SKenneth D. Merry * SIM mutex held. Since it might sleep, it should not be called 733ea37f519SKenneth D. Merry * with the topology lock held. 734ea37f519SKenneth D. Merry */ 735f3548746SScott Long xpt_unlock_buses(); 7368b8a9b1dSJustin T. Gibbs 737ea37f519SKenneth D. Merry /* 738ea37f519SKenneth D. Merry * We need to call the peripheral destructor prior to removing the 739ea37f519SKenneth D. Merry * peripheral from the list. Otherwise, we risk running into a 740ea37f519SKenneth D. Merry * scenario where the peripheral unit number may get reused 741ea37f519SKenneth D. Merry * (because it has been removed from the list), but some resources 742ea37f519SKenneth D. Merry * used by the peripheral are still hanging around. In particular, 743ea37f519SKenneth D. Merry * the devfs nodes used by some peripherals like the pass(4) driver 744ea37f519SKenneth D. Merry * aren't fully cleaned up until the destructor is run. If the 745ea37f519SKenneth D. Merry * unit number is reused before the devfs instance is fully gone, 746ea37f519SKenneth D. Merry * devfs will panic. 747ea37f519SKenneth D. Merry */ 748f3548746SScott Long if (periph->periph_dtor != NULL) 749f3548746SScott Long periph->periph_dtor(periph); 750ea37f519SKenneth D. Merry 751ea37f519SKenneth D. Merry /* 75281490edaSWarner Losh * The peripheral list is protected by the topology lock. We have to 75381490edaSWarner Losh * remove the periph from the drv list before we call deferred_ac. The 75481490edaSWarner Losh * AC_FOUND_DEVICE callback won't create a new periph if it's still there. 755ea37f519SKenneth D. Merry */ 756ea37f519SKenneth D. Merry xpt_lock_buses(); 757ea37f519SKenneth D. Merry 75859fe7664SKenneth D. Merry TAILQ_REMOVE(&drv->units, periph, unit_links); 75959fe7664SKenneth D. Merry drv->generation++; 760ea37f519SKenneth D. Merry 761a29779e8SAlexander Motin xpt_remove_periph(periph); 762ea37f519SKenneth D. Merry 763ea37f519SKenneth D. Merry xpt_unlock_buses(); 764de6a705eSMarius Strobl if ((periph->flags & CAM_PERIPH_ANNOUNCED) && !rebooting) 7658d36a71bSAlexander Motin xpt_print(periph->path, "Periph destroyed\n"); 766de6a705eSMarius Strobl else 76722c7d606SAlexander Motin CAM_DEBUG(periph->path, CAM_DEBUG_INFO, ("Periph destroyed\n")); 7688b8a9b1dSJustin T. Gibbs 7698b8a9b1dSJustin T. Gibbs if (periph->flags & CAM_PERIPH_NEW_DEV_FOUND) { 7708b8a9b1dSJustin T. Gibbs union ccb ccb; 7718b8a9b1dSJustin T. Gibbs void *arg; 7728b8a9b1dSJustin T. Gibbs 773076686feSEdward Tomasz Napierala memset(&ccb, 0, sizeof(ccb)); 7748b8a9b1dSJustin T. Gibbs switch (periph->deferred_ac) { 7758b8a9b1dSJustin T. Gibbs case AC_FOUND_DEVICE: 7768b8a9b1dSJustin T. Gibbs ccb.ccb_h.func_code = XPT_GDEV_TYPE; 777bbfa4aa1SAlexander Motin xpt_setup_ccb(&ccb.ccb_h, periph->path, CAM_PRIORITY_NORMAL); 7788b8a9b1dSJustin T. Gibbs xpt_action(&ccb); 7798b8a9b1dSJustin T. Gibbs arg = &ccb; 7808b8a9b1dSJustin T. Gibbs break; 7818b8a9b1dSJustin T. Gibbs case AC_PATH_REGISTERED: 782762a7f4fSWarner Losh xpt_path_inq(&ccb.cpi, periph->path); 7838b8a9b1dSJustin T. Gibbs arg = &ccb; 7848b8a9b1dSJustin T. Gibbs break; 7858b8a9b1dSJustin T. Gibbs default: 7868b8a9b1dSJustin T. Gibbs arg = NULL; 7878b8a9b1dSJustin T. Gibbs break; 7888b8a9b1dSJustin T. Gibbs } 7898b8a9b1dSJustin T. Gibbs periph->deferred_callback(NULL, periph->deferred_ac, 7908b8a9b1dSJustin T. Gibbs periph->path, arg); 7918b8a9b1dSJustin T. Gibbs } 7928b8a9b1dSJustin T. Gibbs xpt_free_path(periph->path); 793362abc44STai-hwa Liang free(periph, M_CAMPERIPH); 794f3548746SScott Long xpt_lock_buses(); 7958b8a9b1dSJustin T. Gibbs } 7968b8a9b1dSJustin T. Gibbs 7978b8a9b1dSJustin T. Gibbs /* 7988b8a9b1dSJustin T. Gibbs * Map user virtual pointers into kernel virtual address space, so we can 79995fbded6SScott Long * access the memory. This is now a generic function that centralizes most 80095fbded6SScott Long * of the sanity checks on the data flags, if any. 801cd853791SKonstantin Belousov * This also only works for up to maxphys memory. Since we use 8028b8a9b1dSJustin T. Gibbs * buffers to map stuff in and out, we're limited to the buffer size. 8038b8a9b1dSJustin T. Gibbs */ 8048b8a9b1dSJustin T. Gibbs int 805de239312SAlexander Motin cam_periph_mapmem(union ccb *ccb, struct cam_periph_map_info *mapinfo, 806de239312SAlexander Motin u_int maxmap) 8078b8a9b1dSJustin T. Gibbs { 808b059686aSAlexander Motin int numbufs, i; 8097af2f2c8SWarner Losh uint8_t **data_ptrs[CAM_PERIPH_MAXMAPS]; 8107af2f2c8SWarner Losh uint32_t lengths[CAM_PERIPH_MAXMAPS]; 8117af2f2c8SWarner Losh uint32_t dirs[CAM_PERIPH_MAXMAPS]; 8128b8a9b1dSJustin T. Gibbs 813b059686aSAlexander Motin bzero(mapinfo, sizeof(*mapinfo)); 814de239312SAlexander Motin if (maxmap == 0) 815de239312SAlexander Motin maxmap = DFLTPHYS; /* traditional default */ 816cd853791SKonstantin Belousov else if (maxmap > maxphys) 817cd853791SKonstantin Belousov maxmap = maxphys; /* for safety */ 8188b8a9b1dSJustin T. Gibbs switch(ccb->ccb_h.func_code) { 8198b8a9b1dSJustin T. Gibbs case XPT_DEV_MATCH: 8208b8a9b1dSJustin T. Gibbs if (ccb->cdm.match_buf_len == 0) { 8218b8a9b1dSJustin T. Gibbs printf("cam_periph_mapmem: invalid match buffer " 8228b8a9b1dSJustin T. Gibbs "length 0\n"); 8238b8a9b1dSJustin T. Gibbs return(EINVAL); 8248b8a9b1dSJustin T. Gibbs } 8258b8a9b1dSJustin T. Gibbs if (ccb->cdm.pattern_buf_len > 0) { 8267af2f2c8SWarner Losh data_ptrs[0] = (uint8_t **)&ccb->cdm.patterns; 8278b8a9b1dSJustin T. Gibbs lengths[0] = ccb->cdm.pattern_buf_len; 8288b8a9b1dSJustin T. Gibbs dirs[0] = CAM_DIR_OUT; 8297af2f2c8SWarner Losh data_ptrs[1] = (uint8_t **)&ccb->cdm.matches; 8308b8a9b1dSJustin T. Gibbs lengths[1] = ccb->cdm.match_buf_len; 8318b8a9b1dSJustin T. Gibbs dirs[1] = CAM_DIR_IN; 8328b8a9b1dSJustin T. Gibbs numbufs = 2; 8338b8a9b1dSJustin T. Gibbs } else { 8347af2f2c8SWarner Losh data_ptrs[0] = (uint8_t **)&ccb->cdm.matches; 8358b8a9b1dSJustin T. Gibbs lengths[0] = ccb->cdm.match_buf_len; 8368b8a9b1dSJustin T. Gibbs dirs[0] = CAM_DIR_IN; 8378b8a9b1dSJustin T. Gibbs numbufs = 1; 8388b8a9b1dSJustin T. Gibbs } 83952c9ce25SScott Long /* 84052c9ce25SScott Long * This request will not go to the hardware, no reason 841cd853791SKonstantin Belousov * to be so strict. vmapbuf() is able to map up to maxphys. 84252c9ce25SScott Long */ 843cd853791SKonstantin Belousov maxmap = maxphys; 8448b8a9b1dSJustin T. Gibbs break; 8458b8a9b1dSJustin T. Gibbs case XPT_SCSI_IO: 84687cfaf0eSJustin T. Gibbs case XPT_CONT_TARGET_IO: 8478b8a9b1dSJustin T. Gibbs if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_NONE) 8488b8a9b1dSJustin T. Gibbs return(0); 84995fbded6SScott Long if ((ccb->ccb_h.flags & CAM_DATA_MASK) != CAM_DATA_VADDR) 85095fbded6SScott Long return (EINVAL); 8518b8a9b1dSJustin T. Gibbs data_ptrs[0] = &ccb->csio.data_ptr; 85279d49a06SKenneth D. Merry lengths[0] = ccb->csio.dxfer_len; 8538b8a9b1dSJustin T. Gibbs dirs[0] = ccb->ccb_h.flags & CAM_DIR_MASK; 8548b8a9b1dSJustin T. Gibbs numbufs = 1; 8558b8a9b1dSJustin T. Gibbs break; 85652c9ce25SScott Long case XPT_ATA_IO: 85752c9ce25SScott Long if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_NONE) 85852c9ce25SScott Long return(0); 85995fbded6SScott Long if ((ccb->ccb_h.flags & CAM_DATA_MASK) != CAM_DATA_VADDR) 86095fbded6SScott Long return (EINVAL); 86152c9ce25SScott Long data_ptrs[0] = &ccb->ataio.data_ptr; 86252c9ce25SScott Long lengths[0] = ccb->ataio.dxfer_len; 86352c9ce25SScott Long dirs[0] = ccb->ccb_h.flags & CAM_DIR_MASK; 86452c9ce25SScott Long numbufs = 1; 86552c9ce25SScott Long break; 866a94a63f0SWarner Losh case XPT_MMC_IO: 867a94a63f0SWarner Losh if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_NONE) 868a94a63f0SWarner Losh return(0); 869a94a63f0SWarner Losh /* Two mappings: one for cmd->data and one for cmd->data->data */ 870a94a63f0SWarner Losh data_ptrs[0] = (unsigned char **)&ccb->mmcio.cmd.data; 871a94a63f0SWarner Losh lengths[0] = sizeof(struct mmc_data *); 872a94a63f0SWarner Losh dirs[0] = ccb->ccb_h.flags & CAM_DIR_MASK; 873a94a63f0SWarner Losh data_ptrs[1] = (unsigned char **)&ccb->mmcio.cmd.data->data; 874a94a63f0SWarner Losh lengths[1] = ccb->mmcio.cmd.data->len; 875a94a63f0SWarner Losh dirs[1] = ccb->ccb_h.flags & CAM_DIR_MASK; 876a94a63f0SWarner Losh numbufs = 2; 877a94a63f0SWarner Losh break; 87806e79492SKenneth D. Merry case XPT_SMP_IO: 87906e79492SKenneth D. Merry data_ptrs[0] = &ccb->smpio.smp_request; 88006e79492SKenneth D. Merry lengths[0] = ccb->smpio.smp_request_len; 88106e79492SKenneth D. Merry dirs[0] = CAM_DIR_OUT; 88206e79492SKenneth D. Merry data_ptrs[1] = &ccb->smpio.smp_response; 88306e79492SKenneth D. Merry lengths[1] = ccb->smpio.smp_response_len; 88406e79492SKenneth D. Merry dirs[1] = CAM_DIR_IN; 88506e79492SKenneth D. Merry numbufs = 2; 88606e79492SKenneth D. Merry break; 887df424515SWarner Losh case XPT_NVME_IO: 888df424515SWarner Losh case XPT_NVME_ADMIN: 889df424515SWarner Losh if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_NONE) 890df424515SWarner Losh return (0); 891df424515SWarner Losh if ((ccb->ccb_h.flags & CAM_DATA_MASK) != CAM_DATA_VADDR) 892df424515SWarner Losh return (EINVAL); 893df424515SWarner Losh data_ptrs[0] = &ccb->nvmeio.data_ptr; 894df424515SWarner Losh lengths[0] = ccb->nvmeio.dxfer_len; 895df424515SWarner Losh dirs[0] = ccb->ccb_h.flags & CAM_DIR_MASK; 896df424515SWarner Losh numbufs = 1; 897df424515SWarner Losh break; 8983501942bSJustin T. Gibbs case XPT_DEV_ADVINFO: 8993501942bSJustin T. Gibbs if (ccb->cdai.bufsiz == 0) 9007c103ddeSKenneth D. Merry return (0); 9017c103ddeSKenneth D. Merry 9023501942bSJustin T. Gibbs data_ptrs[0] = (uint8_t **)&ccb->cdai.buf; 9033501942bSJustin T. Gibbs lengths[0] = ccb->cdai.bufsiz; 90406e79492SKenneth D. Merry dirs[0] = CAM_DIR_IN; 90506e79492SKenneth D. Merry numbufs = 1; 9067c103ddeSKenneth D. Merry 9077c103ddeSKenneth D. Merry /* 9087c103ddeSKenneth D. Merry * This request will not go to the hardware, no reason 909cd853791SKonstantin Belousov * to be so strict. vmapbuf() is able to map up to maxphys. 9107c103ddeSKenneth D. Merry */ 911cd853791SKonstantin Belousov maxmap = maxphys; 91206e79492SKenneth D. Merry break; 9138b8a9b1dSJustin T. Gibbs default: 9148b8a9b1dSJustin T. Gibbs return(EINVAL); 9158b8a9b1dSJustin T. Gibbs break; /* NOTREACHED */ 9168b8a9b1dSJustin T. Gibbs } 9178b8a9b1dSJustin T. Gibbs 9188b8a9b1dSJustin T. Gibbs /* 91979d49a06SKenneth D. Merry * Check the transfer length and permissions first, so we don't 92079d49a06SKenneth D. Merry * have to unmap any previously mapped buffers. 9218b8a9b1dSJustin T. Gibbs */ 9228b8a9b1dSJustin T. Gibbs for (i = 0; i < numbufs; i++) { 923c389a786SAlexander Motin if (lengths[i] > maxmap) { 924c389a786SAlexander Motin printf("cam_periph_mapmem: attempt to map %lu bytes, " 925c389a786SAlexander Motin "which is greater than %lu\n", 926c389a786SAlexander Motin (long)(lengths[i]), (u_long)maxmap); 927c389a786SAlexander Motin return (E2BIG); 928c389a786SAlexander Motin } 92979d49a06SKenneth D. Merry } 93079d49a06SKenneth D. Merry 93179d49a06SKenneth D. Merry /* 932cef367e6SEitan Adler * This keeps the kernel stack of current thread from getting 93395fbded6SScott Long * swapped. In low-memory situations where the kernel stack might 93495fbded6SScott Long * otherwise get swapped out, this holds it and allows the thread 93595fbded6SScott Long * to make progress and release the kernel mapped pages sooner. 93695fbded6SScott Long * 93779d49a06SKenneth D. Merry * XXX KDM should I use P_NOSWAP instead? 93879d49a06SKenneth D. Merry */ 9390cbbb7bfSPeter Wemm PHOLD(curproc); 94079d49a06SKenneth D. Merry 94179d49a06SKenneth D. Merry for (i = 0; i < numbufs; i++) { 942b059686aSAlexander Motin /* Save the user's data address. */ 943b059686aSAlexander Motin mapinfo->orig[i] = *data_ptrs[i]; 944b059686aSAlexander Motin 945b059686aSAlexander Motin /* 946b059686aSAlexander Motin * For small buffers use malloc+copyin/copyout instead of 947b059686aSAlexander Motin * mapping to KVA to avoid expensive TLB shootdowns. For 948b059686aSAlexander Motin * small allocations malloc is backed by UMA, and so much 949b059686aSAlexander Motin * cheaper on SMP systems. 950b059686aSAlexander Motin */ 9519093e27cSAlexander Motin if (lengths[i] <= periph_mapmem_thresh && 952b059686aSAlexander Motin ccb->ccb_h.func_code != XPT_MMC_IO) { 953b059686aSAlexander Motin *data_ptrs[i] = malloc(lengths[i], M_CAMPERIPH, 954b059686aSAlexander Motin M_WAITOK); 955b059686aSAlexander Motin if (dirs[i] != CAM_DIR_IN) { 956b059686aSAlexander Motin if (copyin(mapinfo->orig[i], *data_ptrs[i], 957b059686aSAlexander Motin lengths[i]) != 0) { 958b059686aSAlexander Motin free(*data_ptrs[i], M_CAMPERIPH); 959b059686aSAlexander Motin *data_ptrs[i] = mapinfo->orig[i]; 960b059686aSAlexander Motin goto fail; 961b059686aSAlexander Motin } 962b059686aSAlexander Motin } else 963b059686aSAlexander Motin bzero(*data_ptrs[i], lengths[i]); 964b059686aSAlexander Motin continue; 965b059686aSAlexander Motin } 966b059686aSAlexander Motin 9678b8a9b1dSJustin T. Gibbs /* 9688b8a9b1dSJustin T. Gibbs * Get the buffer. 9698b8a9b1dSJustin T. Gibbs */ 970756a5412SGleb Smirnoff mapinfo->bp[i] = uma_zalloc(pbuf_zone, M_WAITOK); 9718b8a9b1dSJustin T. Gibbs 97221144e3bSPoul-Henning Kamp /* set the direction */ 973b059686aSAlexander Motin mapinfo->bp[i]->b_iocmd = (dirs[i] == CAM_DIR_OUT) ? 974b059686aSAlexander Motin BIO_WRITE : BIO_READ; 9758b8a9b1dSJustin T. Gibbs 976450a2e2aSWarner Losh /* Map the buffer into kernel memory. */ 97744ca4575SBrooks Davis if (vmapbuf(mapinfo->bp[i], *data_ptrs[i], lengths[i], 1) < 0) { 978756a5412SGleb Smirnoff uma_zfree(pbuf_zone, mapinfo->bp[i]); 979b059686aSAlexander Motin goto fail; 9802d5c7e45SMatthew Dillon } 9818b8a9b1dSJustin T. Gibbs 9828b8a9b1dSJustin T. Gibbs /* set our pointer to the new mapped area */ 9838b8a9b1dSJustin T. Gibbs *data_ptrs[i] = mapinfo->bp[i]->b_data; 9848b8a9b1dSJustin T. Gibbs } 9858b8a9b1dSJustin T. Gibbs 986a62525f3SMatt Jacob /* 987a62525f3SMatt Jacob * Now that we've gotten this far, change ownership to the kernel 988a62525f3SMatt Jacob * of the buffers so that we don't run afoul of returning to user 989a62525f3SMatt Jacob * space with locks (on the buffer) held. 990a62525f3SMatt Jacob */ 991a62525f3SMatt Jacob for (i = 0; i < numbufs; i++) { 992b059686aSAlexander Motin if (mapinfo->bp[i]) 993a62525f3SMatt Jacob BUF_KERNPROC(mapinfo->bp[i]); 994a62525f3SMatt Jacob } 995a62525f3SMatt Jacob 996b059686aSAlexander Motin mapinfo->num_bufs_used = numbufs; 9978b8a9b1dSJustin T. Gibbs return(0); 998b059686aSAlexander Motin 999b059686aSAlexander Motin fail: 1000b059686aSAlexander Motin for (i--; i >= 0; i--) { 1001b059686aSAlexander Motin if (mapinfo->bp[i]) { 1002b059686aSAlexander Motin vunmapbuf(mapinfo->bp[i]); 1003b059686aSAlexander Motin uma_zfree(pbuf_zone, mapinfo->bp[i]); 1004b059686aSAlexander Motin } else 1005b059686aSAlexander Motin free(*data_ptrs[i], M_CAMPERIPH); 1006b059686aSAlexander Motin *data_ptrs[i] = mapinfo->orig[i]; 1007b059686aSAlexander Motin } 1008b059686aSAlexander Motin PRELE(curproc); 1009b059686aSAlexander Motin return(EACCES); 10108b8a9b1dSJustin T. Gibbs } 10118b8a9b1dSJustin T. Gibbs 10128b8a9b1dSJustin T. Gibbs /* 10138b8a9b1dSJustin T. Gibbs * Unmap memory segments mapped into kernel virtual address space by 10148b8a9b1dSJustin T. Gibbs * cam_periph_mapmem(). 10158b8a9b1dSJustin T. Gibbs */ 1016*d068ea16SMark Johnston int 10178b8a9b1dSJustin T. Gibbs cam_periph_unmapmem(union ccb *ccb, struct cam_periph_map_info *mapinfo) 10188b8a9b1dSJustin T. Gibbs { 1019*d068ea16SMark Johnston int error, numbufs, i; 10207af2f2c8SWarner Losh uint8_t **data_ptrs[CAM_PERIPH_MAXMAPS]; 10217af2f2c8SWarner Losh uint32_t lengths[CAM_PERIPH_MAXMAPS]; 10227af2f2c8SWarner Losh uint32_t dirs[CAM_PERIPH_MAXMAPS]; 10238b8a9b1dSJustin T. Gibbs 10248b8a9b1dSJustin T. Gibbs if (mapinfo->num_bufs_used <= 0) { 102595fbded6SScott Long /* nothing to free and the process wasn't held. */ 1026*d068ea16SMark Johnston return (0); 10278b8a9b1dSJustin T. Gibbs } 10288b8a9b1dSJustin T. Gibbs 10298b8a9b1dSJustin T. Gibbs switch (ccb->ccb_h.func_code) { 10308b8a9b1dSJustin T. Gibbs case XPT_DEV_MATCH: 1031b059686aSAlexander Motin if (ccb->cdm.pattern_buf_len > 0) { 10327af2f2c8SWarner Losh data_ptrs[0] = (uint8_t **)&ccb->cdm.patterns; 1033b059686aSAlexander Motin lengths[0] = ccb->cdm.pattern_buf_len; 1034b059686aSAlexander Motin dirs[0] = CAM_DIR_OUT; 10357af2f2c8SWarner Losh data_ptrs[1] = (uint8_t **)&ccb->cdm.matches; 1036b059686aSAlexander Motin lengths[1] = ccb->cdm.match_buf_len; 1037b059686aSAlexander Motin dirs[1] = CAM_DIR_IN; 1038b059686aSAlexander Motin numbufs = 2; 1039b059686aSAlexander Motin } else { 10407af2f2c8SWarner Losh data_ptrs[0] = (uint8_t **)&ccb->cdm.matches; 1041b059686aSAlexander Motin lengths[0] = ccb->cdm.match_buf_len; 1042b059686aSAlexander Motin dirs[0] = CAM_DIR_IN; 1043b059686aSAlexander Motin numbufs = 1; 10448b8a9b1dSJustin T. Gibbs } 10458b8a9b1dSJustin T. Gibbs break; 10468b8a9b1dSJustin T. Gibbs case XPT_SCSI_IO: 10479911ecf9SJustin T. Gibbs case XPT_CONT_TARGET_IO: 10488b8a9b1dSJustin T. Gibbs data_ptrs[0] = &ccb->csio.data_ptr; 1049b059686aSAlexander Motin lengths[0] = ccb->csio.dxfer_len; 1050b059686aSAlexander Motin dirs[0] = ccb->ccb_h.flags & CAM_DIR_MASK; 1051b059686aSAlexander Motin numbufs = 1; 10528b8a9b1dSJustin T. Gibbs break; 105352c9ce25SScott Long case XPT_ATA_IO: 105452c9ce25SScott Long data_ptrs[0] = &ccb->ataio.data_ptr; 1055b059686aSAlexander Motin lengths[0] = ccb->ataio.dxfer_len; 1056b059686aSAlexander Motin dirs[0] = ccb->ccb_h.flags & CAM_DIR_MASK; 1057b059686aSAlexander Motin numbufs = 1; 1058b059686aSAlexander Motin break; 1059b059686aSAlexander Motin case XPT_MMC_IO: 10607af2f2c8SWarner Losh data_ptrs[0] = (uint8_t **)&ccb->mmcio.cmd.data; 1061b059686aSAlexander Motin lengths[0] = sizeof(struct mmc_data *); 1062b059686aSAlexander Motin dirs[0] = ccb->ccb_h.flags & CAM_DIR_MASK; 10637af2f2c8SWarner Losh data_ptrs[1] = (uint8_t **)&ccb->mmcio.cmd.data->data; 1064b059686aSAlexander Motin lengths[1] = ccb->mmcio.cmd.data->len; 1065b059686aSAlexander Motin dirs[1] = ccb->ccb_h.flags & CAM_DIR_MASK; 1066b059686aSAlexander Motin numbufs = 2; 106752c9ce25SScott Long break; 106806e79492SKenneth D. Merry case XPT_SMP_IO: 106906e79492SKenneth D. Merry data_ptrs[0] = &ccb->smpio.smp_request; 1070b059686aSAlexander Motin lengths[0] = ccb->smpio.smp_request_len; 1071b059686aSAlexander Motin dirs[0] = CAM_DIR_OUT; 107206e79492SKenneth D. Merry data_ptrs[1] = &ccb->smpio.smp_response; 1073b059686aSAlexander Motin lengths[1] = ccb->smpio.smp_response_len; 1074b059686aSAlexander Motin dirs[1] = CAM_DIR_IN; 1075b059686aSAlexander Motin numbufs = 2; 107606e79492SKenneth D. Merry break; 1077df424515SWarner Losh case XPT_NVME_IO: 1078df424515SWarner Losh case XPT_NVME_ADMIN: 1079df424515SWarner Losh data_ptrs[0] = &ccb->nvmeio.data_ptr; 1080b059686aSAlexander Motin lengths[0] = ccb->nvmeio.dxfer_len; 1081b059686aSAlexander Motin dirs[0] = ccb->ccb_h.flags & CAM_DIR_MASK; 1082b059686aSAlexander Motin numbufs = 1; 1083b059686aSAlexander Motin break; 1084b059686aSAlexander Motin case XPT_DEV_ADVINFO: 1085b059686aSAlexander Motin data_ptrs[0] = (uint8_t **)&ccb->cdai.buf; 1086b059686aSAlexander Motin lengths[0] = ccb->cdai.bufsiz; 1087b059686aSAlexander Motin dirs[0] = CAM_DIR_IN; 1088b059686aSAlexander Motin numbufs = 1; 1089df424515SWarner Losh break; 10908b8a9b1dSJustin T. Gibbs default: 1091*d068ea16SMark Johnston numbufs = 0; 1092*d068ea16SMark Johnston break; 10938b8a9b1dSJustin T. Gibbs } 10948b8a9b1dSJustin T. Gibbs 1095*d068ea16SMark Johnston error = 0; 10968b8a9b1dSJustin T. Gibbs for (i = 0; i < numbufs; i++) { 1097b059686aSAlexander Motin if (mapinfo->bp[i]) { 10988b8a9b1dSJustin T. Gibbs /* unmap the buffer */ 10998b8a9b1dSJustin T. Gibbs vunmapbuf(mapinfo->bp[i]); 11008b8a9b1dSJustin T. Gibbs 11018b8a9b1dSJustin T. Gibbs /* release the buffer */ 1102756a5412SGleb Smirnoff uma_zfree(pbuf_zone, mapinfo->bp[i]); 1103b059686aSAlexander Motin } else { 1104b059686aSAlexander Motin if (dirs[i] != CAM_DIR_OUT) { 1105*d068ea16SMark Johnston int error1; 1106*d068ea16SMark Johnston 1107*d068ea16SMark Johnston error1 = copyout(*data_ptrs[i], mapinfo->orig[i], 1108b059686aSAlexander Motin lengths[i]); 1109*d068ea16SMark Johnston if (error == 0) 1110*d068ea16SMark Johnston error = error1; 1111b059686aSAlexander Motin } 1112b059686aSAlexander Motin free(*data_ptrs[i], M_CAMPERIPH); 1113b059686aSAlexander Motin } 1114b059686aSAlexander Motin 1115b059686aSAlexander Motin /* Set the user's pointer back to the original value */ 1116b059686aSAlexander Motin *data_ptrs[i] = mapinfo->orig[i]; 11178b8a9b1dSJustin T. Gibbs } 11188b8a9b1dSJustin T. Gibbs 11198b8a9b1dSJustin T. Gibbs /* allow ourselves to be swapped once again */ 11200cbbb7bfSPeter Wemm PRELE(curproc); 1121*d068ea16SMark Johnston 1122*d068ea16SMark Johnston return (error); 11238b8a9b1dSJustin T. Gibbs } 11248b8a9b1dSJustin T. Gibbs 11258b8a9b1dSJustin T. Gibbs int 1126571e8e20SScott Long cam_periph_ioctl(struct cam_periph *periph, u_long cmd, caddr_t addr, 11278b8a9b1dSJustin T. Gibbs int (*error_routine)(union ccb *ccb, 11288b8a9b1dSJustin T. Gibbs cam_flags camflags, 11297af2f2c8SWarner Losh uint32_t sense_flags)) 11308b8a9b1dSJustin T. Gibbs { 11318b8a9b1dSJustin T. Gibbs union ccb *ccb; 11328b8a9b1dSJustin T. Gibbs int error; 11338b8a9b1dSJustin T. Gibbs int found; 11348b8a9b1dSJustin T. Gibbs 11358b8a9b1dSJustin T. Gibbs error = found = 0; 11368b8a9b1dSJustin T. Gibbs 11378b8a9b1dSJustin T. Gibbs switch(cmd){ 11380cd631eeSMark Johnston case CAMGETPASSTHRU_0x19: 11398b8a9b1dSJustin T. Gibbs case CAMGETPASSTHRU: 1140bbfa4aa1SAlexander Motin ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL); 11418b8a9b1dSJustin T. Gibbs xpt_setup_ccb(&ccb->ccb_h, 11428b8a9b1dSJustin T. Gibbs ccb->ccb_h.path, 1143bbfa4aa1SAlexander Motin CAM_PRIORITY_NORMAL); 11448b8a9b1dSJustin T. Gibbs ccb->ccb_h.func_code = XPT_GDEVLIST; 11458b8a9b1dSJustin T. Gibbs 11468b8a9b1dSJustin T. Gibbs /* 11478b8a9b1dSJustin T. Gibbs * Basically, the point of this is that we go through 11488b8a9b1dSJustin T. Gibbs * getting the list of devices, until we find a passthrough 11498b8a9b1dSJustin T. Gibbs * device. In the current version of the CAM code, the 11508b8a9b1dSJustin T. Gibbs * only way to determine what type of device we're dealing 11518b8a9b1dSJustin T. Gibbs * with is by its name. 11528b8a9b1dSJustin T. Gibbs */ 11538b8a9b1dSJustin T. Gibbs while (found == 0) { 11548b8a9b1dSJustin T. Gibbs ccb->cgdl.index = 0; 11558b8a9b1dSJustin T. Gibbs ccb->cgdl.status = CAM_GDEVLIST_MORE_DEVS; 11568b8a9b1dSJustin T. Gibbs while (ccb->cgdl.status == CAM_GDEVLIST_MORE_DEVS) { 11578b8a9b1dSJustin T. Gibbs /* we want the next device in the list */ 11588b8a9b1dSJustin T. Gibbs xpt_action(ccb); 11598b8a9b1dSJustin T. Gibbs if (strncmp(ccb->cgdl.periph_name, 11608b8a9b1dSJustin T. Gibbs "pass", 4) == 0){ 11618b8a9b1dSJustin T. Gibbs found = 1; 11628b8a9b1dSJustin T. Gibbs break; 11638b8a9b1dSJustin T. Gibbs } 11648b8a9b1dSJustin T. Gibbs } 11658b8a9b1dSJustin T. Gibbs if ((ccb->cgdl.status == CAM_GDEVLIST_LAST_DEVICE) && 11668b8a9b1dSJustin T. Gibbs (found == 0)) { 11678b8a9b1dSJustin T. Gibbs ccb->cgdl.periph_name[0] = '\0'; 11688b8a9b1dSJustin T. Gibbs ccb->cgdl.unit_number = 0; 11698b8a9b1dSJustin T. Gibbs break; 11708b8a9b1dSJustin T. Gibbs } 11718b8a9b1dSJustin T. Gibbs } 11728b8a9b1dSJustin T. Gibbs 11738b8a9b1dSJustin T. Gibbs /* copy the result back out */ 11748b8a9b1dSJustin T. Gibbs bcopy(ccb, addr, sizeof(union ccb)); 11758b8a9b1dSJustin T. Gibbs 11768b8a9b1dSJustin T. Gibbs /* and release the ccb */ 11778b8a9b1dSJustin T. Gibbs xpt_release_ccb(ccb); 11788b8a9b1dSJustin T. Gibbs 11798b8a9b1dSJustin T. Gibbs break; 11808b8a9b1dSJustin T. Gibbs default: 11818b8a9b1dSJustin T. Gibbs error = ENOTTY; 11828b8a9b1dSJustin T. Gibbs break; 11838b8a9b1dSJustin T. Gibbs } 11848b8a9b1dSJustin T. Gibbs return(error); 11858b8a9b1dSJustin T. Gibbs } 11868b8a9b1dSJustin T. Gibbs 1187227d67aaSAlexander Motin static void 1188991b5d26SMark Johnston cam_periph_done_panic(struct cam_periph *periph, union ccb *done_ccb) 1189991b5d26SMark Johnston { 1190991b5d26SMark Johnston 1191991b5d26SMark Johnston panic("%s: already done with ccb %p", __func__, done_ccb); 1192991b5d26SMark Johnston } 1193991b5d26SMark Johnston 1194991b5d26SMark Johnston static void 1195227d67aaSAlexander Motin cam_periph_done(struct cam_periph *periph, union ccb *done_ccb) 1196227d67aaSAlexander Motin { 1197227d67aaSAlexander Motin 1198227d67aaSAlexander Motin /* Caller will release the CCB */ 1199991b5d26SMark Johnston xpt_path_assert(done_ccb->ccb_h.path, MA_OWNED); 1200991b5d26SMark Johnston done_ccb->ccb_h.cbfcnp = cam_periph_done_panic; 1201227d67aaSAlexander Motin wakeup(&done_ccb->ccb_h.cbfcnp); 1202227d67aaSAlexander Motin } 1203227d67aaSAlexander Motin 1204991b5d26SMark Johnston static void 1205991b5d26SMark Johnston cam_periph_ccbwait(union ccb *ccb) 1206991b5d26SMark Johnston { 1207991b5d26SMark Johnston 1208991b5d26SMark Johnston if ((ccb->ccb_h.func_code & XPT_FC_QUEUED) != 0) { 1209991b5d26SMark Johnston while (ccb->ccb_h.cbfcnp != cam_periph_done_panic) 1210991b5d26SMark Johnston xpt_path_sleep(ccb->ccb_h.path, &ccb->ccb_h.cbfcnp, 1211991b5d26SMark Johnston PRIBIO, "cbwait", 0); 1212991b5d26SMark Johnston } 1213991b5d26SMark Johnston KASSERT(ccb->ccb_h.pinfo.index == CAM_UNQUEUED_INDEX && 1214991b5d26SMark Johnston (ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_INPROG, 1215991b5d26SMark Johnston ("%s: proceeding with incomplete ccb: ccb=%p, func_code=%#x, " 1216991b5d26SMark Johnston "status=%#x, index=%d", __func__, ccb, ccb->ccb_h.func_code, 1217991b5d26SMark Johnston ccb->ccb_h.status, ccb->ccb_h.pinfo.index)); 1218991b5d26SMark Johnston } 1219991b5d26SMark Johnston 122076314772SScott Long /* 122176314772SScott Long * Dispatch a CCB and wait for it to complete. If the CCB has set a 122276314772SScott Long * callback function (ccb->ccb_h.cbfcnp), it will be overwritten and lost. 122376314772SScott Long */ 12248b8a9b1dSJustin T. Gibbs int 12258b8a9b1dSJustin T. Gibbs cam_periph_runccb(union ccb *ccb, 12268b8a9b1dSJustin T. Gibbs int (*error_routine)(union ccb *ccb, 12278b8a9b1dSJustin T. Gibbs cam_flags camflags, 12287af2f2c8SWarner Losh uint32_t sense_flags), 12297af2f2c8SWarner Losh cam_flags camflags, uint32_t sense_flags, 12308b8a9b1dSJustin T. Gibbs struct devstat *ds) 12318b8a9b1dSJustin T. Gibbs { 1232fd8be18fSKenneth D. Merry struct bintime *starttime; 1233fd8be18fSKenneth D. Merry struct bintime ltime; 12348b8a9b1dSJustin T. Gibbs int error; 12355cf3cd10SWarner Losh bool must_poll; 1236f93a843cSWarner Losh uint32_t timeout = 1; 12378b8a9b1dSJustin T. Gibbs 1238fd8be18fSKenneth D. Merry starttime = NULL; 1239227d67aaSAlexander Motin xpt_path_assert(ccb->ccb_h.path, MA_OWNED); 1240991b5d26SMark Johnston KASSERT((ccb->ccb_h.flags & CAM_UNLOCKED) == 0, 1241991b5d26SMark Johnston ("%s: ccb=%p, func_code=%#x, flags=%#x", __func__, ccb, 1242991b5d26SMark Johnston ccb->ccb_h.func_code, ccb->ccb_h.flags)); 12438b8a9b1dSJustin T. Gibbs 12448b8a9b1dSJustin T. Gibbs /* 12458b8a9b1dSJustin T. Gibbs * If the user has supplied a stats structure, and if we understand 12468b8a9b1dSJustin T. Gibbs * this particular type of ccb, record the transaction start. 12478b8a9b1dSJustin T. Gibbs */ 1248d2f3208dSWarner Losh if (ds != NULL && 1249d2f3208dSWarner Losh (ccb->ccb_h.func_code == XPT_SCSI_IO || 1250d2f3208dSWarner Losh ccb->ccb_h.func_code == XPT_ATA_IO || 1251d2f3208dSWarner Losh ccb->ccb_h.func_code == XPT_NVME_IO)) { 1252fd8be18fSKenneth D. Merry starttime = <ime; 1253fd8be18fSKenneth D. Merry binuptime(starttime); 1254fd8be18fSKenneth D. Merry devstat_start_transaction(ds, starttime); 1255fd8be18fSKenneth D. Merry } 12568b8a9b1dSJustin T. Gibbs 12575cf3cd10SWarner Losh /* 12585cf3cd10SWarner Losh * We must poll the I/O while we're dumping. The scheduler is normally 12595cf3cd10SWarner Losh * stopped for dumping, except when we call doadump from ddb. While the 12605cf3cd10SWarner Losh * scheduler is running in this case, we still need to poll the I/O to 12615cf3cd10SWarner Losh * avoid sleeping waiting for the ccb to complete. 126204e814aeSScott Long * 1263045f8bc8SWarner Losh * A panic triggered dump stops the scheduler, any callback from the 1264045f8bc8SWarner Losh * shutdown_post_sync event will run with the scheduler stopped, but 1265045f8bc8SWarner Losh * before we're officially dumping. To avoid hanging in adashutdown 1266045f8bc8SWarner Losh * initiated commands (or other similar situations), we have to test for 1267b4993704SWarner Losh * either dumping or SCHEDULER_STOPPED() here. 1268045f8bc8SWarner Losh * 1269045f8bc8SWarner Losh * To avoid locking problems, dumping/polling callers must call 127004e814aeSScott Long * without a periph lock held. 12715cf3cd10SWarner Losh */ 1272045f8bc8SWarner Losh must_poll = dumping || SCHEDULER_STOPPED(); 1273227d67aaSAlexander Motin ccb->ccb_h.cbfcnp = cam_periph_done; 12748b8a9b1dSJustin T. Gibbs 1275f93a843cSWarner Losh /* 1276f93a843cSWarner Losh * If we're polling, then we need to ensure that we have ample resources 127776314772SScott Long * in the periph. cam_periph_error can reschedule the ccb by calling 127876314772SScott Long * xpt_action and returning ERESTART, so we have to effect the polling 127976314772SScott Long * in the do loop below. 1280f93a843cSWarner Losh */ 12815cf3cd10SWarner Losh if (must_poll) { 1282447b3557SJohn Baldwin if (cam_sim_pollable(ccb->ccb_h.path->bus->sim)) 1283f93a843cSWarner Losh timeout = xpt_poll_setup(ccb); 1284447b3557SJohn Baldwin else 1285447b3557SJohn Baldwin timeout = 0; 1286f93a843cSWarner Losh } 1287f93a843cSWarner Losh 1288f93a843cSWarner Losh if (timeout == 0) { 1289f93a843cSWarner Losh ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 1290f93a843cSWarner Losh error = EBUSY; 1291f93a843cSWarner Losh } else { 1292f93a843cSWarner Losh xpt_action(ccb); 12938b8a9b1dSJustin T. Gibbs do { 12945cf3cd10SWarner Losh if (must_poll) { 1295f93a843cSWarner Losh xpt_pollwait(ccb, timeout); 1296f93a843cSWarner Losh timeout = ccb->ccb_h.timeout * 10; 12975cf3cd10SWarner Losh } else { 12985cf3cd10SWarner Losh cam_periph_ccbwait(ccb); 1299f93a843cSWarner Losh } 13008b8a9b1dSJustin T. Gibbs if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) 13018b8a9b1dSJustin T. Gibbs error = 0; 1302991b5d26SMark Johnston else if (error_routine != NULL) { 1303ff4633d9SWarner Losh /* 1304ff4633d9SWarner Losh * cbfcnp is modified by cam_periph_ccbwait so 1305ff4633d9SWarner Losh * reset it before we call the error routine 1306ff4633d9SWarner Losh * which may call xpt_done. 1307ff4633d9SWarner Losh */ 1308991b5d26SMark Johnston ccb->ccb_h.cbfcnp = cam_periph_done; 13098b8a9b1dSJustin T. Gibbs error = (*error_routine)(ccb, camflags, sense_flags); 1310991b5d26SMark Johnston } else 13118b8a9b1dSJustin T. Gibbs error = 0; 13128b8a9b1dSJustin T. Gibbs } while (error == ERESTART); 1313f93a843cSWarner Losh } 1314f93a843cSWarner Losh 131583c5d981SAlexander Motin if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { 13168b8a9b1dSJustin T. Gibbs cam_release_devq(ccb->ccb_h.path, 13178b8a9b1dSJustin T. Gibbs /* relsim_flags */0, 13188b8a9b1dSJustin T. Gibbs /* openings */0, 13198b8a9b1dSJustin T. Gibbs /* timeout */0, 13208b8a9b1dSJustin T. Gibbs /* getcount_only */ FALSE); 132183c5d981SAlexander Motin ccb->ccb_h.status &= ~CAM_DEV_QFRZN; 132283c5d981SAlexander Motin } 13238b8a9b1dSJustin T. Gibbs 1324379ad358SAlexander Motin if (ds != NULL) { 1325d2f3208dSWarner Losh uint32_t bytes; 1326d2f3208dSWarner Losh devstat_tag_type tag; 1327d2f3208dSWarner Losh bool valid = true; 1328d2f3208dSWarner Losh 1329379ad358SAlexander Motin if (ccb->ccb_h.func_code == XPT_SCSI_IO) { 1330d2f3208dSWarner Losh bytes = ccb->csio.dxfer_len - ccb->csio.resid; 1331d2f3208dSWarner Losh tag = (devstat_tag_type)(ccb->csio.tag_action & 0x3); 1332379ad358SAlexander Motin } else if (ccb->ccb_h.func_code == XPT_ATA_IO) { 1333d2f3208dSWarner Losh bytes = ccb->ataio.dxfer_len - ccb->ataio.resid; 1334d2f3208dSWarner Losh tag = (devstat_tag_type)0; 1335d2f3208dSWarner Losh } else if (ccb->ccb_h.func_code == XPT_NVME_IO) { 1336d2f3208dSWarner Losh bytes = ccb->nvmeio.dxfer_len; /* NB: resid no possible */ 1337d2f3208dSWarner Losh tag = (devstat_tag_type)0; 1338d2f3208dSWarner Losh } else { 1339d2f3208dSWarner Losh valid = false; 1340379ad358SAlexander Motin } 1341d2f3208dSWarner Losh if (valid) 1342d2f3208dSWarner Losh devstat_end_transaction(ds, bytes, tag, 1343d2f3208dSWarner Losh ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_NONE) ? 1344d2f3208dSWarner Losh DEVSTAT_NO_DATA : (ccb->ccb_h.flags & CAM_DIR_OUT) ? 1345d2f3208dSWarner Losh DEVSTAT_WRITE : DEVSTAT_READ, NULL, starttime); 1346379ad358SAlexander Motin } 13478b8a9b1dSJustin T. Gibbs 13488b8a9b1dSJustin T. Gibbs return(error); 13498b8a9b1dSJustin T. Gibbs } 13508b8a9b1dSJustin T. Gibbs 135187cfaf0eSJustin T. Gibbs void 135287cfaf0eSJustin T. Gibbs cam_freeze_devq(struct cam_path *path) 135387cfaf0eSJustin T. Gibbs { 1354cccf4220SAlexander Motin struct ccb_hdr ccb_h; 135587cfaf0eSJustin T. Gibbs 13560d4f3c31SAlexander Motin CAM_DEBUG(path, CAM_DEBUG_TRACE, ("cam_freeze_devq\n")); 1357076686feSEdward Tomasz Napierala memset(&ccb_h, 0, sizeof(ccb_h)); 1358cccf4220SAlexander Motin xpt_setup_ccb(&ccb_h, path, /*priority*/1); 1359cccf4220SAlexander Motin ccb_h.func_code = XPT_NOOP; 1360cccf4220SAlexander Motin ccb_h.flags = CAM_DEV_QFREEZE; 1361cccf4220SAlexander Motin xpt_action((union ccb *)&ccb_h); 136287cfaf0eSJustin T. Gibbs } 136387cfaf0eSJustin T. Gibbs 13647af2f2c8SWarner Losh uint32_t 13657af2f2c8SWarner Losh cam_release_devq(struct cam_path *path, uint32_t relsim_flags, 13667af2f2c8SWarner Losh uint32_t openings, uint32_t arg, 13678b8a9b1dSJustin T. Gibbs int getcount_only) 13688b8a9b1dSJustin T. Gibbs { 13698b8a9b1dSJustin T. Gibbs struct ccb_relsim crs; 13708b8a9b1dSJustin T. Gibbs 13710d4f3c31SAlexander Motin CAM_DEBUG(path, CAM_DEBUG_TRACE, ("cam_release_devq(%u, %u, %u, %d)\n", 13720d4f3c31SAlexander Motin relsim_flags, openings, arg, getcount_only)); 1373076686feSEdward Tomasz Napierala memset(&crs, 0, sizeof(crs)); 1374bbfa4aa1SAlexander Motin xpt_setup_ccb(&crs.ccb_h, path, CAM_PRIORITY_NORMAL); 13758b8a9b1dSJustin T. Gibbs crs.ccb_h.func_code = XPT_REL_SIMQ; 13768b8a9b1dSJustin T. Gibbs crs.ccb_h.flags = getcount_only ? CAM_DEV_QFREEZE : 0; 13778b8a9b1dSJustin T. Gibbs crs.release_flags = relsim_flags; 13788b8a9b1dSJustin T. Gibbs crs.openings = openings; 137983c5d981SAlexander Motin crs.release_timeout = arg; 13808b8a9b1dSJustin T. Gibbs xpt_action((union ccb *)&crs); 13818b8a9b1dSJustin T. Gibbs return (crs.qfrozen_cnt); 13828b8a9b1dSJustin T. Gibbs } 13838b8a9b1dSJustin T. Gibbs 13848b8a9b1dSJustin T. Gibbs #define saved_ccb_ptr ppriv_ptr0 138583c5d981SAlexander Motin static void 138683c5d981SAlexander Motin camperiphdone(struct cam_periph *periph, union ccb *done_ccb) 138783c5d981SAlexander Motin { 13880191d9b3SAlexander Motin union ccb *saved_ccb; 138983c5d981SAlexander Motin cam_status status; 139083c5d981SAlexander Motin struct scsi_start_stop_unit *scsi_cmd; 139179fab7d4SAlexander Motin int error = 0, error_code, sense_key, asc, ascq; 13927af2f2c8SWarner Losh uint16_t done_flags; 139383c5d981SAlexander Motin 13940191d9b3SAlexander Motin scsi_cmd = (struct scsi_start_stop_unit *) 13950191d9b3SAlexander Motin &done_ccb->csio.cdb_io.cdb_bytes; 139683c5d981SAlexander Motin status = done_ccb->ccb_h.status; 13978b8a9b1dSJustin T. Gibbs 13980191d9b3SAlexander Motin if ((status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 1399e7493b28SAlexander Motin if (scsi_extract_sense_ccb(done_ccb, 1400e7493b28SAlexander Motin &error_code, &sense_key, &asc, &ascq)) { 140165afe1f4SKenneth D. Merry /* 14028b8a9b1dSJustin T. Gibbs * If the error is "invalid field in CDB", 14038b8a9b1dSJustin T. Gibbs * and the load/eject flag is set, turn the 14048b8a9b1dSJustin T. Gibbs * flag off and try again. This is just in 14058b8a9b1dSJustin T. Gibbs * case the drive in question barfs on the 14068b8a9b1dSJustin T. Gibbs * load eject flag. The CAM code should set 14078b8a9b1dSJustin T. Gibbs * the load/eject flag by default for 14088b8a9b1dSJustin T. Gibbs * removable media. 14098b8a9b1dSJustin T. Gibbs */ 14108b8a9b1dSJustin T. Gibbs if ((scsi_cmd->opcode == START_STOP_UNIT) && 14118b8a9b1dSJustin T. Gibbs ((scsi_cmd->how & SSS_LOEJ) != 0) && 14120191d9b3SAlexander Motin (asc == 0x24) && (ascq == 0x00)) { 14138b8a9b1dSJustin T. Gibbs scsi_cmd->how &= ~SSS_LOEJ; 14140191d9b3SAlexander Motin if (status & CAM_DEV_QFRZN) { 14150191d9b3SAlexander Motin cam_release_devq(done_ccb->ccb_h.path, 14160191d9b3SAlexander Motin 0, 0, 0, 0); 14170191d9b3SAlexander Motin done_ccb->ccb_h.status &= 14180191d9b3SAlexander Motin ~CAM_DEV_QFRZN; 14190191d9b3SAlexander Motin } 14208b8a9b1dSJustin T. Gibbs xpt_action(done_ccb); 14210191d9b3SAlexander Motin goto out; 14220191d9b3SAlexander Motin } 14230191d9b3SAlexander Motin } 142479fab7d4SAlexander Motin error = cam_periph_error(done_ccb, 0, 142579fab7d4SAlexander Motin SF_RETRY_UA | SF_NO_PRINT); 142679fab7d4SAlexander Motin if (error == ERESTART) 14270191d9b3SAlexander Motin goto out; 14280191d9b3SAlexander Motin if (done_ccb->ccb_h.status & CAM_DEV_QFRZN) { 14290191d9b3SAlexander Motin cam_release_devq(done_ccb->ccb_h.path, 0, 0, 0, 0); 14300191d9b3SAlexander Motin done_ccb->ccb_h.status &= ~CAM_DEV_QFRZN; 14310191d9b3SAlexander Motin } 14320191d9b3SAlexander Motin } else { 14330191d9b3SAlexander Motin /* 14340191d9b3SAlexander Motin * If we have successfully taken a device from the not 14350191d9b3SAlexander Motin * ready to ready state, re-scan the device and re-get 14360191d9b3SAlexander Motin * the inquiry information. Many devices (mostly disks) 14370191d9b3SAlexander Motin * don't properly report their inquiry information unless 14380191d9b3SAlexander Motin * they are spun up. 14390191d9b3SAlexander Motin */ 14400191d9b3SAlexander Motin if (scsi_cmd->opcode == START_STOP_UNIT) 14410191d9b3SAlexander Motin xpt_async(AC_INQ_CHANGED, done_ccb->ccb_h.path, NULL); 14420191d9b3SAlexander Motin } 144365afe1f4SKenneth D. Merry 1444bae3729bSAlexander Motin /* If we tried long wait and still failed, remember that. */ 1445bae3729bSAlexander Motin if ((periph->flags & CAM_PERIPH_RECOVERY_WAIT) && 1446bae3729bSAlexander Motin (done_ccb->csio.cdb_io.cdb_bytes[0] == TEST_UNIT_READY)) { 1447bae3729bSAlexander Motin periph->flags &= ~CAM_PERIPH_RECOVERY_WAIT; 1448bae3729bSAlexander Motin if (error != 0 && done_ccb->ccb_h.retry_count == 0) 1449bae3729bSAlexander Motin periph->flags |= CAM_PERIPH_RECOVERY_WAIT_FAILED; 1450bae3729bSAlexander Motin } 1451bae3729bSAlexander Motin 14528b8a9b1dSJustin T. Gibbs /* 145379fab7d4SAlexander Motin * After recovery action(s) completed, return to the original CCB. 145479fab7d4SAlexander Motin * If the recovery CCB has failed, considering its own possible 145579fab7d4SAlexander Motin * retries and recovery, assume we are back in state where we have 145679fab7d4SAlexander Motin * been originally, but without recovery hopes left. In such case, 145779fab7d4SAlexander Motin * after the final attempt below, we cancel any further retries, 145879fab7d4SAlexander Motin * blocking by that also any new recovery attempts for this CCB, 145979fab7d4SAlexander Motin * and the result will be the final one returned to the CCB owher. 14608b8a9b1dSJustin T. Gibbs */ 14610191d9b3SAlexander Motin saved_ccb = (union ccb *)done_ccb->ccb_h.saved_ccb_ptr; 146213aa56fcSEdward Tomasz Napierala KASSERT(saved_ccb->ccb_h.func_code == XPT_SCSI_IO, 146313aa56fcSEdward Tomasz Napierala ("%s: saved_ccb func_code %#x != XPT_SCSI_IO", 146413aa56fcSEdward Tomasz Napierala __func__, saved_ccb->ccb_h.func_code)); 146513aa56fcSEdward Tomasz Napierala KASSERT(done_ccb->ccb_h.func_code == XPT_SCSI_IO, 146613aa56fcSEdward Tomasz Napierala ("%s: done_ccb func_code %#x != XPT_SCSI_IO", 146713aa56fcSEdward Tomasz Napierala __func__, done_ccb->ccb_h.func_code)); 1468404f0011SAlexander Motin saved_ccb->ccb_h.periph_links = done_ccb->ccb_h.periph_links; 146913aa56fcSEdward Tomasz Napierala done_flags = done_ccb->ccb_h.alloc_flags; 147013aa56fcSEdward Tomasz Napierala bcopy(saved_ccb, done_ccb, sizeof(struct ccb_scsiio)); 147113aa56fcSEdward Tomasz Napierala done_ccb->ccb_h.alloc_flags = done_flags; 147283c5d981SAlexander Motin xpt_free_ccb(saved_ccb); 14730191d9b3SAlexander Motin if (done_ccb->ccb_h.cbfcnp != camperiphdone) 147460a899a0SKenneth D. Merry periph->flags &= ~CAM_PERIPH_RECOVERY_INPROG; 147579fab7d4SAlexander Motin if (error != 0) 147679fab7d4SAlexander Motin done_ccb->ccb_h.retry_count = 0; 14778b8a9b1dSJustin T. Gibbs xpt_action(done_ccb); 14788b8a9b1dSJustin T. Gibbs 14790191d9b3SAlexander Motin out: 14800191d9b3SAlexander Motin /* Drop freeze taken due to CAM_DEV_QFREEZE flag set. */ 14810191d9b3SAlexander Motin cam_release_devq(done_ccb->ccb_h.path, 0, 0, 0, 0); 1482d84c90a6SAlexander Motin } 14838b8a9b1dSJustin T. Gibbs 14848b8a9b1dSJustin T. Gibbs /* 148587cfaf0eSJustin T. Gibbs * Generic Async Event handler. Peripheral drivers usually 148687cfaf0eSJustin T. Gibbs * filter out the events that require personal attention, 148787cfaf0eSJustin T. Gibbs * and leave the rest to this function. 148887cfaf0eSJustin T. Gibbs */ 148987cfaf0eSJustin T. Gibbs void 14907af2f2c8SWarner Losh cam_periph_async(struct cam_periph *periph, uint32_t code, 149187cfaf0eSJustin T. Gibbs struct cam_path *path, void *arg) 149287cfaf0eSJustin T. Gibbs { 149387cfaf0eSJustin T. Gibbs switch (code) { 149487cfaf0eSJustin T. Gibbs case AC_LOST_DEVICE: 149587cfaf0eSJustin T. Gibbs cam_periph_invalidate(periph); 149687cfaf0eSJustin T. Gibbs break; 149787cfaf0eSJustin T. Gibbs default: 149887cfaf0eSJustin T. Gibbs break; 149987cfaf0eSJustin T. Gibbs } 150087cfaf0eSJustin T. Gibbs } 150187cfaf0eSJustin T. Gibbs 150287cfaf0eSJustin T. Gibbs void 150387cfaf0eSJustin T. Gibbs cam_periph_bus_settle(struct cam_periph *periph, u_int bus_settle) 150487cfaf0eSJustin T. Gibbs { 150587cfaf0eSJustin T. Gibbs struct ccb_getdevstats cgds; 150687cfaf0eSJustin T. Gibbs 1507076686feSEdward Tomasz Napierala memset(&cgds, 0, sizeof(cgds)); 1508bbfa4aa1SAlexander Motin xpt_setup_ccb(&cgds.ccb_h, periph->path, CAM_PRIORITY_NORMAL); 150987cfaf0eSJustin T. Gibbs cgds.ccb_h.func_code = XPT_GDEV_STATS; 151087cfaf0eSJustin T. Gibbs xpt_action((union ccb *)&cgds); 151187cfaf0eSJustin T. Gibbs cam_periph_freeze_after_event(periph, &cgds.last_reset, bus_settle); 151287cfaf0eSJustin T. Gibbs } 151387cfaf0eSJustin T. Gibbs 151487cfaf0eSJustin T. Gibbs void 151587cfaf0eSJustin T. Gibbs cam_periph_freeze_after_event(struct cam_periph *periph, 151687cfaf0eSJustin T. Gibbs struct timeval* event_time, u_int duration_ms) 151787cfaf0eSJustin T. Gibbs { 151887cfaf0eSJustin T. Gibbs struct timeval delta; 151987cfaf0eSJustin T. Gibbs struct timeval duration_tv; 152087cfaf0eSJustin T. Gibbs 1521f8ff57d2SAlexander Motin if (!timevalisset(event_time)) 1522f8ff57d2SAlexander Motin return; 1523f8ff57d2SAlexander Motin 152487cfaf0eSJustin T. Gibbs microtime(&delta); 152587cfaf0eSJustin T. Gibbs timevalsub(&delta, event_time); 152687cfaf0eSJustin T. Gibbs duration_tv.tv_sec = duration_ms / 1000; 152787cfaf0eSJustin T. Gibbs duration_tv.tv_usec = (duration_ms % 1000) * 1000; 152887cfaf0eSJustin T. Gibbs if (timevalcmp(&delta, &duration_tv, <)) { 152987cfaf0eSJustin T. Gibbs timevalsub(&duration_tv, &delta); 153087cfaf0eSJustin T. Gibbs 153187cfaf0eSJustin T. Gibbs duration_ms = duration_tv.tv_sec * 1000; 153287cfaf0eSJustin T. Gibbs duration_ms += duration_tv.tv_usec / 1000; 153387cfaf0eSJustin T. Gibbs cam_freeze_devq(periph->path); 153487cfaf0eSJustin T. Gibbs cam_release_devq(periph->path, 153587cfaf0eSJustin T. Gibbs RELSIM_RELEASE_AFTER_TIMEOUT, 153687cfaf0eSJustin T. Gibbs /*reduction*/0, 153787cfaf0eSJustin T. Gibbs /*timeout*/duration_ms, 153887cfaf0eSJustin T. Gibbs /*getcount_only*/0); 153987cfaf0eSJustin T. Gibbs } 154087cfaf0eSJustin T. Gibbs 154187cfaf0eSJustin T. Gibbs } 154287cfaf0eSJustin T. Gibbs 15433393f8daSKenneth D. Merry static int 15440191d9b3SAlexander Motin camperiphscsistatuserror(union ccb *ccb, union ccb **orig_ccb, 15457af2f2c8SWarner Losh cam_flags camflags, uint32_t sense_flags, 15467af2f2c8SWarner Losh int *openings, uint32_t *relsim_flags, 15477af2f2c8SWarner Losh uint32_t *timeout, uint32_t *action, const char **action_string) 15488b8a9b1dSJustin T. Gibbs { 154999bad9caSAlexander Motin struct cam_periph *periph; 15508b8a9b1dSJustin T. Gibbs int error; 15518b8a9b1dSJustin T. Gibbs 15528b8a9b1dSJustin T. Gibbs switch (ccb->csio.scsi_status) { 15538b8a9b1dSJustin T. Gibbs case SCSI_STATUS_OK: 15548b8a9b1dSJustin T. Gibbs case SCSI_STATUS_COND_MET: 15558b8a9b1dSJustin T. Gibbs case SCSI_STATUS_INTERMED: 15568b8a9b1dSJustin T. Gibbs case SCSI_STATUS_INTERMED_COND_MET: 15578b8a9b1dSJustin T. Gibbs error = 0; 15588b8a9b1dSJustin T. Gibbs break; 15598b8a9b1dSJustin T. Gibbs case SCSI_STATUS_CMD_TERMINATED: 15608b8a9b1dSJustin T. Gibbs case SCSI_STATUS_CHECK_COND: 15610191d9b3SAlexander Motin error = camperiphscsisenseerror(ccb, orig_ccb, 15623393f8daSKenneth D. Merry camflags, 15638b8a9b1dSJustin T. Gibbs sense_flags, 15643393f8daSKenneth D. Merry openings, 15653393f8daSKenneth D. Merry relsim_flags, 156683c5d981SAlexander Motin timeout, 15670181d54bSAlexander Motin action, 156883c5d981SAlexander Motin action_string); 15698b8a9b1dSJustin T. Gibbs break; 15708b8a9b1dSJustin T. Gibbs case SCSI_STATUS_QUEUE_FULL: 15718b8a9b1dSJustin T. Gibbs { 15728b8a9b1dSJustin T. Gibbs /* no decrement */ 157382815562SJustin T. Gibbs struct ccb_getdevstats cgds; 15748b8a9b1dSJustin T. Gibbs 15758b8a9b1dSJustin T. Gibbs /* 15768b8a9b1dSJustin T. Gibbs * First off, find out what the current 15778b8a9b1dSJustin T. Gibbs * transaction counts are. 15788b8a9b1dSJustin T. Gibbs */ 1579076686feSEdward Tomasz Napierala memset(&cgds, 0, sizeof(cgds)); 158082815562SJustin T. Gibbs xpt_setup_ccb(&cgds.ccb_h, 15818b8a9b1dSJustin T. Gibbs ccb->ccb_h.path, 1582bbfa4aa1SAlexander Motin CAM_PRIORITY_NORMAL); 158382815562SJustin T. Gibbs cgds.ccb_h.func_code = XPT_GDEV_STATS; 158482815562SJustin T. Gibbs xpt_action((union ccb *)&cgds); 15858b8a9b1dSJustin T. Gibbs 15868b8a9b1dSJustin T. Gibbs /* 15878b8a9b1dSJustin T. Gibbs * If we were the only transaction active, treat 15888b8a9b1dSJustin T. Gibbs * the QUEUE FULL as if it were a BUSY condition. 15898b8a9b1dSJustin T. Gibbs */ 159082815562SJustin T. Gibbs if (cgds.dev_active != 0) { 159182815562SJustin T. Gibbs int total_openings; 159282815562SJustin T. Gibbs 15938b8a9b1dSJustin T. Gibbs /* 15948b8a9b1dSJustin T. Gibbs * Reduce the number of openings to 15958b8a9b1dSJustin T. Gibbs * be 1 less than the amount it took 15968b8a9b1dSJustin T. Gibbs * to get a queue full bounded by the 15978b8a9b1dSJustin T. Gibbs * minimum allowed tag count for this 15988b8a9b1dSJustin T. Gibbs * device. 15998b8a9b1dSJustin T. Gibbs */ 16003393f8daSKenneth D. Merry total_openings = cgds.dev_active + cgds.dev_openings; 16013393f8daSKenneth D. Merry *openings = cgds.dev_active; 16023393f8daSKenneth D. Merry if (*openings < cgds.mintags) 16033393f8daSKenneth D. Merry *openings = cgds.mintags; 16043393f8daSKenneth D. Merry if (*openings < total_openings) 16053393f8daSKenneth D. Merry *relsim_flags = RELSIM_ADJUST_OPENINGS; 16068b8a9b1dSJustin T. Gibbs else { 16078b8a9b1dSJustin T. Gibbs /* 16088b8a9b1dSJustin T. Gibbs * Some devices report queue full for 16098b8a9b1dSJustin T. Gibbs * temporary resource shortages. For 16108b8a9b1dSJustin T. Gibbs * this reason, we allow a minimum 16118b8a9b1dSJustin T. Gibbs * tag count to be entered via a 16128b8a9b1dSJustin T. Gibbs * quirk entry to prevent the queue 16138b8a9b1dSJustin T. Gibbs * count on these devices from falling 16148b8a9b1dSJustin T. Gibbs * to a pessimisticly low value. We 16158b8a9b1dSJustin T. Gibbs * still wait for the next successful 16168b8a9b1dSJustin T. Gibbs * completion, however, before queueing 16178b8a9b1dSJustin T. Gibbs * more transactions to the device. 16188b8a9b1dSJustin T. Gibbs */ 16193393f8daSKenneth D. Merry *relsim_flags = RELSIM_RELEASE_AFTER_CMDCMPLT; 16208b8a9b1dSJustin T. Gibbs } 16213393f8daSKenneth D. Merry *timeout = 0; 16228b8a9b1dSJustin T. Gibbs error = ERESTART; 16230181d54bSAlexander Motin *action &= ~SSQ_PRINT_SENSE; 16248b8a9b1dSJustin T. Gibbs break; 16258b8a9b1dSJustin T. Gibbs } 16268b8a9b1dSJustin T. Gibbs /* FALLTHROUGH */ 16278b8a9b1dSJustin T. Gibbs } 16288b8a9b1dSJustin T. Gibbs case SCSI_STATUS_BUSY: 16298b8a9b1dSJustin T. Gibbs /* 16308b8a9b1dSJustin T. Gibbs * Restart the queue after either another 16318b8a9b1dSJustin T. Gibbs * command completes or a 1 second timeout. 16328b8a9b1dSJustin T. Gibbs */ 163399bad9caSAlexander Motin periph = xpt_path_periph(ccb->ccb_h.path); 163499bad9caSAlexander Motin if (periph->flags & CAM_PERIPH_INVALID) { 16359fb40bafSWarner Losh error = ENXIO; 163699bad9caSAlexander Motin *action_string = "Periph was invalidated"; 163799bad9caSAlexander Motin } else if ((sense_flags & SF_RETRY_BUSY) != 0 || 163899bad9caSAlexander Motin ccb->ccb_h.retry_count > 0) { 163999bad9caSAlexander Motin if ((sense_flags & SF_RETRY_BUSY) == 0) 164099bad9caSAlexander Motin ccb->ccb_h.retry_count--; 16418b8a9b1dSJustin T. Gibbs error = ERESTART; 16423393f8daSKenneth D. Merry *relsim_flags = RELSIM_RELEASE_AFTER_TIMEOUT 16438b8a9b1dSJustin T. Gibbs | RELSIM_RELEASE_AFTER_CMDCMPLT; 16443393f8daSKenneth D. Merry *timeout = 1000; 1645af51b059SMatt Jacob } else { 1646af51b059SMatt Jacob error = EIO; 164799bad9caSAlexander Motin *action_string = "Retries exhausted"; 1648af51b059SMatt Jacob } 16498b8a9b1dSJustin T. Gibbs break; 16508b8a9b1dSJustin T. Gibbs case SCSI_STATUS_RESERV_CONFLICT: 16518b8a9b1dSJustin T. Gibbs default: 16528b8a9b1dSJustin T. Gibbs error = EIO; 16538b8a9b1dSJustin T. Gibbs break; 16548b8a9b1dSJustin T. Gibbs } 16553393f8daSKenneth D. Merry return (error); 16563393f8daSKenneth D. Merry } 16573393f8daSKenneth D. Merry 16583393f8daSKenneth D. Merry static int 16590191d9b3SAlexander Motin camperiphscsisenseerror(union ccb *ccb, union ccb **orig, 16607af2f2c8SWarner Losh cam_flags camflags, uint32_t sense_flags, 16617af2f2c8SWarner Losh int *openings, uint32_t *relsim_flags, 16627af2f2c8SWarner Losh uint32_t *timeout, uint32_t *action, const char **action_string) 16633393f8daSKenneth D. Merry { 16643393f8daSKenneth D. Merry struct cam_periph *periph; 166583c5d981SAlexander Motin union ccb *orig_ccb = ccb; 16660191d9b3SAlexander Motin int error, recoveryccb; 16677af2f2c8SWarner Losh uint16_t flags; 16683393f8daSKenneth D. Merry 16698532d381SConrad Meyer #if defined(BUF_TRACKING) || defined(FULL_BUF_TRACKING) 16708532d381SConrad Meyer if (ccb->ccb_h.func_code == XPT_SCSI_IO && ccb->csio.bio != NULL) 16718532d381SConrad Meyer biotrack(ccb->csio.bio, __func__); 16728532d381SConrad Meyer #endif 16738532d381SConrad Meyer 16743393f8daSKenneth D. Merry periph = xpt_path_periph(ccb->ccb_h.path); 16750191d9b3SAlexander Motin recoveryccb = (ccb->ccb_h.cbfcnp == camperiphdone); 16760191d9b3SAlexander Motin if ((periph->flags & CAM_PERIPH_RECOVERY_INPROG) && !recoveryccb) { 16773393f8daSKenneth D. Merry /* 16783393f8daSKenneth D. Merry * If error recovery is already in progress, don't attempt 16793393f8daSKenneth D. Merry * to process this error, but requeue it unconditionally 16803393f8daSKenneth D. Merry * and attempt to process it once error recovery has 16813393f8daSKenneth D. Merry * completed. This failed command is probably related to 16823393f8daSKenneth D. Merry * the error that caused the currently active error recovery 16833393f8daSKenneth D. Merry * action so our current recovery efforts should also 16843393f8daSKenneth D. Merry * address this command. Be aware that the error recovery 16853393f8daSKenneth D. Merry * code assumes that only one recovery action is in progress 16863393f8daSKenneth D. Merry * on a particular peripheral instance at any given time 16873393f8daSKenneth D. Merry * (e.g. only one saved CCB for error recovery) so it is 16883393f8daSKenneth D. Merry * imperitive that we don't violate this assumption. 16893393f8daSKenneth D. Merry */ 16903393f8daSKenneth D. Merry error = ERESTART; 16910181d54bSAlexander Motin *action &= ~SSQ_PRINT_SENSE; 16923393f8daSKenneth D. Merry } else { 16933393f8daSKenneth D. Merry scsi_sense_action err_action; 16943393f8daSKenneth D. Merry struct ccb_getdev cgd; 16953393f8daSKenneth D. Merry 16963393f8daSKenneth D. Merry /* 16973393f8daSKenneth D. Merry * Grab the inquiry data for this device. 16983393f8daSKenneth D. Merry */ 1699076686feSEdward Tomasz Napierala memset(&cgd, 0, sizeof(cgd)); 1700bbfa4aa1SAlexander Motin xpt_setup_ccb(&cgd.ccb_h, ccb->ccb_h.path, CAM_PRIORITY_NORMAL); 17013393f8daSKenneth D. Merry cgd.ccb_h.func_code = XPT_GDEV_TYPE; 17023393f8daSKenneth D. Merry xpt_action((union ccb *)&cgd); 17033393f8daSKenneth D. Merry 1704e7493b28SAlexander Motin err_action = scsi_error_action(&ccb->csio, &cgd.inq_data, 17053393f8daSKenneth D. Merry sense_flags); 17063393f8daSKenneth D. Merry error = err_action & SS_ERRMASK; 17073393f8daSKenneth D. Merry 17083393f8daSKenneth D. Merry /* 17090191d9b3SAlexander Motin * Do not autostart sequential access devices 17100191d9b3SAlexander Motin * to avoid unexpected tape loading. 17110191d9b3SAlexander Motin */ 17120191d9b3SAlexander Motin if ((err_action & SS_MASK) == SS_START && 17130191d9b3SAlexander Motin SID_TYPE(&cgd.inq_data) == T_SEQUENTIAL) { 17140191d9b3SAlexander Motin *action_string = "Will not autostart a " 17150191d9b3SAlexander Motin "sequential access device"; 17160191d9b3SAlexander Motin goto sense_error_done; 17170191d9b3SAlexander Motin } 17180191d9b3SAlexander Motin 17190191d9b3SAlexander Motin /* 17200191d9b3SAlexander Motin * Avoid recovery recursion if recovery action is the same. 17210191d9b3SAlexander Motin */ 17220191d9b3SAlexander Motin if ((err_action & SS_MASK) >= SS_START && recoveryccb) { 17230191d9b3SAlexander Motin if (((err_action & SS_MASK) == SS_START && 17240191d9b3SAlexander Motin ccb->csio.cdb_io.cdb_bytes[0] == START_STOP_UNIT) || 17250191d9b3SAlexander Motin ((err_action & SS_MASK) == SS_TUR && 17260191d9b3SAlexander Motin (ccb->csio.cdb_io.cdb_bytes[0] == TEST_UNIT_READY))) { 17270191d9b3SAlexander Motin err_action = SS_RETRY|SSQ_DECREMENT_COUNT|EIO; 17280191d9b3SAlexander Motin *relsim_flags = RELSIM_RELEASE_AFTER_TIMEOUT; 17290191d9b3SAlexander Motin *timeout = 500; 17300191d9b3SAlexander Motin } 17310191d9b3SAlexander Motin } 17320191d9b3SAlexander Motin 17330191d9b3SAlexander Motin /* 17343393f8daSKenneth D. Merry * If the recovery action will consume a retry, 17353393f8daSKenneth D. Merry * make sure we actually have retries available. 17363393f8daSKenneth D. Merry */ 17373393f8daSKenneth D. Merry if ((err_action & SSQ_DECREMENT_COUNT) != 0) { 1738a07e846bSAlexander Motin if (ccb->ccb_h.retry_count > 0 && 1739a07e846bSAlexander Motin (periph->flags & CAM_PERIPH_INVALID) == 0) 17403393f8daSKenneth D. Merry ccb->ccb_h.retry_count--; 17413393f8daSKenneth D. Merry else { 174283c5d981SAlexander Motin *action_string = "Retries exhausted"; 17433393f8daSKenneth D. Merry goto sense_error_done; 17443393f8daSKenneth D. Merry } 17453393f8daSKenneth D. Merry } 17463393f8daSKenneth D. Merry 17473393f8daSKenneth D. Merry if ((err_action & SS_MASK) >= SS_START) { 17483393f8daSKenneth D. Merry /* 17493393f8daSKenneth D. Merry * Do common portions of commands that 17503393f8daSKenneth D. Merry * use recovery CCBs. 17513393f8daSKenneth D. Merry */ 175283c5d981SAlexander Motin orig_ccb = xpt_alloc_ccb_nowait(); 175383c5d981SAlexander Motin if (orig_ccb == NULL) { 175483c5d981SAlexander Motin *action_string = "Can't allocate recovery CCB"; 17553393f8daSKenneth D. Merry goto sense_error_done; 17563393f8daSKenneth D. Merry } 17571f1158b2SAlexander Motin /* 17581f1158b2SAlexander Motin * Clear freeze flag for original request here, as 17591f1158b2SAlexander Motin * this freeze will be dropped as part of ERESTART. 17601f1158b2SAlexander Motin */ 17611f1158b2SAlexander Motin ccb->ccb_h.status &= ~CAM_DEV_QFRZN; 176213aa56fcSEdward Tomasz Napierala 176313aa56fcSEdward Tomasz Napierala KASSERT(ccb->ccb_h.func_code == XPT_SCSI_IO, 176413aa56fcSEdward Tomasz Napierala ("%s: ccb func_code %#x != XPT_SCSI_IO", 176513aa56fcSEdward Tomasz Napierala __func__, ccb->ccb_h.func_code)); 176613aa56fcSEdward Tomasz Napierala flags = orig_ccb->ccb_h.alloc_flags; 176713aa56fcSEdward Tomasz Napierala bcopy(ccb, orig_ccb, sizeof(struct ccb_scsiio)); 176813aa56fcSEdward Tomasz Napierala orig_ccb->ccb_h.alloc_flags = flags; 17693393f8daSKenneth D. Merry } 17703393f8daSKenneth D. Merry 17713393f8daSKenneth D. Merry switch (err_action & SS_MASK) { 17723393f8daSKenneth D. Merry case SS_NOP: 177383c5d981SAlexander Motin *action_string = "No recovery action needed"; 177400e54d14SKenneth D. Merry error = 0; 177500e54d14SKenneth D. Merry break; 17763393f8daSKenneth D. Merry case SS_RETRY: 177783c5d981SAlexander Motin *action_string = "Retrying command (per sense data)"; 17783393f8daSKenneth D. Merry error = ERESTART; 17798b8a9b1dSJustin T. Gibbs break; 17803393f8daSKenneth D. Merry case SS_FAIL: 178183c5d981SAlexander Motin *action_string = "Unretryable error"; 17823393f8daSKenneth D. Merry break; 17833393f8daSKenneth D. Merry case SS_START: 17843393f8daSKenneth D. Merry { 17853393f8daSKenneth D. Merry int le; 17863393f8daSKenneth D. Merry 17873393f8daSKenneth D. Merry /* 17883393f8daSKenneth D. Merry * Send a start unit command to the device, and 17893393f8daSKenneth D. Merry * then retry the command. 17903393f8daSKenneth D. Merry */ 179183c5d981SAlexander Motin *action_string = "Attempting to start unit"; 179283c5d981SAlexander Motin periph->flags |= CAM_PERIPH_RECOVERY_INPROG; 17933393f8daSKenneth D. Merry 17943393f8daSKenneth D. Merry /* 17953393f8daSKenneth D. Merry * Check for removable media and set 17963393f8daSKenneth D. Merry * load/eject flag appropriately. 17973393f8daSKenneth D. Merry */ 17983393f8daSKenneth D. Merry if (SID_IS_REMOVABLE(&cgd.inq_data)) 17993393f8daSKenneth D. Merry le = TRUE; 18003393f8daSKenneth D. Merry else 18013393f8daSKenneth D. Merry le = FALSE; 18023393f8daSKenneth D. Merry 18033393f8daSKenneth D. Merry scsi_start_stop(&ccb->csio, 18043393f8daSKenneth D. Merry /*retries*/1, 18053393f8daSKenneth D. Merry camperiphdone, 18063393f8daSKenneth D. Merry MSG_SIMPLE_Q_TAG, 18073393f8daSKenneth D. Merry /*start*/TRUE, 18083393f8daSKenneth D. Merry /*load/eject*/le, 18093393f8daSKenneth D. Merry /*immediate*/FALSE, 18103393f8daSKenneth D. Merry SSD_FULL_SIZE, 18113393f8daSKenneth D. Merry /*timeout*/50000); 18123393f8daSKenneth D. Merry break; 18133393f8daSKenneth D. Merry } 18143393f8daSKenneth D. Merry case SS_TUR: 18153393f8daSKenneth D. Merry { 18163393f8daSKenneth D. Merry /* 18173393f8daSKenneth D. Merry * Send a Test Unit Ready to the device. 18183393f8daSKenneth D. Merry * If the 'many' flag is set, we send 120 18193393f8daSKenneth D. Merry * test unit ready commands, one every half 18203393f8daSKenneth D. Merry * second. Otherwise, we just send one TUR. 18213393f8daSKenneth D. Merry * We only want to do this if the retry 18223393f8daSKenneth D. Merry * count has not been exhausted. 18233393f8daSKenneth D. Merry */ 18243393f8daSKenneth D. Merry int retries; 18253393f8daSKenneth D. Merry 1826bae3729bSAlexander Motin if ((err_action & SSQ_MANY) != 0 && (periph->flags & 1827bae3729bSAlexander Motin CAM_PERIPH_RECOVERY_WAIT_FAILED) == 0) { 1828bae3729bSAlexander Motin periph->flags |= CAM_PERIPH_RECOVERY_WAIT; 182983c5d981SAlexander Motin *action_string = "Polling device for readiness"; 18303393f8daSKenneth D. Merry retries = 120; 18313393f8daSKenneth D. Merry } else { 183283c5d981SAlexander Motin *action_string = "Testing device for readiness"; 18333393f8daSKenneth D. Merry retries = 1; 18343393f8daSKenneth D. Merry } 183583c5d981SAlexander Motin periph->flags |= CAM_PERIPH_RECOVERY_INPROG; 18363393f8daSKenneth D. Merry scsi_test_unit_ready(&ccb->csio, 18373393f8daSKenneth D. Merry retries, 18383393f8daSKenneth D. Merry camperiphdone, 18393393f8daSKenneth D. Merry MSG_SIMPLE_Q_TAG, 18403393f8daSKenneth D. Merry SSD_FULL_SIZE, 18413393f8daSKenneth D. Merry /*timeout*/5000); 18423393f8daSKenneth D. Merry 18433393f8daSKenneth D. Merry /* 18443393f8daSKenneth D. Merry * Accomplish our 500ms delay by deferring 18453393f8daSKenneth D. Merry * the release of our device queue appropriately. 18463393f8daSKenneth D. Merry */ 18473393f8daSKenneth D. Merry *relsim_flags = RELSIM_RELEASE_AFTER_TIMEOUT; 18483393f8daSKenneth D. Merry *timeout = 500; 18493393f8daSKenneth D. Merry break; 18503393f8daSKenneth D. Merry } 18513393f8daSKenneth D. Merry default: 1852e3c29144SWarner Losh panic("Unhandled error action %x", err_action); 18533393f8daSKenneth D. Merry } 18543393f8daSKenneth D. Merry 18553393f8daSKenneth D. Merry if ((err_action & SS_MASK) >= SS_START) { 18563393f8daSKenneth D. Merry /* 1857bbfa4aa1SAlexander Motin * Drop the priority, so that the recovery 18583393f8daSKenneth D. Merry * CCB is the first to execute. Freeze the queue 18593393f8daSKenneth D. Merry * after this command is sent so that we can 18603393f8daSKenneth D. Merry * restore the old csio and have it queued in 18613393f8daSKenneth D. Merry * the proper order before we release normal 18623393f8daSKenneth D. Merry * transactions to the device. 18633393f8daSKenneth D. Merry */ 186483c5d981SAlexander Motin ccb->ccb_h.pinfo.priority--; 18653393f8daSKenneth D. Merry ccb->ccb_h.flags |= CAM_DEV_QFREEZE; 186683c5d981SAlexander Motin ccb->ccb_h.saved_ccb_ptr = orig_ccb; 18673393f8daSKenneth D. Merry error = ERESTART; 18680191d9b3SAlexander Motin *orig = orig_ccb; 18693393f8daSKenneth D. Merry } 18703393f8daSKenneth D. Merry 18713393f8daSKenneth D. Merry sense_error_done: 18720181d54bSAlexander Motin *action = err_action; 18733393f8daSKenneth D. Merry } 18743393f8daSKenneth D. Merry return (error); 18753393f8daSKenneth D. Merry } 18763393f8daSKenneth D. Merry 18773393f8daSKenneth D. Merry /* 18783393f8daSKenneth D. Merry * Generic error handler. Peripheral drivers usually filter 18791ffe5851SPedro F. Giffuni * out the errors that they handle in a unique manner, then 18803393f8daSKenneth D. Merry * call this function. 18813393f8daSKenneth D. Merry */ 18823393f8daSKenneth D. Merry int 18833393f8daSKenneth D. Merry cam_periph_error(union ccb *ccb, cam_flags camflags, 18847af2f2c8SWarner Losh uint32_t sense_flags) 18853393f8daSKenneth D. Merry { 18860181d54bSAlexander Motin struct cam_path *newpath; 18870181d54bSAlexander Motin union ccb *orig_ccb, *scan_ccb; 1888a07e846bSAlexander Motin struct cam_periph *periph; 18893393f8daSKenneth D. Merry const char *action_string; 18903393f8daSKenneth D. Merry cam_status status; 1891a30ecd42SScott Long int frozen, error, openings, devctl_err; 18927af2f2c8SWarner Losh uint32_t action, relsim_flags, timeout; 18933393f8daSKenneth D. Merry 18940181d54bSAlexander Motin action = SSQ_PRINT_SENSE; 1895a07e846bSAlexander Motin periph = xpt_path_periph(ccb->ccb_h.path); 18963393f8daSKenneth D. Merry action_string = NULL; 18973393f8daSKenneth D. Merry status = ccb->ccb_h.status; 18983393f8daSKenneth D. Merry frozen = (status & CAM_DEV_QFRZN) != 0; 18993393f8daSKenneth D. Merry status &= CAM_STATUS_MASK; 1900a30ecd42SScott Long devctl_err = openings = relsim_flags = timeout = 0; 19010191d9b3SAlexander Motin orig_ccb = ccb; 19023393f8daSKenneth D. Merry 1903a30ecd42SScott Long /* Filter the errors that should be reported via devctl */ 1904a30ecd42SScott Long switch (ccb->ccb_h.status & CAM_STATUS_MASK) { 1905a30ecd42SScott Long case CAM_CMD_TIMEOUT: 1906a30ecd42SScott Long case CAM_REQ_ABORTED: 1907a30ecd42SScott Long case CAM_REQ_CMP_ERR: 1908a30ecd42SScott Long case CAM_REQ_TERMIO: 1909a30ecd42SScott Long case CAM_UNREC_HBA_ERROR: 1910a30ecd42SScott Long case CAM_DATA_RUN_ERR: 1911a30ecd42SScott Long case CAM_SCSI_STATUS_ERROR: 1912a30ecd42SScott Long case CAM_ATA_STATUS_ERROR: 1913a30ecd42SScott Long case CAM_SMP_STATUS_ERROR: 1914cf0a543fSWarner Losh case CAM_DEV_NOT_THERE: 1915cf0a543fSWarner Losh case CAM_NVME_STATUS_ERROR: 1916a30ecd42SScott Long devctl_err++; 1917a30ecd42SScott Long break; 1918a30ecd42SScott Long default: 1919a30ecd42SScott Long break; 1920a30ecd42SScott Long } 1921a30ecd42SScott Long 19223393f8daSKenneth D. Merry switch (status) { 19233393f8daSKenneth D. Merry case CAM_REQ_CMP: 19243393f8daSKenneth D. Merry error = 0; 19250181d54bSAlexander Motin action &= ~SSQ_PRINT_SENSE; 19263393f8daSKenneth D. Merry break; 19273393f8daSKenneth D. Merry case CAM_SCSI_STATUS_ERROR: 19280191d9b3SAlexander Motin error = camperiphscsistatuserror(ccb, &orig_ccb, 19290191d9b3SAlexander Motin camflags, sense_flags, &openings, &relsim_flags, 19300181d54bSAlexander Motin &timeout, &action, &action_string); 19313393f8daSKenneth D. Merry break; 19323393f8daSKenneth D. Merry case CAM_AUTOSENSE_FAIL: 1933c7ec4390SMatt Jacob error = EIO; /* we have to kill the command */ 1934c7ec4390SMatt Jacob break; 19358b8a9b1dSJustin T. Gibbs case CAM_UA_ABORT: 19368b8a9b1dSJustin T. Gibbs case CAM_UA_TERMIO: 19378b8a9b1dSJustin T. Gibbs case CAM_MSG_REJECT_REC: 19388b8a9b1dSJustin T. Gibbs /* XXX Don't know that these are correct */ 19398b8a9b1dSJustin T. Gibbs error = EIO; 19408b8a9b1dSJustin T. Gibbs break; 19418b8a9b1dSJustin T. Gibbs case CAM_SEL_TIMEOUT: 19423393f8daSKenneth D. Merry if ((camflags & CAM_RETRY_SELTO) != 0) { 1943a07e846bSAlexander Motin if (ccb->ccb_h.retry_count > 0 && 1944a07e846bSAlexander Motin (periph->flags & CAM_PERIPH_INVALID) == 0) { 19453393f8daSKenneth D. Merry ccb->ccb_h.retry_count--; 19463393f8daSKenneth D. Merry error = ERESTART; 19473393f8daSKenneth D. Merry 19483393f8daSKenneth D. Merry /* 194973cf209fSMatt Jacob * Wait a bit to give the device 19503393f8daSKenneth D. Merry * time to recover before we try again. 19513393f8daSKenneth D. Merry */ 19523393f8daSKenneth D. Merry relsim_flags = RELSIM_RELEASE_AFTER_TIMEOUT; 195373cf209fSMatt Jacob timeout = periph_selto_delay; 19543393f8daSKenneth D. Merry break; 19553393f8daSKenneth D. Merry } 1956a07e846bSAlexander Motin action_string = "Retries exhausted"; 19573393f8daSKenneth D. Merry } 19588900f4b8SKenneth D. Merry /* FALLTHROUGH */ 19598900f4b8SKenneth D. Merry case CAM_DEV_NOT_THERE: 19603393f8daSKenneth D. Merry error = ENXIO; 19610181d54bSAlexander Motin action = SSQ_LOST; 19628b8a9b1dSJustin T. Gibbs break; 19638b8a9b1dSJustin T. Gibbs case CAM_REQ_INVALID: 19648b8a9b1dSJustin T. Gibbs case CAM_PATH_INVALID: 19658b8a9b1dSJustin T. Gibbs case CAM_NO_HBA: 19668b8a9b1dSJustin T. Gibbs case CAM_PROVIDE_FAIL: 19678b8a9b1dSJustin T. Gibbs case CAM_REQ_TOO_BIG: 19689a014e6fSIan Dowse case CAM_LUN_INVALID: 19699a014e6fSIan Dowse case CAM_TID_INVALID: 1970357478a5SAlexander Motin case CAM_FUNC_NOTAVAIL: 19718b8a9b1dSJustin T. Gibbs error = EINVAL; 19728b8a9b1dSJustin T. Gibbs break; 19738b8a9b1dSJustin T. Gibbs case CAM_SCSI_BUS_RESET: 19748b8a9b1dSJustin T. Gibbs case CAM_BDR_SENT: 19753393f8daSKenneth D. Merry /* 19763393f8daSKenneth D. Merry * Commands that repeatedly timeout and cause these 19773393f8daSKenneth D. Merry * kinds of error recovery actions, should return 19783393f8daSKenneth D. Merry * CAM_CMD_TIMEOUT, which allows us to safely assume 19793393f8daSKenneth D. Merry * that this command was an innocent bystander to 19803393f8daSKenneth D. Merry * these events and should be unconditionally 19813393f8daSKenneth D. Merry * retried. 19823393f8daSKenneth D. Merry */ 19838b8a9b1dSJustin T. Gibbs case CAM_REQUEUE_REQ: 19840191d9b3SAlexander Motin /* Unconditional requeue if device is still there */ 19850191d9b3SAlexander Motin if (periph->flags & CAM_PERIPH_INVALID) { 19860191d9b3SAlexander Motin action_string = "Periph was invalidated"; 19879fb40bafSWarner Losh error = ENXIO; 19880191d9b3SAlexander Motin } else if (sense_flags & SF_NO_RETRY) { 19890191d9b3SAlexander Motin error = EIO; 19900191d9b3SAlexander Motin action_string = "Retry was blocked"; 199184c4de2dSAlexander Motin } else { 19920191d9b3SAlexander Motin error = ERESTART; 19930181d54bSAlexander Motin action &= ~SSQ_PRINT_SENSE; 199484c4de2dSAlexander Motin } 19958b8a9b1dSJustin T. Gibbs break; 19968b8a9b1dSJustin T. Gibbs case CAM_RESRC_UNAVAIL: 199773cf209fSMatt Jacob /* Wait a bit for the resource shortage to abate. */ 199873cf209fSMatt Jacob timeout = periph_noresrc_delay; 199973cf209fSMatt Jacob /* FALLTHROUGH */ 20008b8a9b1dSJustin T. Gibbs case CAM_BUSY: 200173cf209fSMatt Jacob if (timeout == 0) { 200273cf209fSMatt Jacob /* Wait a bit for the busy condition to abate. */ 200373cf209fSMatt Jacob timeout = periph_busy_delay; 200473cf209fSMatt Jacob } 200573cf209fSMatt Jacob relsim_flags = RELSIM_RELEASE_AFTER_TIMEOUT; 200673cf209fSMatt Jacob /* FALLTHROUGH */ 20070191d9b3SAlexander Motin case CAM_ATA_STATUS_ERROR: 2008774ab87cSWarner Losh case CAM_NVME_STATUS_ERROR: 200933734ddfSWarner Losh case CAM_SMP_STATUS_ERROR: 20100191d9b3SAlexander Motin case CAM_REQ_CMP_ERR: 20110191d9b3SAlexander Motin case CAM_CMD_TIMEOUT: 20120191d9b3SAlexander Motin case CAM_UNEXP_BUSFREE: 20130191d9b3SAlexander Motin case CAM_UNCOR_PARITY: 20140191d9b3SAlexander Motin case CAM_DATA_RUN_ERR: 20158b8a9b1dSJustin T. Gibbs default: 20160191d9b3SAlexander Motin if (periph->flags & CAM_PERIPH_INVALID) { 20179fb40bafSWarner Losh error = ENXIO; 20180191d9b3SAlexander Motin action_string = "Periph was invalidated"; 20190191d9b3SAlexander Motin } else if (ccb->ccb_h.retry_count == 0) { 20208b8a9b1dSJustin T. Gibbs error = EIO; 202183c5d981SAlexander Motin action_string = "Retries exhausted"; 20220191d9b3SAlexander Motin } else if (sense_flags & SF_NO_RETRY) { 20230191d9b3SAlexander Motin error = EIO; 20240191d9b3SAlexander Motin action_string = "Retry was blocked"; 20250191d9b3SAlexander Motin } else { 20260191d9b3SAlexander Motin ccb->ccb_h.retry_count--; 20270191d9b3SAlexander Motin error = ERESTART; 20288b8a9b1dSJustin T. Gibbs } 20298b8a9b1dSJustin T. Gibbs break; 20308b8a9b1dSJustin T. Gibbs } 20318b8a9b1dSJustin T. Gibbs 20320191d9b3SAlexander Motin if ((sense_flags & SF_PRINT_ALWAYS) || 20330191d9b3SAlexander Motin CAM_DEBUGGED(ccb->ccb_h.path, CAM_DEBUG_INFO)) 20340181d54bSAlexander Motin action |= SSQ_PRINT_SENSE; 20350191d9b3SAlexander Motin else if (sense_flags & SF_NO_PRINT) 20360181d54bSAlexander Motin action &= ~SSQ_PRINT_SENSE; 20370181d54bSAlexander Motin if ((action & SSQ_PRINT_SENSE) != 0) 20380191d9b3SAlexander Motin cam_error_print(orig_ccb, CAM_ESF_ALL, CAM_EPF_ALL); 20390181d54bSAlexander Motin if (error != 0 && (action & SSQ_PRINT_SENSE) != 0) { 20400f3e2159SAlexander Motin if (error != ERESTART) { 20413393f8daSKenneth D. Merry if (action_string == NULL) 204283c5d981SAlexander Motin action_string = "Unretryable error"; 204383c5d981SAlexander Motin xpt_print(ccb->ccb_h.path, "Error %d, %s\n", 204483c5d981SAlexander Motin error, action_string); 204583c5d981SAlexander Motin } else if (action_string != NULL) 2046f0d9af51SMatt Jacob xpt_print(ccb->ccb_h.path, "%s\n", action_string); 2047bc40691eSWarner Losh else { 2048bc40691eSWarner Losh xpt_print(ccb->ccb_h.path, 2049bc40691eSWarner Losh "Retrying command, %d more tries remain\n", 2050bc40691eSWarner Losh ccb->ccb_h.retry_count); 2051bc40691eSWarner Losh } 20520f3e2159SAlexander Motin } 20530f3e2159SAlexander Motin 2054cd375264SAlexander Motin if (devctl_err && (error != 0 || (action & SSQ_PRINT_SENSE) != 0)) 2055a30ecd42SScott Long cam_periph_devctl_notify(orig_ccb); 2056a30ecd42SScott Long 20570181d54bSAlexander Motin if ((action & SSQ_LOST) != 0) { 20580191d9b3SAlexander Motin lun_id_t lun_id; 20590191d9b3SAlexander Motin 20600191d9b3SAlexander Motin /* 20610191d9b3SAlexander Motin * For a selection timeout, we consider all of the LUNs on 20620191d9b3SAlexander Motin * the target to be gone. If the status is CAM_DEV_NOT_THERE, 20630191d9b3SAlexander Motin * then we only get rid of the device(s) specified by the 20640191d9b3SAlexander Motin * path in the original CCB. 20650191d9b3SAlexander Motin */ 20660181d54bSAlexander Motin if (status == CAM_SEL_TIMEOUT) 20670191d9b3SAlexander Motin lun_id = CAM_LUN_WILDCARD; 20680181d54bSAlexander Motin else 20690181d54bSAlexander Motin lun_id = xpt_path_lun_id(ccb->ccb_h.path); 20700191d9b3SAlexander Motin 20710191d9b3SAlexander Motin /* Should we do more if we can't create the path?? */ 20720191d9b3SAlexander Motin if (xpt_create_path(&newpath, periph, 20730191d9b3SAlexander Motin xpt_path_path_id(ccb->ccb_h.path), 20740191d9b3SAlexander Motin xpt_path_target_id(ccb->ccb_h.path), 20750191d9b3SAlexander Motin lun_id) == CAM_REQ_CMP) { 20760191d9b3SAlexander Motin /* 20770191d9b3SAlexander Motin * Let peripheral drivers know that this 20780191d9b3SAlexander Motin * device has gone away. 20790191d9b3SAlexander Motin */ 20800191d9b3SAlexander Motin xpt_async(AC_LOST_DEVICE, newpath, NULL); 20810191d9b3SAlexander Motin xpt_free_path(newpath); 20820191d9b3SAlexander Motin } 20830181d54bSAlexander Motin } 20843631c638SAlexander Motin 20853631c638SAlexander Motin /* Broadcast UNIT ATTENTIONs to all periphs. */ 20860181d54bSAlexander Motin if ((action & SSQ_UA) != 0) 20873631c638SAlexander Motin xpt_async(AC_UNIT_ATTENTION, orig_ccb->ccb_h.path, orig_ccb); 20880181d54bSAlexander Motin 20890181d54bSAlexander Motin /* Rescan target on "Reported LUNs data has changed" */ 20900181d54bSAlexander Motin if ((action & SSQ_RESCAN) != 0) { 20910181d54bSAlexander Motin if (xpt_create_path(&newpath, NULL, 20920181d54bSAlexander Motin xpt_path_path_id(ccb->ccb_h.path), 20930181d54bSAlexander Motin xpt_path_target_id(ccb->ccb_h.path), 2094e5736ac8SAlexander Motin CAM_LUN_WILDCARD) == CAM_REQ_CMP) { 20950181d54bSAlexander Motin scan_ccb = xpt_alloc_ccb_nowait(); 2096e5736ac8SAlexander Motin if (scan_ccb != NULL) { 20970181d54bSAlexander Motin scan_ccb->ccb_h.path = newpath; 2098e5736ac8SAlexander Motin scan_ccb->ccb_h.func_code = XPT_SCAN_TGT; 20990181d54bSAlexander Motin scan_ccb->crcn.flags = 0; 21000181d54bSAlexander Motin xpt_rescan(scan_ccb); 21013231e8bdSAlexander Motin } else { 2102e5736ac8SAlexander Motin xpt_print(newpath, 2103e5736ac8SAlexander Motin "Can't allocate CCB to rescan target\n"); 21043231e8bdSAlexander Motin xpt_free_path(newpath); 21053231e8bdSAlexander Motin } 21060181d54bSAlexander Motin } 21070191d9b3SAlexander Motin } 21080191d9b3SAlexander Motin 21090f3e2159SAlexander Motin /* Attempt a retry */ 21100f3e2159SAlexander Motin if (error == ERESTART || error == 0) { 21110f3e2159SAlexander Motin if (frozen != 0) 21120f3e2159SAlexander Motin ccb->ccb_h.status &= ~CAM_DEV_QFRZN; 21130f3e2159SAlexander Motin if (error == ERESTART) 21140f3e2159SAlexander Motin xpt_action(ccb); 21150f3e2159SAlexander Motin if (frozen != 0) 21160f3e2159SAlexander Motin cam_release_devq(ccb->ccb_h.path, 21170f3e2159SAlexander Motin relsim_flags, 21180f3e2159SAlexander Motin openings, 21190f3e2159SAlexander Motin timeout, 21200f3e2159SAlexander Motin /*getcount_only*/0); 21213393f8daSKenneth D. Merry } 21228b8a9b1dSJustin T. Gibbs 21238b8a9b1dSJustin T. Gibbs return (error); 21248b8a9b1dSJustin T. Gibbs } 2125a30ecd42SScott Long 2126a30ecd42SScott Long #define CAM_PERIPH_DEVD_MSG_SIZE 256 2127a30ecd42SScott Long 2128a30ecd42SScott Long static void 2129a30ecd42SScott Long cam_periph_devctl_notify(union ccb *ccb) 2130a30ecd42SScott Long { 2131a30ecd42SScott Long struct cam_periph *periph; 2132a30ecd42SScott Long struct ccb_getdev *cgd; 2133a30ecd42SScott Long struct sbuf sb; 2134a30ecd42SScott Long int serr, sk, asc, ascq; 2135a30ecd42SScott Long char *sbmsg, *type; 2136a30ecd42SScott Long 2137a30ecd42SScott Long sbmsg = malloc(CAM_PERIPH_DEVD_MSG_SIZE, M_CAMPERIPH, M_NOWAIT); 2138a30ecd42SScott Long if (sbmsg == NULL) 2139a30ecd42SScott Long return; 2140a30ecd42SScott Long 2141a30ecd42SScott Long sbuf_new(&sb, sbmsg, CAM_PERIPH_DEVD_MSG_SIZE, SBUF_FIXEDLEN); 2142a30ecd42SScott Long 2143a30ecd42SScott Long periph = xpt_path_periph(ccb->ccb_h.path); 2144a30ecd42SScott Long sbuf_printf(&sb, "device=%s%d ", periph->periph_name, 2145a30ecd42SScott Long periph->unit_number); 2146a30ecd42SScott Long 2147519b24f0SAlexander Motin sbuf_cat(&sb, "serial=\""); 2148a30ecd42SScott Long if ((cgd = (struct ccb_getdev *)xpt_alloc_ccb_nowait()) != NULL) { 2149a30ecd42SScott Long xpt_setup_ccb(&cgd->ccb_h, ccb->ccb_h.path, 2150a30ecd42SScott Long CAM_PRIORITY_NORMAL); 2151a30ecd42SScott Long cgd->ccb_h.func_code = XPT_GDEV_TYPE; 2152a30ecd42SScott Long xpt_action((union ccb *)cgd); 2153a30ecd42SScott Long 2154a30ecd42SScott Long if (cgd->ccb_h.status == CAM_REQ_CMP) 2155a30ecd42SScott Long sbuf_bcat(&sb, cgd->serial_num, cgd->serial_num_len); 2156de482e7bSScott Long xpt_free_ccb((union ccb *)cgd); 2157a30ecd42SScott Long } 2158519b24f0SAlexander Motin sbuf_cat(&sb, "\" "); 2159a30ecd42SScott Long sbuf_printf(&sb, "cam_status=\"0x%x\" ", ccb->ccb_h.status); 2160a30ecd42SScott Long 2161a30ecd42SScott Long switch (ccb->ccb_h.status & CAM_STATUS_MASK) { 2162a30ecd42SScott Long case CAM_CMD_TIMEOUT: 2163a30ecd42SScott Long sbuf_printf(&sb, "timeout=%d ", ccb->ccb_h.timeout); 2164a30ecd42SScott Long type = "timeout"; 2165a30ecd42SScott Long break; 2166a30ecd42SScott Long case CAM_SCSI_STATUS_ERROR: 2167a30ecd42SScott Long sbuf_printf(&sb, "scsi_status=%d ", ccb->csio.scsi_status); 2168a30ecd42SScott Long if (scsi_extract_sense_ccb(ccb, &serr, &sk, &asc, &ascq)) 2169a30ecd42SScott Long sbuf_printf(&sb, "scsi_sense=\"%02x %02x %02x %02x\" ", 2170a30ecd42SScott Long serr, sk, asc, ascq); 2171a30ecd42SScott Long type = "error"; 2172a30ecd42SScott Long break; 2173a30ecd42SScott Long case CAM_ATA_STATUS_ERROR: 2174519b24f0SAlexander Motin sbuf_cat(&sb, "RES=\""); 2175a30ecd42SScott Long ata_res_sbuf(&ccb->ataio.res, &sb); 2176519b24f0SAlexander Motin sbuf_cat(&sb, "\" "); 2177a30ecd42SScott Long type = "error"; 2178a30ecd42SScott Long break; 2179500196c5SWarner Losh case CAM_NVME_STATUS_ERROR: 2180500196c5SWarner Losh { 2181500196c5SWarner Losh struct ccb_nvmeio *n = &ccb->nvmeio; 2182500196c5SWarner Losh 2183500196c5SWarner Losh sbuf_printf(&sb, "sc=\"%02x\" sct=\"%02x\" cdw0=\"%08x\" ", 2184500196c5SWarner Losh NVME_STATUS_GET_SC(n->cpl.status), 2185500196c5SWarner Losh NVME_STATUS_GET_SCT(n->cpl.status), n->cpl.cdw0); 2186500196c5SWarner Losh type = "error"; 2187500196c5SWarner Losh break; 2188500196c5SWarner Losh } 2189a30ecd42SScott Long default: 2190a30ecd42SScott Long type = "error"; 2191a30ecd42SScott Long break; 2192a30ecd42SScott Long } 2193a30ecd42SScott Long 2194500196c5SWarner Losh 2195500196c5SWarner Losh switch (ccb->ccb_h.func_code) { 2196500196c5SWarner Losh case XPT_SCSI_IO: 2197519b24f0SAlexander Motin sbuf_cat(&sb, "CDB=\""); 21984902e14dSAlexander Motin scsi_cdb_sbuf(scsiio_cdb_ptr(&ccb->csio), &sb); 2199519b24f0SAlexander Motin sbuf_cat(&sb, "\" "); 2200500196c5SWarner Losh break; 2201500196c5SWarner Losh case XPT_ATA_IO: 2202519b24f0SAlexander Motin sbuf_cat(&sb, "ACB=\""); 2203a30ecd42SScott Long ata_cmd_sbuf(&ccb->ataio.cmd, &sb); 2204519b24f0SAlexander Motin sbuf_cat(&sb, "\" "); 2205500196c5SWarner Losh break; 2206500196c5SWarner Losh case XPT_NVME_IO: 2207500196c5SWarner Losh case XPT_NVME_ADMIN: 2208500196c5SWarner Losh { 2209500196c5SWarner Losh struct ccb_nvmeio *n = &ccb->nvmeio; 2210500196c5SWarner Losh struct nvme_command *cmd = &n->cmd; 2211500196c5SWarner Losh 2212500196c5SWarner Losh // XXX Likely should be nvme_cmd_sbuf 2213500196c5SWarner Losh sbuf_printf(&sb, "opc=\"%02x\" fuse=\"%02x\" cid=\"%04x\" " 2214500196c5SWarner Losh "nsid=\"%08x\" cdw10=\"%08x\" cdw11=\"%08x\" cdw12=\"%08x\" " 2215500196c5SWarner Losh "cdw13=\"%08x\" cdw14=\"%08x\" cdw15=\"%08x\" ", 2216500196c5SWarner Losh cmd->opc, cmd->fuse, cmd->cid, cmd->nsid, cmd->cdw10, 2217500196c5SWarner Losh cmd->cdw11, cmd->cdw12, cmd->cdw13, cmd->cdw14, cmd->cdw15); 2218500196c5SWarner Losh break; 2219500196c5SWarner Losh } 2220500196c5SWarner Losh default: 2221500196c5SWarner Losh break; 2222a30ecd42SScott Long } 2223a30ecd42SScott Long 2224a30ecd42SScott Long if (sbuf_finish(&sb) == 0) 2225a30ecd42SScott Long devctl_notify("CAM", "periph", type, sbuf_data(&sb)); 2226a30ecd42SScott Long sbuf_delete(&sb); 2227a30ecd42SScott Long free(sbmsg, M_CAMPERIPH); 2228a30ecd42SScott Long } 2229a30ecd42SScott Long 2230d38677d2SWarner Losh /* 2231d38677d2SWarner Losh * Sysctl to force an invalidation of the drive right now. Can be 2232d38677d2SWarner Losh * called with CTLFLAG_MPSAFE since we take periph lock. 2233d38677d2SWarner Losh */ 2234d38677d2SWarner Losh int 2235d38677d2SWarner Losh cam_periph_invalidate_sysctl(SYSCTL_HANDLER_ARGS) 2236d38677d2SWarner Losh { 2237d38677d2SWarner Losh struct cam_periph *periph; 2238d38677d2SWarner Losh int error, value; 2239d38677d2SWarner Losh 2240d38677d2SWarner Losh periph = arg1; 2241d38677d2SWarner Losh value = 0; 2242d38677d2SWarner Losh error = sysctl_handle_int(oidp, &value, 0, req); 2243d38677d2SWarner Losh if (error != 0 || req->newptr == NULL || value != 1) 2244d38677d2SWarner Losh return (error); 2245d38677d2SWarner Losh 2246d38677d2SWarner Losh cam_periph_lock(periph); 2247d38677d2SWarner Losh cam_periph_invalidate(periph); 2248d38677d2SWarner Losh cam_periph_unlock(periph); 2249d38677d2SWarner Losh 2250d38677d2SWarner Losh return (0); 2251d38677d2SWarner Losh } 2252