1fa9e4066Sahrens /* 2fa9e4066Sahrens * CDDL HEADER START 3fa9e4066Sahrens * 4fa9e4066Sahrens * The contents of this file are subject to the terms of the 5bef6b7d2Swebaker * Common Development and Distribution License (the "License"). 6bef6b7d2Swebaker * You may not use this file except in compliance with the License. 7fa9e4066Sahrens * 8fa9e4066Sahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9fa9e4066Sahrens * or http://www.opensolaris.org/os/licensing. 10fa9e4066Sahrens * See the License for the specific language governing permissions 11fa9e4066Sahrens * and limitations under the License. 12fa9e4066Sahrens * 13fa9e4066Sahrens * When distributing Covered Code, include this CDDL HEADER in each 14fa9e4066Sahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15fa9e4066Sahrens * If applicable, add the following below this CDDL HEADER, with the 16fa9e4066Sahrens * fields enclosed by brackets "[]" replaced with your own identifying 17fa9e4066Sahrens * information: Portions Copyright [yyyy] [name of copyright owner] 18fa9e4066Sahrens * 19fa9e4066Sahrens * CDDL HEADER END 20fa9e4066Sahrens */ 21fa9e4066Sahrens /* 22f13665b7Sbo zhou - Sun Microsystems - Beijing China * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 236fe4f300SPavel Zakharov * Copyright (c) 2012, 2018 by Delphix. All rights reserved. 24295438baSHans Rosenfeld * Copyright 2016 Nexenta Systems, Inc. All rights reserved. 25fa88c70fSJerry Jelinek * Copyright 2019 Joyent, Inc. 26fa9e4066Sahrens */ 27fa9e4066Sahrens 28fa9e4066Sahrens #include <sys/zfs_context.h> 29dcba9f3fSGeorge Wilson #include <sys/spa_impl.h> 30e7cbe64fSgw #include <sys/refcount.h> 31fa9e4066Sahrens #include <sys/vdev_disk.h> 32fa9e4066Sahrens #include <sys/vdev_impl.h> 33084fd14fSBrian Behlendorf #include <sys/vdev_trim.h> 34770499e1SDan Kimmel #include <sys/abd.h> 35fa9e4066Sahrens #include <sys/fs/zfs.h> 36fa9e4066Sahrens #include <sys/zio.h> 37afefbcddSeschrock #include <sys/sunldi.h> 384263d13fSGeorge Wilson #include <sys/efi_partition.h> 3951ece835Seschrock #include <sys/fm/fs/zfs.h> 40fa9e4066Sahrens 41fb05b94aSJerry Jelinek /* 42*fc5c75cfSJerry Jelinek * Tunable to disable TRIM in case we're using a problematic SSD. 43fb05b94aSJerry Jelinek */ 44*fc5c75cfSJerry Jelinek uint_t zfs_no_trim = 0; 45fb05b94aSJerry Jelinek 46f8fdf681SPrakash Surya /* 47f8fdf681SPrakash Surya * Tunable parameter for debugging or performance analysis. Setting this 48f8fdf681SPrakash Surya * will cause pool corruption on power loss if a volatile out-of-order 49f8fdf681SPrakash Surya * write cache is enabled. 50f8fdf681SPrakash Surya */ 51f8fdf681SPrakash Surya boolean_t zfs_nocacheflush = B_FALSE; 52f8fdf681SPrakash Surya 53fa9e4066Sahrens /* 54fa9e4066Sahrens * Virtual device vector for disks. 55fa9e4066Sahrens */ 56fa9e4066Sahrens 57fa9e4066Sahrens extern ldi_ident_t zfs_li; 58fa9e4066Sahrens 5939cddb10SJoshua M. Clulow static void vdev_disk_close(vdev_t *); 6039cddb10SJoshua M. Clulow 6139cddb10SJoshua M. Clulow typedef struct vdev_disk_ldi_cb { 6239cddb10SJoshua M. Clulow list_node_t lcb_next; 6339cddb10SJoshua M. Clulow ldi_callback_id_t lcb_id; 6439cddb10SJoshua M. Clulow } vdev_disk_ldi_cb_t; 6539cddb10SJoshua M. Clulow 666fe4f300SPavel Zakharov /* 676fe4f300SPavel Zakharov * Bypass the devid when opening a disk vdev. 686fe4f300SPavel Zakharov * There have been issues where the devids of several devices were shuffled, 696fe4f300SPavel Zakharov * causing pool open failures. Note, that this flag is intended to be used 706fe4f300SPavel Zakharov * for pool recovery only. 716fe4f300SPavel Zakharov * 726fe4f300SPavel Zakharov * Note that if a pool is imported with the devids bypassed, all its vdevs will 736fe4f300SPavel Zakharov * cease storing devid information permanently. In practice, the devid is rarely 746fe4f300SPavel Zakharov * useful as vdev paths do not tend to change unless the hardware is 756fe4f300SPavel Zakharov * reconfigured. That said, if the paths do change and a pool fails to open 766fe4f300SPavel Zakharov * automatically at boot, a simple zpool import should re-scan the paths and fix 776fe4f300SPavel Zakharov * the issue. 786fe4f300SPavel Zakharov */ 796fe4f300SPavel Zakharov boolean_t vdev_disk_bypass_devid = B_FALSE; 806fe4f300SPavel Zakharov 8139cddb10SJoshua M. Clulow static void 8239cddb10SJoshua M. Clulow vdev_disk_alloc(vdev_t *vd) 8339cddb10SJoshua M. Clulow { 8439cddb10SJoshua M. Clulow vdev_disk_t *dvd; 8539cddb10SJoshua M. Clulow 8639cddb10SJoshua M. Clulow dvd = vd->vdev_tsd = kmem_zalloc(sizeof (vdev_disk_t), KM_SLEEP); 8739cddb10SJoshua M. Clulow /* 8839cddb10SJoshua M. Clulow * Create the LDI event callback list. 8939cddb10SJoshua M. Clulow */ 9039cddb10SJoshua M. Clulow list_create(&dvd->vd_ldi_cbs, sizeof (vdev_disk_ldi_cb_t), 9139cddb10SJoshua M. Clulow offsetof(vdev_disk_ldi_cb_t, lcb_next)); 9239cddb10SJoshua M. Clulow } 9339cddb10SJoshua M. Clulow 9439cddb10SJoshua M. Clulow static void 9539cddb10SJoshua M. Clulow vdev_disk_free(vdev_t *vd) 9639cddb10SJoshua M. Clulow { 9739cddb10SJoshua M. Clulow vdev_disk_t *dvd = vd->vdev_tsd; 9839cddb10SJoshua M. Clulow vdev_disk_ldi_cb_t *lcb; 9939cddb10SJoshua M. Clulow 10039cddb10SJoshua M. Clulow if (dvd == NULL) 10139cddb10SJoshua M. Clulow return; 10239cddb10SJoshua M. Clulow 10339cddb10SJoshua M. Clulow /* 10439cddb10SJoshua M. Clulow * We have already closed the LDI handle. Clean up the LDI event 10539cddb10SJoshua M. Clulow * callbacks and free vd->vdev_tsd. 10639cddb10SJoshua M. Clulow */ 10739cddb10SJoshua M. Clulow while ((lcb = list_head(&dvd->vd_ldi_cbs)) != NULL) { 10839cddb10SJoshua M. Clulow list_remove(&dvd->vd_ldi_cbs, lcb); 10939cddb10SJoshua M. Clulow (void) ldi_ev_remove_callbacks(lcb->lcb_id); 11039cddb10SJoshua M. Clulow kmem_free(lcb, sizeof (vdev_disk_ldi_cb_t)); 11139cddb10SJoshua M. Clulow } 11239cddb10SJoshua M. Clulow list_destroy(&dvd->vd_ldi_cbs); 11339cddb10SJoshua M. Clulow kmem_free(dvd, sizeof (vdev_disk_t)); 11439cddb10SJoshua M. Clulow vd->vdev_tsd = NULL; 11539cddb10SJoshua M. Clulow } 11639cddb10SJoshua M. Clulow 11739cddb10SJoshua M. Clulow /* ARGSUSED */ 11839cddb10SJoshua M. Clulow static int 11939cddb10SJoshua M. Clulow vdev_disk_off_notify(ldi_handle_t lh, ldi_ev_cookie_t ecookie, void *arg, 12039cddb10SJoshua M. Clulow void *ev_data) 12139cddb10SJoshua M. Clulow { 12239cddb10SJoshua M. Clulow vdev_t *vd = (vdev_t *)arg; 12339cddb10SJoshua M. Clulow vdev_disk_t *dvd = vd->vdev_tsd; 12439cddb10SJoshua M. Clulow 12539cddb10SJoshua M. Clulow /* 12639cddb10SJoshua M. Clulow * Ignore events other than offline. 12739cddb10SJoshua M. Clulow */ 12839cddb10SJoshua M. Clulow if (strcmp(ldi_ev_get_type(ecookie), LDI_EV_OFFLINE) != 0) 12939cddb10SJoshua M. Clulow return (LDI_EV_SUCCESS); 13039cddb10SJoshua M. Clulow 13139cddb10SJoshua M. Clulow /* 13239cddb10SJoshua M. Clulow * All LDI handles must be closed for the state change to succeed, so 13339cddb10SJoshua M. Clulow * call on vdev_disk_close() to do this. 13439cddb10SJoshua M. Clulow * 13539cddb10SJoshua M. Clulow * We inform vdev_disk_close that it is being called from offline 13639cddb10SJoshua M. Clulow * notify context so it will defer cleanup of LDI event callbacks and 13739cddb10SJoshua M. Clulow * freeing of vd->vdev_tsd to the offline finalize or a reopen. 13839cddb10SJoshua M. Clulow */ 13939cddb10SJoshua M. Clulow dvd->vd_ldi_offline = B_TRUE; 14039cddb10SJoshua M. Clulow vdev_disk_close(vd); 14139cddb10SJoshua M. Clulow 14239cddb10SJoshua M. Clulow /* 14339cddb10SJoshua M. Clulow * Now that the device is closed, request that the spa_async_thread 14439cddb10SJoshua M. Clulow * mark the device as REMOVED and notify FMA of the removal. 14539cddb10SJoshua M. Clulow */ 14639cddb10SJoshua M. Clulow zfs_post_remove(vd->vdev_spa, vd); 14739cddb10SJoshua M. Clulow vd->vdev_remove_wanted = B_TRUE; 14839cddb10SJoshua M. Clulow spa_async_request(vd->vdev_spa, SPA_ASYNC_REMOVE); 14939cddb10SJoshua M. Clulow 15039cddb10SJoshua M. Clulow return (LDI_EV_SUCCESS); 15139cddb10SJoshua M. Clulow } 15239cddb10SJoshua M. Clulow 15339cddb10SJoshua M. Clulow /* ARGSUSED */ 15439cddb10SJoshua M. Clulow static void 15539cddb10SJoshua M. Clulow vdev_disk_off_finalize(ldi_handle_t lh, ldi_ev_cookie_t ecookie, 15639cddb10SJoshua M. Clulow int ldi_result, void *arg, void *ev_data) 15739cddb10SJoshua M. Clulow { 15839cddb10SJoshua M. Clulow vdev_t *vd = (vdev_t *)arg; 15939cddb10SJoshua M. Clulow 16039cddb10SJoshua M. Clulow /* 16139cddb10SJoshua M. Clulow * Ignore events other than offline. 16239cddb10SJoshua M. Clulow */ 16339cddb10SJoshua M. Clulow if (strcmp(ldi_ev_get_type(ecookie), LDI_EV_OFFLINE) != 0) 16439cddb10SJoshua M. Clulow return; 16539cddb10SJoshua M. Clulow 16639cddb10SJoshua M. Clulow /* 16739cddb10SJoshua M. Clulow * We have already closed the LDI handle in notify. 16839cddb10SJoshua M. Clulow * Clean up the LDI event callbacks and free vd->vdev_tsd. 16939cddb10SJoshua M. Clulow */ 17039cddb10SJoshua M. Clulow vdev_disk_free(vd); 17139cddb10SJoshua M. Clulow 17239cddb10SJoshua M. Clulow /* 17339cddb10SJoshua M. Clulow * Request that the vdev be reopened if the offline state change was 17439cddb10SJoshua M. Clulow * unsuccessful. 17539cddb10SJoshua M. Clulow */ 17639cddb10SJoshua M. Clulow if (ldi_result != LDI_EV_SUCCESS) { 17739cddb10SJoshua M. Clulow vd->vdev_probe_wanted = B_TRUE; 17839cddb10SJoshua M. Clulow spa_async_request(vd->vdev_spa, SPA_ASYNC_PROBE); 17939cddb10SJoshua M. Clulow } 18039cddb10SJoshua M. Clulow } 18139cddb10SJoshua M. Clulow 18239cddb10SJoshua M. Clulow static ldi_ev_callback_t vdev_disk_off_callb = { 18339cddb10SJoshua M. Clulow .cb_vers = LDI_EV_CB_VERS, 18439cddb10SJoshua M. Clulow .cb_notify = vdev_disk_off_notify, 18539cddb10SJoshua M. Clulow .cb_finalize = vdev_disk_off_finalize 18639cddb10SJoshua M. Clulow }; 18739cddb10SJoshua M. Clulow 18839cddb10SJoshua M. Clulow /* ARGSUSED */ 18939cddb10SJoshua M. Clulow static void 19039cddb10SJoshua M. Clulow vdev_disk_dgrd_finalize(ldi_handle_t lh, ldi_ev_cookie_t ecookie, 19139cddb10SJoshua M. Clulow int ldi_result, void *arg, void *ev_data) 19239cddb10SJoshua M. Clulow { 19339cddb10SJoshua M. Clulow vdev_t *vd = (vdev_t *)arg; 19439cddb10SJoshua M. Clulow 19539cddb10SJoshua M. Clulow /* 19639cddb10SJoshua M. Clulow * Ignore events other than degrade. 19739cddb10SJoshua M. Clulow */ 19839cddb10SJoshua M. Clulow if (strcmp(ldi_ev_get_type(ecookie), LDI_EV_DEGRADE) != 0) 19939cddb10SJoshua M. Clulow return; 20039cddb10SJoshua M. Clulow 20139cddb10SJoshua M. Clulow /* 20239cddb10SJoshua M. Clulow * Degrade events always succeed. Mark the vdev as degraded. 20339cddb10SJoshua M. Clulow * This status is purely informative for the user. 20439cddb10SJoshua M. Clulow */ 20539cddb10SJoshua M. Clulow (void) vdev_degrade(vd->vdev_spa, vd->vdev_guid, 0); 20639cddb10SJoshua M. Clulow } 20739cddb10SJoshua M. Clulow 20839cddb10SJoshua M. Clulow static ldi_ev_callback_t vdev_disk_dgrd_callb = { 20939cddb10SJoshua M. Clulow .cb_vers = LDI_EV_CB_VERS, 21039cddb10SJoshua M. Clulow .cb_notify = NULL, 21139cddb10SJoshua M. Clulow .cb_finalize = vdev_disk_dgrd_finalize 21239cddb10SJoshua M. Clulow }; 21339cddb10SJoshua M. Clulow 214dcba9f3fSGeorge Wilson static void 215dcba9f3fSGeorge Wilson vdev_disk_hold(vdev_t *vd) 216dcba9f3fSGeorge Wilson { 217dcba9f3fSGeorge Wilson ddi_devid_t devid; 218dcba9f3fSGeorge Wilson char *minor; 219dcba9f3fSGeorge Wilson 220dcba9f3fSGeorge Wilson ASSERT(spa_config_held(vd->vdev_spa, SCL_STATE, RW_WRITER)); 221dcba9f3fSGeorge Wilson 222dcba9f3fSGeorge Wilson /* 223dcba9f3fSGeorge Wilson * We must have a pathname, and it must be absolute. 224dcba9f3fSGeorge Wilson */ 225dcba9f3fSGeorge Wilson if (vd->vdev_path == NULL || vd->vdev_path[0] != '/') 226dcba9f3fSGeorge Wilson return; 227dcba9f3fSGeorge Wilson 228dcba9f3fSGeorge Wilson /* 229dcba9f3fSGeorge Wilson * Only prefetch path and devid info if the device has 230dcba9f3fSGeorge Wilson * never been opened. 231dcba9f3fSGeorge Wilson */ 232dcba9f3fSGeorge Wilson if (vd->vdev_tsd != NULL) 233dcba9f3fSGeorge Wilson return; 234dcba9f3fSGeorge Wilson 235dcba9f3fSGeorge Wilson if (vd->vdev_wholedisk == -1ULL) { 236dcba9f3fSGeorge Wilson size_t len = strlen(vd->vdev_path) + 3; 237dcba9f3fSGeorge Wilson char *buf = kmem_alloc(len, KM_SLEEP); 238dcba9f3fSGeorge Wilson 239dcba9f3fSGeorge Wilson (void) snprintf(buf, len, "%ss0", vd->vdev_path); 240dcba9f3fSGeorge Wilson 241dcba9f3fSGeorge Wilson (void) ldi_vp_from_name(buf, &vd->vdev_name_vp); 242dcba9f3fSGeorge Wilson kmem_free(buf, len); 243dcba9f3fSGeorge Wilson } 244dcba9f3fSGeorge Wilson 245dcba9f3fSGeorge Wilson if (vd->vdev_name_vp == NULL) 246dcba9f3fSGeorge Wilson (void) ldi_vp_from_name(vd->vdev_path, &vd->vdev_name_vp); 247dcba9f3fSGeorge Wilson 248dcba9f3fSGeorge Wilson if (vd->vdev_devid != NULL && 249dcba9f3fSGeorge Wilson ddi_devid_str_decode(vd->vdev_devid, &devid, &minor) == 0) { 250dcba9f3fSGeorge Wilson (void) ldi_vp_from_devid(devid, minor, &vd->vdev_devid_vp); 251dcba9f3fSGeorge Wilson ddi_devid_str_free(minor); 252dcba9f3fSGeorge Wilson ddi_devid_free(devid); 253dcba9f3fSGeorge Wilson } 254dcba9f3fSGeorge Wilson } 255dcba9f3fSGeorge Wilson 256dcba9f3fSGeorge Wilson static void 257dcba9f3fSGeorge Wilson vdev_disk_rele(vdev_t *vd) 258dcba9f3fSGeorge Wilson { 259dcba9f3fSGeorge Wilson ASSERT(spa_config_held(vd->vdev_spa, SCL_STATE, RW_WRITER)); 260dcba9f3fSGeorge Wilson 261dcba9f3fSGeorge Wilson if (vd->vdev_name_vp) { 262dcba9f3fSGeorge Wilson VN_RELE_ASYNC(vd->vdev_name_vp, 263dcba9f3fSGeorge Wilson dsl_pool_vnrele_taskq(vd->vdev_spa->spa_dsl_pool)); 264dcba9f3fSGeorge Wilson vd->vdev_name_vp = NULL; 265dcba9f3fSGeorge Wilson } 266dcba9f3fSGeorge Wilson if (vd->vdev_devid_vp) { 267dcba9f3fSGeorge Wilson VN_RELE_ASYNC(vd->vdev_devid_vp, 268dcba9f3fSGeorge Wilson dsl_pool_vnrele_taskq(vd->vdev_spa->spa_dsl_pool)); 269dcba9f3fSGeorge Wilson vd->vdev_devid_vp = NULL; 270dcba9f3fSGeorge Wilson } 271dcba9f3fSGeorge Wilson } 272dcba9f3fSGeorge Wilson 273a5b57771SDan McDonald /* 274a5b57771SDan McDonald * We want to be loud in DEBUG kernels when DKIOCGMEDIAINFOEXT fails, or when 275a5b57771SDan McDonald * even a fallback to DKIOCGMEDIAINFO fails. 276a5b57771SDan McDonald */ 277a5b57771SDan McDonald #ifdef DEBUG 278a5b57771SDan McDonald #define VDEV_DEBUG(...) cmn_err(CE_NOTE, __VA_ARGS__) 279a5b57771SDan McDonald #else 280a5b57771SDan McDonald #define VDEV_DEBUG(...) /* Nothing... */ 281a5b57771SDan McDonald #endif 282a5b57771SDan McDonald 283fa9e4066Sahrens static int 2844263d13fSGeorge Wilson vdev_disk_open(vdev_t *vd, uint64_t *psize, uint64_t *max_psize, 2854263d13fSGeorge Wilson uint64_t *ashift) 286fa9e4066Sahrens { 2878ad4d6ddSJeff Bonwick spa_t *spa = vd->vdev_spa; 28839cddb10SJoshua M. Clulow vdev_disk_t *dvd = vd->vdev_tsd; 28939cddb10SJoshua M. Clulow ldi_ev_cookie_t ecookie; 29039cddb10SJoshua M. Clulow vdev_disk_ldi_cb_t *lcb; 291a5b57771SDan McDonald union { 292a5b57771SDan McDonald struct dk_minfo_ext ude; 293a5b57771SDan McDonald struct dk_minfo ud; 294a5b57771SDan McDonald } dks; 295a5b57771SDan McDonald struct dk_minfo_ext *dkmext = &dks.ude; 296a5b57771SDan McDonald struct dk_minfo *dkm = &dks.ud; 297084fd14fSBrian Behlendorf int error, can_free; 298e14bb325SJeff Bonwick dev_t dev; 299e14bb325SJeff Bonwick int otyp; 300fb02ae02SGeorge Wilson boolean_t validate_devid = B_FALSE; 301a5b57771SDan McDonald uint64_t capacity = 0, blksz = 0, pbsize; 302fa9e4066Sahrens 303fa9e4066Sahrens /* 304fa9e4066Sahrens * We must have a pathname, and it must be absolute. 305fa9e4066Sahrens */ 306fa9e4066Sahrens if (vd->vdev_path == NULL || vd->vdev_path[0] != '/') { 307fa9e4066Sahrens vd->vdev_stat.vs_aux = VDEV_AUX_BAD_LABEL; 308be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 309fa9e4066Sahrens } 310fa9e4066Sahrens 311095bcd66SGeorge Wilson /* 312095bcd66SGeorge Wilson * Reopen the device if it's not currently open. Otherwise, 313095bcd66SGeorge Wilson * just update the physical size of the device. 314095bcd66SGeorge Wilson */ 31539cddb10SJoshua M. Clulow if (dvd != NULL) { 31639cddb10SJoshua M. Clulow if (dvd->vd_ldi_offline && dvd->vd_lh == NULL) { 31739cddb10SJoshua M. Clulow /* 31839cddb10SJoshua M. Clulow * If we are opening a device in its offline notify 31939cddb10SJoshua M. Clulow * context, the LDI handle was just closed. Clean 32039cddb10SJoshua M. Clulow * up the LDI event callbacks and free vd->vdev_tsd. 32139cddb10SJoshua M. Clulow */ 32239cddb10SJoshua M. Clulow vdev_disk_free(vd); 32339cddb10SJoshua M. Clulow } else { 32439cddb10SJoshua M. Clulow ASSERT(vd->vdev_reopening); 32539cddb10SJoshua M. Clulow goto skip_open; 32639cddb10SJoshua M. Clulow } 327095bcd66SGeorge Wilson } 328095bcd66SGeorge Wilson 32939cddb10SJoshua M. Clulow /* 33039cddb10SJoshua M. Clulow * Create vd->vdev_tsd. 33139cddb10SJoshua M. Clulow */ 33239cddb10SJoshua M. Clulow vdev_disk_alloc(vd); 33339cddb10SJoshua M. Clulow dvd = vd->vdev_tsd; 334fa9e4066Sahrens 3356fe4f300SPavel Zakharov /* 3366fe4f300SPavel Zakharov * Allow bypassing the devid. 3376fe4f300SPavel Zakharov */ 3386fe4f300SPavel Zakharov if (vd->vdev_devid != NULL && vdev_disk_bypass_devid) { 3396fe4f300SPavel Zakharov vdev_dbgmsg(vd, "vdev_disk_open, devid %s bypassed", 3406fe4f300SPavel Zakharov vd->vdev_devid); 3416fe4f300SPavel Zakharov spa_strfree(vd->vdev_devid); 3426fe4f300SPavel Zakharov vd->vdev_devid = NULL; 3436fe4f300SPavel Zakharov } 3446fe4f300SPavel Zakharov 345fa9e4066Sahrens /* 346fa9e4066Sahrens * When opening a disk device, we want to preserve the user's original 347fa9e4066Sahrens * intent. We always want to open the device by the path the user gave 3481724dc7bSJoshua M. Clulow * us, even if it is one of multiple paths to the same device. But we 349fa9e4066Sahrens * also want to be able to survive disks being removed/recabled. 350fa9e4066Sahrens * Therefore the sequence of opening devices is: 351fa9e4066Sahrens * 352afefbcddSeschrock * 1. Try opening the device by path. For legacy pools without the 353afefbcddSeschrock * 'whole_disk' property, attempt to fix the path by appending 's0'. 354fa9e4066Sahrens * 355fa9e4066Sahrens * 2. If the devid of the device matches the stored value, return 356fa9e4066Sahrens * success. 357fa9e4066Sahrens * 358fa9e4066Sahrens * 3. Otherwise, the device may have moved. Try opening the device 359fa9e4066Sahrens * by the devid instead. 360fa9e4066Sahrens */ 361fa9e4066Sahrens if (vd->vdev_devid != NULL) { 362fa9e4066Sahrens if (ddi_devid_str_decode(vd->vdev_devid, &dvd->vd_devid, 363fa9e4066Sahrens &dvd->vd_minor) != 0) { 364fa9e4066Sahrens vd->vdev_stat.vs_aux = VDEV_AUX_BAD_LABEL; 3653ee8c80cSPavel Zakharov vdev_dbgmsg(vd, "vdev_disk_open: invalid " 3663ee8c80cSPavel Zakharov "vdev_devid '%s'", vd->vdev_devid); 367be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 368fa9e4066Sahrens } 369fa9e4066Sahrens } 370fa9e4066Sahrens 371fa9e4066Sahrens error = EINVAL; /* presume failure */ 372fa9e4066Sahrens 373095bcd66SGeorge Wilson if (vd->vdev_path != NULL) { 374fa9e4066Sahrens 375afefbcddSeschrock if (vd->vdev_wholedisk == -1ULL) { 376afefbcddSeschrock size_t len = strlen(vd->vdev_path) + 3; 377afefbcddSeschrock char *buf = kmem_alloc(len, KM_SLEEP); 378afefbcddSeschrock 379afefbcddSeschrock (void) snprintf(buf, len, "%ss0", vd->vdev_path); 380afefbcddSeschrock 38139cddb10SJoshua M. Clulow error = ldi_open_by_name(buf, spa_mode(spa), kcred, 38239cddb10SJoshua M. Clulow &dvd->vd_lh, zfs_li); 38339cddb10SJoshua M. Clulow if (error == 0) { 384afefbcddSeschrock spa_strfree(vd->vdev_path); 385afefbcddSeschrock vd->vdev_path = buf; 386afefbcddSeschrock vd->vdev_wholedisk = 1ULL; 387afefbcddSeschrock } else { 388afefbcddSeschrock kmem_free(buf, len); 389afefbcddSeschrock } 390afefbcddSeschrock } 391fa9e4066Sahrens 39239cddb10SJoshua M. Clulow /* 39339cddb10SJoshua M. Clulow * If we have not yet opened the device, try to open it by the 39439cddb10SJoshua M. Clulow * specified path. 39539cddb10SJoshua M. Clulow */ 39639cddb10SJoshua M. Clulow if (error != 0) { 39739cddb10SJoshua M. Clulow error = ldi_open_by_name(vd->vdev_path, spa_mode(spa), 39839cddb10SJoshua M. Clulow kcred, &dvd->vd_lh, zfs_li); 39939cddb10SJoshua M. Clulow } 400fa9e4066Sahrens 401fa9e4066Sahrens /* 402fa9e4066Sahrens * Compare the devid to the stored value. 403fa9e4066Sahrens */ 4046af23589SJoshua M. Clulow if (error == 0 && vd->vdev_devid != NULL) { 4056af23589SJoshua M. Clulow ddi_devid_t devid = NULL; 4066af23589SJoshua M. Clulow 4076af23589SJoshua M. Clulow if (ldi_get_devid(dvd->vd_lh, &devid) != 0) { 4086af23589SJoshua M. Clulow /* 4096af23589SJoshua M. Clulow * We expected a devid on this device but it no 4106af23589SJoshua M. Clulow * longer appears to have one. The validation 4116af23589SJoshua M. Clulow * step may need to remove it from the 4126af23589SJoshua M. Clulow * configuration. 4136af23589SJoshua M. Clulow */ 4146af23589SJoshua M. Clulow validate_devid = B_TRUE; 4156af23589SJoshua M. Clulow 4166af23589SJoshua M. Clulow } else if (ddi_devid_compare(devid, dvd->vd_devid) != 4176af23589SJoshua M. Clulow 0) { 4186fe4f300SPavel Zakharov /* 4196fe4f300SPavel Zakharov * A mismatch here is unexpected, log it. 4206fe4f300SPavel Zakharov */ 4216fe4f300SPavel Zakharov char *devid_str = ddi_devid_str_encode(devid, 4226fe4f300SPavel Zakharov dvd->vd_minor); 4236fe4f300SPavel Zakharov vdev_dbgmsg(vd, "vdev_disk_open: devid " 4246fe4f300SPavel Zakharov "mismatch: %s != %s", vd->vdev_devid, 4256fe4f300SPavel Zakharov devid_str); 4266fe4f300SPavel Zakharov cmn_err(CE_NOTE, "vdev_disk_open %s: devid " 4276fe4f300SPavel Zakharov "mismatch: %s != %s", vd->vdev_path, 4286fe4f300SPavel Zakharov vd->vdev_devid, devid_str); 4296fe4f300SPavel Zakharov ddi_devid_str_free(devid_str); 4306fe4f300SPavel Zakharov 431be6fd75aSMatthew Ahrens error = SET_ERROR(EINVAL); 4328ad4d6ddSJeff Bonwick (void) ldi_close(dvd->vd_lh, spa_mode(spa), 4338ad4d6ddSJeff Bonwick kcred); 434fa9e4066Sahrens dvd->vd_lh = NULL; 435fa9e4066Sahrens } 4366af23589SJoshua M. Clulow 4376af23589SJoshua M. Clulow if (devid != NULL) { 4386af23589SJoshua M. Clulow ddi_devid_free(devid); 4396af23589SJoshua M. Clulow } 440fa9e4066Sahrens } 441afefbcddSeschrock 442afefbcddSeschrock /* 443afefbcddSeschrock * If we succeeded in opening the device, but 'vdev_wholedisk' 444afefbcddSeschrock * is not yet set, then this must be a slice. 445afefbcddSeschrock */ 446afefbcddSeschrock if (error == 0 && vd->vdev_wholedisk == -1ULL) 447afefbcddSeschrock vd->vdev_wholedisk = 0; 448fa9e4066Sahrens } 449fa9e4066Sahrens 450fa9e4066Sahrens /* 451fa9e4066Sahrens * If we were unable to open by path, or the devid check fails, open by 452fa9e4066Sahrens * devid instead. 453fa9e4066Sahrens */ 454fb02ae02SGeorge Wilson if (error != 0 && vd->vdev_devid != NULL) { 455fa9e4066Sahrens error = ldi_open_by_devid(dvd->vd_devid, dvd->vd_minor, 4568ad4d6ddSJeff Bonwick spa_mode(spa), kcred, &dvd->vd_lh, zfs_li); 4576fe4f300SPavel Zakharov if (error != 0) { 4586fe4f300SPavel Zakharov vdev_dbgmsg(vd, "Failed to open by devid (%s)", 4596fe4f300SPavel Zakharov vd->vdev_devid); 4606fe4f300SPavel Zakharov } 461fb02ae02SGeorge Wilson } 462fa9e4066Sahrens 4633d7072f8Seschrock /* 4643d7072f8Seschrock * If all else fails, then try opening by physical path (if available) 4653d7072f8Seschrock * or the logical path (if we failed due to the devid check). While not 4663d7072f8Seschrock * as reliable as the devid, this will give us something, and the higher 4673d7072f8Seschrock * level vdev validation will prevent us from opening the wrong device. 4683d7072f8Seschrock */ 4696af23589SJoshua M. Clulow if (error != 0) { 4706af23589SJoshua M. Clulow validate_devid = B_TRUE; 471fb02ae02SGeorge Wilson 4723d7072f8Seschrock if (vd->vdev_physpath != NULL && 4736af23589SJoshua M. Clulow (dev = ddi_pathname_to_dev_t(vd->vdev_physpath)) != NODEV) { 4748ad4d6ddSJeff Bonwick error = ldi_open_by_dev(&dev, OTYP_BLK, spa_mode(spa), 4753d7072f8Seschrock kcred, &dvd->vd_lh, zfs_li); 4766af23589SJoshua M. Clulow } 4773d7072f8Seschrock 4783d7072f8Seschrock /* 4793d7072f8Seschrock * Note that we don't support the legacy auto-wholedisk support 4803d7072f8Seschrock * as above. This hasn't been used in a very long time and we 4813d7072f8Seschrock * don't need to propagate its oddities to this edge condition. 4823d7072f8Seschrock */ 4836af23589SJoshua M. Clulow if (error != 0 && vd->vdev_path != NULL) { 4848ad4d6ddSJeff Bonwick error = ldi_open_by_name(vd->vdev_path, spa_mode(spa), 4858ad4d6ddSJeff Bonwick kcred, &dvd->vd_lh, zfs_li); 4866af23589SJoshua M. Clulow } 4873d7072f8Seschrock } 4883d7072f8Seschrock 4896af23589SJoshua M. Clulow if (error != 0) { 490fa9e4066Sahrens vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED; 4913ee8c80cSPavel Zakharov vdev_dbgmsg(vd, "vdev_disk_open: failed to open [error=%d]", 4923ee8c80cSPavel Zakharov error); 493fa9e4066Sahrens return (error); 494e14bb325SJeff Bonwick } 495fa9e4066Sahrens 496fb02ae02SGeorge Wilson /* 497fb02ae02SGeorge Wilson * Now that the device has been successfully opened, update the devid 498fb02ae02SGeorge Wilson * if necessary. 499fb02ae02SGeorge Wilson */ 5006af23589SJoshua M. Clulow if (validate_devid) { 5016af23589SJoshua M. Clulow ddi_devid_t devid = NULL; 5026af23589SJoshua M. Clulow char *minorname = NULL; 5036af23589SJoshua M. Clulow char *vd_devid = NULL; 5046af23589SJoshua M. Clulow boolean_t remove = B_FALSE, update = B_FALSE; 5056af23589SJoshua M. Clulow 5066af23589SJoshua M. Clulow /* 5076af23589SJoshua M. Clulow * Get the current devid and minor name for the device we 5086af23589SJoshua M. Clulow * opened. 5096af23589SJoshua M. Clulow */ 5106af23589SJoshua M. Clulow if (ldi_get_devid(dvd->vd_lh, &devid) != 0 || 5116af23589SJoshua M. Clulow ldi_get_minor_name(dvd->vd_lh, &minorname) != 0) { 5126af23589SJoshua M. Clulow /* 5136af23589SJoshua M. Clulow * If we are unable to get the devid or the minor name 5146af23589SJoshua M. Clulow * for the device, we need to remove them from the 5156af23589SJoshua M. Clulow * configuration to prevent potential inconsistencies. 5166af23589SJoshua M. Clulow */ 5176af23589SJoshua M. Clulow if (dvd->vd_minor != NULL || dvd->vd_devid != NULL || 5186af23589SJoshua M. Clulow vd->vdev_devid != NULL) { 5196af23589SJoshua M. Clulow /* 5206af23589SJoshua M. Clulow * We only need to remove the devid if one 5216af23589SJoshua M. Clulow * exists. 5226af23589SJoshua M. Clulow */ 5236af23589SJoshua M. Clulow remove = B_TRUE; 5246af23589SJoshua M. Clulow } 525fb02ae02SGeorge Wilson 5266af23589SJoshua M. Clulow } else if (dvd->vd_devid == NULL || dvd->vd_minor == NULL) { 5276af23589SJoshua M. Clulow /* 5286af23589SJoshua M. Clulow * There was previously no devid at all so we need to 5296af23589SJoshua M. Clulow * add one. 5306af23589SJoshua M. Clulow */ 5316af23589SJoshua M. Clulow update = B_TRUE; 5326af23589SJoshua M. Clulow 5336af23589SJoshua M. Clulow } else if (ddi_devid_compare(devid, dvd->vd_devid) != 0 || 5346af23589SJoshua M. Clulow strcmp(minorname, dvd->vd_minor) != 0) { 5356af23589SJoshua M. Clulow /* 5366af23589SJoshua M. Clulow * The devid or minor name on file does not match the 5376af23589SJoshua M. Clulow * one from the opened device. 5386af23589SJoshua M. Clulow */ 5396af23589SJoshua M. Clulow update = B_TRUE; 5406af23589SJoshua M. Clulow } 5416af23589SJoshua M. Clulow 5426af23589SJoshua M. Clulow if (update) { 5436af23589SJoshua M. Clulow /* 5446af23589SJoshua M. Clulow * Render the new devid and minor name as a string for 5456af23589SJoshua M. Clulow * logging and to store in the vdev configuration. 5466af23589SJoshua M. Clulow */ 5476af23589SJoshua M. Clulow vd_devid = ddi_devid_str_encode(devid, minorname); 5486af23589SJoshua M. Clulow } 5496af23589SJoshua M. Clulow 5506af23589SJoshua M. Clulow if (update || remove) { 5513ee8c80cSPavel Zakharov vdev_dbgmsg(vd, "vdev_disk_open: update devid from " 5526af23589SJoshua M. Clulow "'%s' to '%s'", 5536af23589SJoshua M. Clulow vd->vdev_devid != NULL ? vd->vdev_devid : "<none>", 5546af23589SJoshua M. Clulow vd_devid != NULL ? vd_devid : "<none>"); 5556fe4f300SPavel Zakharov cmn_err(CE_NOTE, "vdev_disk_open %s: update devid " 5566af23589SJoshua M. Clulow "from '%s' to '%s'", 5576af23589SJoshua M. Clulow vd->vdev_path != NULL ? vd->vdev_path : "?", 5586af23589SJoshua M. Clulow vd->vdev_devid != NULL ? vd->vdev_devid : "<none>", 5596af23589SJoshua M. Clulow vd_devid != NULL ? vd_devid : "<none>"); 5606af23589SJoshua M. Clulow 5616af23589SJoshua M. Clulow /* 5626af23589SJoshua M. Clulow * Remove and free any existing values. 5636af23589SJoshua M. Clulow */ 5646af23589SJoshua M. Clulow if (dvd->vd_minor != NULL) { 5656af23589SJoshua M. Clulow ddi_devid_str_free(dvd->vd_minor); 5666af23589SJoshua M. Clulow dvd->vd_minor = NULL; 5676af23589SJoshua M. Clulow } 5686af23589SJoshua M. Clulow if (dvd->vd_devid != NULL) { 5696af23589SJoshua M. Clulow ddi_devid_free(dvd->vd_devid); 5706af23589SJoshua M. Clulow dvd->vd_devid = NULL; 5716af23589SJoshua M. Clulow } 5726af23589SJoshua M. Clulow if (vd->vdev_devid != NULL) { 5736af23589SJoshua M. Clulow spa_strfree(vd->vdev_devid); 5746af23589SJoshua M. Clulow vd->vdev_devid = NULL; 5756af23589SJoshua M. Clulow } 5766af23589SJoshua M. Clulow } 5776af23589SJoshua M. Clulow 5786af23589SJoshua M. Clulow if (update) { 5796af23589SJoshua M. Clulow /* 5806af23589SJoshua M. Clulow * Install the new values. 5816af23589SJoshua M. Clulow */ 5826af23589SJoshua M. Clulow vd->vdev_devid = vd_devid; 5836af23589SJoshua M. Clulow dvd->vd_minor = minorname; 5846af23589SJoshua M. Clulow dvd->vd_devid = devid; 5856af23589SJoshua M. Clulow 5866af23589SJoshua M. Clulow } else { 5876af23589SJoshua M. Clulow if (devid != NULL) { 5886af23589SJoshua M. Clulow ddi_devid_free(devid); 5896af23589SJoshua M. Clulow } 5906af23589SJoshua M. Clulow if (minorname != NULL) { 5916af23589SJoshua M. Clulow kmem_free(minorname, strlen(minorname) + 1); 5926af23589SJoshua M. Clulow } 593fb02ae02SGeorge Wilson } 594fb02ae02SGeorge Wilson } 595fb02ae02SGeorge Wilson 5963d7072f8Seschrock /* 5973d7072f8Seschrock * Once a device is opened, verify that the physical device path (if 5983d7072f8Seschrock * available) is up to date. 5993d7072f8Seschrock */ 6003d7072f8Seschrock if (ldi_get_dev(dvd->vd_lh, &dev) == 0 && 6013d7072f8Seschrock ldi_get_otyp(dvd->vd_lh, &otyp) == 0) { 6020a4e9518Sgw char *physpath, *minorname; 6030a4e9518Sgw 6043d7072f8Seschrock physpath = kmem_alloc(MAXPATHLEN, KM_SLEEP); 6053d7072f8Seschrock minorname = NULL; 6063d7072f8Seschrock if (ddi_dev_pathname(dev, otyp, physpath) == 0 && 6073d7072f8Seschrock ldi_get_minor_name(dvd->vd_lh, &minorname) == 0 && 6083d7072f8Seschrock (vd->vdev_physpath == NULL || 6093d7072f8Seschrock strcmp(vd->vdev_physpath, physpath) != 0)) { 6103d7072f8Seschrock if (vd->vdev_physpath) 6113d7072f8Seschrock spa_strfree(vd->vdev_physpath); 6123d7072f8Seschrock (void) strlcat(physpath, ":", MAXPATHLEN); 6133d7072f8Seschrock (void) strlcat(physpath, minorname, MAXPATHLEN); 6143d7072f8Seschrock vd->vdev_physpath = spa_strdup(physpath); 6153d7072f8Seschrock } 6163d7072f8Seschrock if (minorname) 6173d7072f8Seschrock kmem_free(minorname, strlen(minorname) + 1); 6183d7072f8Seschrock kmem_free(physpath, MAXPATHLEN); 6193d7072f8Seschrock } 6203d7072f8Seschrock 62139cddb10SJoshua M. Clulow /* 62239cddb10SJoshua M. Clulow * Register callbacks for the LDI offline event. 62339cddb10SJoshua M. Clulow */ 62439cddb10SJoshua M. Clulow if (ldi_ev_get_cookie(dvd->vd_lh, LDI_EV_OFFLINE, &ecookie) == 62539cddb10SJoshua M. Clulow LDI_EV_SUCCESS) { 62639cddb10SJoshua M. Clulow lcb = kmem_zalloc(sizeof (vdev_disk_ldi_cb_t), KM_SLEEP); 62739cddb10SJoshua M. Clulow list_insert_tail(&dvd->vd_ldi_cbs, lcb); 62839cddb10SJoshua M. Clulow (void) ldi_ev_register_callbacks(dvd->vd_lh, ecookie, 62939cddb10SJoshua M. Clulow &vdev_disk_off_callb, (void *) vd, &lcb->lcb_id); 63039cddb10SJoshua M. Clulow } 63139cddb10SJoshua M. Clulow 63239cddb10SJoshua M. Clulow /* 63339cddb10SJoshua M. Clulow * Register callbacks for the LDI degrade event. 63439cddb10SJoshua M. Clulow */ 63539cddb10SJoshua M. Clulow if (ldi_ev_get_cookie(dvd->vd_lh, LDI_EV_DEGRADE, &ecookie) == 63639cddb10SJoshua M. Clulow LDI_EV_SUCCESS) { 63739cddb10SJoshua M. Clulow lcb = kmem_zalloc(sizeof (vdev_disk_ldi_cb_t), KM_SLEEP); 63839cddb10SJoshua M. Clulow list_insert_tail(&dvd->vd_ldi_cbs, lcb); 63939cddb10SJoshua M. Clulow (void) ldi_ev_register_callbacks(dvd->vd_lh, ecookie, 64039cddb10SJoshua M. Clulow &vdev_disk_dgrd_callb, (void *) vd, &lcb->lcb_id); 64139cddb10SJoshua M. Clulow } 642084fd14fSBrian Behlendorf 643095bcd66SGeorge Wilson skip_open: 644fa9e4066Sahrens /* 645fa9e4066Sahrens * Determine the actual size of the device. 646fa9e4066Sahrens */ 647fa9e4066Sahrens if (ldi_get_size(dvd->vd_lh, psize) != 0) { 648fa9e4066Sahrens vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED; 6493ee8c80cSPavel Zakharov vdev_dbgmsg(vd, "vdev_disk_open: failed to get size"); 650be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 651fa9e4066Sahrens } 652fa9e4066Sahrens 653a5b57771SDan McDonald *max_psize = *psize; 654a5b57771SDan McDonald 655ecc2d604Sbonwick /* 656ecc2d604Sbonwick * Determine the device's minimum transfer size. 657ecc2d604Sbonwick * If the ioctl isn't supported, assume DEV_BSIZE. 658ecc2d604Sbonwick */ 659a5b57771SDan McDonald if ((error = ldi_ioctl(dvd->vd_lh, DKIOCGMEDIAINFOEXT, 660a5b57771SDan McDonald (intptr_t)dkmext, FKIOCTL, kcred, NULL)) == 0) { 661a5b57771SDan McDonald capacity = dkmext->dki_capacity - 1; 662a5b57771SDan McDonald blksz = dkmext->dki_lbsize; 663a5b57771SDan McDonald pbsize = dkmext->dki_pbsize; 664a5b57771SDan McDonald } else if ((error = ldi_ioctl(dvd->vd_lh, DKIOCGMEDIAINFO, 665a5b57771SDan McDonald (intptr_t)dkm, FKIOCTL, kcred, NULL)) == 0) { 666a5b57771SDan McDonald VDEV_DEBUG( 667a5b57771SDan McDonald "vdev_disk_open(\"%s\"): fallback to DKIOCGMEDIAINFO\n", 668a5b57771SDan McDonald vd->vdev_path); 669a5b57771SDan McDonald capacity = dkm->dki_capacity - 1; 670a5b57771SDan McDonald blksz = dkm->dki_lbsize; 671a5b57771SDan McDonald pbsize = blksz; 672a5b57771SDan McDonald } else { 673a5b57771SDan McDonald VDEV_DEBUG("vdev_disk_open(\"%s\"): " 674a5b57771SDan McDonald "both DKIOCGMEDIAINFO{,EXT} calls failed, %d\n", 675a5b57771SDan McDonald vd->vdev_path, error); 676a5b57771SDan McDonald pbsize = DEV_BSIZE; 677a5b57771SDan McDonald } 678bef6b7d2Swebaker 679bf16b11eSMatthew Ahrens *ashift = highbit64(MAX(pbsize, SPA_MINBLOCKSIZE)) - 1; 680bef6b7d2Swebaker 6814263d13fSGeorge Wilson if (vd->vdev_wholedisk == 1) { 6824263d13fSGeorge Wilson int wce = 1; 6834263d13fSGeorge Wilson 684a5b57771SDan McDonald if (error == 0) { 685a5b57771SDan McDonald /* 686a5b57771SDan McDonald * If we have the capability to expand, we'd have 687a5b57771SDan McDonald * found out via success from DKIOCGMEDIAINFO{,EXT}. 688a5b57771SDan McDonald * Adjust max_psize upward accordingly since we know 689a5b57771SDan McDonald * we own the whole disk now. 690a5b57771SDan McDonald */ 691c39a2aaeSGeorge Wilson *max_psize = capacity * blksz; 692a5b57771SDan McDonald } 693a5b57771SDan McDonald 6944263d13fSGeorge Wilson /* 695a5b57771SDan McDonald * Since we own the whole disk, try to enable disk write 696a5b57771SDan McDonald * caching. We ignore errors because it's OK if we can't do it. 6974263d13fSGeorge Wilson */ 6984263d13fSGeorge Wilson (void) ldi_ioctl(dvd->vd_lh, DKIOCSETWCE, (intptr_t)&wce, 6994263d13fSGeorge Wilson FKIOCTL, kcred, NULL); 7004263d13fSGeorge Wilson } 7014263d13fSGeorge Wilson 702b468a217Seschrock /* 703b468a217Seschrock * Clear the nowritecache bit, so that on a vdev_reopen() we will 704b468a217Seschrock * try again. 705b468a217Seschrock */ 706b468a217Seschrock vd->vdev_nowritecache = B_FALSE; 707b468a217Seschrock 708084fd14fSBrian Behlendorf if (ldi_ioctl(dvd->vd_lh, DKIOC_CANFREE, (intptr_t)&can_free, FKIOCTL, 709084fd14fSBrian Behlendorf kcred, NULL) == 0 && can_free == 1) { 710084fd14fSBrian Behlendorf vd->vdev_has_trim = B_TRUE; 711084fd14fSBrian Behlendorf } else { 712084fd14fSBrian Behlendorf vd->vdev_has_trim = B_FALSE; 713084fd14fSBrian Behlendorf } 714084fd14fSBrian Behlendorf 715fb05b94aSJerry Jelinek if (zfs_no_trim == 1) 716fb05b94aSJerry Jelinek vd->vdev_has_trim = B_FALSE; 717fb05b94aSJerry Jelinek 718084fd14fSBrian Behlendorf /* Currently only supported for ZoL. */ 719084fd14fSBrian Behlendorf vd->vdev_has_securetrim = B_FALSE; 720084fd14fSBrian Behlendorf 72112a8814cSTom Caputi /* Inform the ZIO pipeline that we are non-rotational */ 72212a8814cSTom Caputi vd->vdev_nonrot = B_FALSE; 72312a8814cSTom Caputi if (ldi_prop_exists(dvd->vd_lh, DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, 72412a8814cSTom Caputi "device-solid-state")) { 72512a8814cSTom Caputi if (ldi_prop_get_int(dvd->vd_lh, 72612a8814cSTom Caputi LDI_DEV_T_ANY | DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, 72712a8814cSTom Caputi "device-solid-state", B_FALSE) != 0) 72812a8814cSTom Caputi vd->vdev_nonrot = B_TRUE; 72912a8814cSTom Caputi } 73012a8814cSTom Caputi 731fa9e4066Sahrens return (0); 732fa9e4066Sahrens } 733fa9e4066Sahrens 734fa9e4066Sahrens static void 735fa9e4066Sahrens vdev_disk_close(vdev_t *vd) 736fa9e4066Sahrens { 737fa9e4066Sahrens vdev_disk_t *dvd = vd->vdev_tsd; 738fa9e4066Sahrens 739095bcd66SGeorge Wilson if (vd->vdev_reopening || dvd == NULL) 740fa9e4066Sahrens return; 741fa9e4066Sahrens 74239cddb10SJoshua M. Clulow if (dvd->vd_minor != NULL) { 743fa9e4066Sahrens ddi_devid_str_free(dvd->vd_minor); 74439cddb10SJoshua M. Clulow dvd->vd_minor = NULL; 74539cddb10SJoshua M. Clulow } 746fa9e4066Sahrens 74739cddb10SJoshua M. Clulow if (dvd->vd_devid != NULL) { 748fa9e4066Sahrens ddi_devid_free(dvd->vd_devid); 74939cddb10SJoshua M. Clulow dvd->vd_devid = NULL; 75039cddb10SJoshua M. Clulow } 751fa9e4066Sahrens 75239cddb10SJoshua M. Clulow if (dvd->vd_lh != NULL) { 7538ad4d6ddSJeff Bonwick (void) ldi_close(dvd->vd_lh, spa_mode(vd->vdev_spa), kcred); 75439cddb10SJoshua M. Clulow dvd->vd_lh = NULL; 75539cddb10SJoshua M. Clulow } 756fa9e4066Sahrens 75798d1cbfeSGeorge Wilson vd->vdev_delayed_close = B_FALSE; 75839cddb10SJoshua M. Clulow /* 75939cddb10SJoshua M. Clulow * If we closed the LDI handle due to an offline notify from LDI, 76039cddb10SJoshua M. Clulow * don't free vd->vdev_tsd or unregister the callbacks here; 76139cddb10SJoshua M. Clulow * the offline finalize callback or a reopen will take care of it. 76239cddb10SJoshua M. Clulow */ 76339cddb10SJoshua M. Clulow if (dvd->vd_ldi_offline) 76439cddb10SJoshua M. Clulow return; 76539cddb10SJoshua M. Clulow 76639cddb10SJoshua M. Clulow vdev_disk_free(vd); 767fa9e4066Sahrens } 768fa9e4066Sahrens 769e7cbe64fSgw int 770810e43b2SBill Pijewski vdev_disk_physio(vdev_t *vd, caddr_t data, 771810e43b2SBill Pijewski size_t size, uint64_t offset, int flags, boolean_t isdump) 772810e43b2SBill Pijewski { 773810e43b2SBill Pijewski vdev_disk_t *dvd = vd->vdev_tsd; 774810e43b2SBill Pijewski 77539cddb10SJoshua M. Clulow /* 77639cddb10SJoshua M. Clulow * If the vdev is closed, it's likely in the REMOVED or FAULTED state. 77739cddb10SJoshua M. Clulow * Nothing to be done here but return failure. 77839cddb10SJoshua M. Clulow */ 77939cddb10SJoshua M. Clulow if (dvd == NULL || (dvd->vd_ldi_offline && dvd->vd_lh == NULL)) 78039cddb10SJoshua M. Clulow return (EIO); 78139cddb10SJoshua M. Clulow 782810e43b2SBill Pijewski ASSERT(vd->vdev_ops == &vdev_disk_ops); 783810e43b2SBill Pijewski 784810e43b2SBill Pijewski /* 785810e43b2SBill Pijewski * If in the context of an active crash dump, use the ldi_dump(9F) 786810e43b2SBill Pijewski * call instead of ldi_strategy(9F) as usual. 787810e43b2SBill Pijewski */ 788810e43b2SBill Pijewski if (isdump) { 789810e43b2SBill Pijewski ASSERT3P(dvd, !=, NULL); 790810e43b2SBill Pijewski return (ldi_dump(dvd->vd_lh, data, lbtodb(offset), 791810e43b2SBill Pijewski lbtodb(size))); 792810e43b2SBill Pijewski } 793810e43b2SBill Pijewski 794810e43b2SBill Pijewski return (vdev_disk_ldi_physio(dvd->vd_lh, data, size, offset, flags)); 795810e43b2SBill Pijewski } 796810e43b2SBill Pijewski 797810e43b2SBill Pijewski int 798810e43b2SBill Pijewski vdev_disk_ldi_physio(ldi_handle_t vd_lh, caddr_t data, 799810e43b2SBill Pijewski size_t size, uint64_t offset, int flags) 800e7cbe64fSgw { 801e7cbe64fSgw buf_t *bp; 802e7cbe64fSgw int error = 0; 803e7cbe64fSgw 804e7cbe64fSgw if (vd_lh == NULL) 805be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 806e7cbe64fSgw 807e7cbe64fSgw ASSERT(flags & B_READ || flags & B_WRITE); 808e7cbe64fSgw 809e7cbe64fSgw bp = getrbuf(KM_SLEEP); 810e7cbe64fSgw bp->b_flags = flags | B_BUSY | B_NOCACHE | B_FAILFAST; 811e7cbe64fSgw bp->b_bcount = size; 812e7cbe64fSgw bp->b_un.b_addr = (void *)data; 813e7cbe64fSgw bp->b_lblkno = lbtodb(offset); 814e7cbe64fSgw bp->b_bufsize = size; 815e7cbe64fSgw 816e7cbe64fSgw error = ldi_strategy(vd_lh, bp); 817e7cbe64fSgw ASSERT(error == 0); 818e7cbe64fSgw if ((error = biowait(bp)) == 0 && bp->b_resid != 0) 819be6fd75aSMatthew Ahrens error = SET_ERROR(EIO); 820e7cbe64fSgw freerbuf(bp); 821e7cbe64fSgw 822e7cbe64fSgw return (error); 823e7cbe64fSgw } 824e7cbe64fSgw 825c62757b2SToomas Soome static int 826fa9e4066Sahrens vdev_disk_io_intr(buf_t *bp) 827fa9e4066Sahrens { 82831d7e8faSGeorge Wilson vdev_buf_t *vb = (vdev_buf_t *)bp; 82931d7e8faSGeorge Wilson zio_t *zio = vb->vb_io; 830fa9e4066Sahrens 83151ece835Seschrock /* 83251ece835Seschrock * The rest of the zio stack only deals with EIO, ECKSUM, and ENXIO. 83351ece835Seschrock * Rather than teach the rest of the stack about other error 83451ece835Seschrock * possibilities (EFAULT, etc), we normalize the error value here. 83551ece835Seschrock */ 83651ece835Seschrock zio->io_error = (geterror(bp) != 0 ? EIO : 0); 83751ece835Seschrock 83851ece835Seschrock if (zio->io_error == 0 && bp->b_resid != 0) 839be6fd75aSMatthew Ahrens zio->io_error = SET_ERROR(EIO); 840fa9e4066Sahrens 841770499e1SDan Kimmel if (zio->io_type == ZIO_TYPE_READ) { 842770499e1SDan Kimmel abd_return_buf_copy(zio->io_abd, bp->b_un.b_addr, zio->io_size); 843770499e1SDan Kimmel } else { 844770499e1SDan Kimmel abd_return_buf(zio->io_abd, bp->b_un.b_addr, zio->io_size); 845770499e1SDan Kimmel } 846770499e1SDan Kimmel 84731d7e8faSGeorge Wilson kmem_free(vb, sizeof (vdev_buf_t)); 848fa9e4066Sahrens 84997e81309SPrakash Surya zio_delay_interrupt(zio); 850c62757b2SToomas Soome return (0); 851fa9e4066Sahrens } 852fa9e4066Sahrens 853f4a72450SJeff Bonwick static void 854f4a72450SJeff Bonwick vdev_disk_ioctl_free(zio_t *zio) 855f4a72450SJeff Bonwick { 856f4a72450SJeff Bonwick kmem_free(zio->io_vsd, sizeof (struct dk_callback)); 857f4a72450SJeff Bonwick } 858f4a72450SJeff Bonwick 85922fe2c88SJonathan Adams static const zio_vsd_ops_t vdev_disk_vsd_ops = { 86022fe2c88SJonathan Adams vdev_disk_ioctl_free, 86122fe2c88SJonathan Adams zio_vsd_default_cksum_report 86222fe2c88SJonathan Adams }; 86322fe2c88SJonathan Adams 864fa9e4066Sahrens static void 865fa9e4066Sahrens vdev_disk_ioctl_done(void *zio_arg, int error) 866fa9e4066Sahrens { 867fa9e4066Sahrens zio_t *zio = zio_arg; 868fa9e4066Sahrens 869fa9e4066Sahrens zio->io_error = error; 870fa9e4066Sahrens 871e05725b1Sbonwick zio_interrupt(zio); 872fa9e4066Sahrens } 873fa9e4066Sahrens 874738f37bcSGeorge Wilson static void 875fa9e4066Sahrens vdev_disk_io_start(zio_t *zio) 876fa9e4066Sahrens { 877fa9e4066Sahrens vdev_t *vd = zio->io_vd; 878fa9e4066Sahrens vdev_disk_t *dvd = vd->vdev_tsd; 879084fd14fSBrian Behlendorf unsigned long trim_flags = 0; 88031d7e8faSGeorge Wilson vdev_buf_t *vb; 881e14bb325SJeff Bonwick struct dk_callback *dkc; 882fa9e4066Sahrens buf_t *bp; 883e14bb325SJeff Bonwick int error; 884fa9e4066Sahrens 88539cddb10SJoshua M. Clulow /* 88639cddb10SJoshua M. Clulow * If the vdev is closed, it's likely in the REMOVED or FAULTED state. 88739cddb10SJoshua M. Clulow * Nothing to be done here but return failure. 88839cddb10SJoshua M. Clulow */ 88939cddb10SJoshua M. Clulow if (dvd == NULL || (dvd->vd_ldi_offline && dvd->vd_lh == NULL)) { 89039cddb10SJoshua M. Clulow zio->io_error = ENXIO; 891738f37bcSGeorge Wilson zio_interrupt(zio); 892738f37bcSGeorge Wilson return; 89339cddb10SJoshua M. Clulow } 89439cddb10SJoshua M. Clulow 895084fd14fSBrian Behlendorf switch (zio->io_type) { 896084fd14fSBrian Behlendorf case ZIO_TYPE_IOCTL: 897fa9e4066Sahrens /* XXPOLICY */ 8980a4e9518Sgw if (!vdev_readable(vd)) { 899be6fd75aSMatthew Ahrens zio->io_error = SET_ERROR(ENXIO); 900738f37bcSGeorge Wilson zio_interrupt(zio); 901738f37bcSGeorge Wilson return; 902fa9e4066Sahrens } 903fa9e4066Sahrens 904fa9e4066Sahrens switch (zio->io_cmd) { 905fa9e4066Sahrens 906fa9e4066Sahrens case DKIOCFLUSHWRITECACHE: 907fa9e4066Sahrens 908a2eea2e1Sahrens if (zfs_nocacheflush) 909a2eea2e1Sahrens break; 910a2eea2e1Sahrens 911b468a217Seschrock if (vd->vdev_nowritecache) { 912be6fd75aSMatthew Ahrens zio->io_error = SET_ERROR(ENOTSUP); 913b468a217Seschrock break; 914b468a217Seschrock } 915b468a217Seschrock 916e14bb325SJeff Bonwick zio->io_vsd = dkc = kmem_alloc(sizeof (*dkc), KM_SLEEP); 91722fe2c88SJonathan Adams zio->io_vsd_ops = &vdev_disk_vsd_ops; 918e14bb325SJeff Bonwick 919e14bb325SJeff Bonwick dkc->dkc_callback = vdev_disk_ioctl_done; 920e14bb325SJeff Bonwick dkc->dkc_flag = FLUSH_VOLATILE; 921e14bb325SJeff Bonwick dkc->dkc_cookie = zio; 922fa9e4066Sahrens 923fa9e4066Sahrens error = ldi_ioctl(dvd->vd_lh, zio->io_cmd, 924e14bb325SJeff Bonwick (uintptr_t)dkc, FKIOCTL, kcred, NULL); 925fa9e4066Sahrens 926fa9e4066Sahrens if (error == 0) { 927fa9e4066Sahrens /* 928fa9e4066Sahrens * The ioctl will be done asychronously, 929fa9e4066Sahrens * and will call vdev_disk_ioctl_done() 930fa9e4066Sahrens * upon completion. 931fa9e4066Sahrens */ 932738f37bcSGeorge Wilson return; 933e05725b1Sbonwick } 934e05725b1Sbonwick 935fa9e4066Sahrens zio->io_error = error; 936b468a217Seschrock 937fa9e4066Sahrens break; 938fa9e4066Sahrens 939fa9e4066Sahrens default: 940be6fd75aSMatthew Ahrens zio->io_error = SET_ERROR(ENOTSUP); 941fa9e4066Sahrens } 942fa9e4066Sahrens 943738f37bcSGeorge Wilson zio_execute(zio); 944738f37bcSGeorge Wilson return; 945084fd14fSBrian Behlendorf 946084fd14fSBrian Behlendorf case ZIO_TYPE_TRIM: 947fb05b94aSJerry Jelinek if (zfs_no_trim == 1 || !vd->vdev_has_trim) { 948084fd14fSBrian Behlendorf zio->io_error = SET_ERROR(ENOTSUP); 949084fd14fSBrian Behlendorf zio_execute(zio); 950084fd14fSBrian Behlendorf return; 951084fd14fSBrian Behlendorf } 952084fd14fSBrian Behlendorf /* Currently only supported on ZoL. */ 953084fd14fSBrian Behlendorf ASSERT0(zio->io_trim_flags & ZIO_TRIM_SECURE); 954084fd14fSBrian Behlendorf 955084fd14fSBrian Behlendorf /* dkioc_free_list_t is already declared to hold one entry */ 956084fd14fSBrian Behlendorf dkioc_free_list_t dfl; 957084fd14fSBrian Behlendorf dfl.dfl_flags = 0; 958084fd14fSBrian Behlendorf dfl.dfl_num_exts = 1; 959d0562c10SJerry Jelinek dfl.dfl_offset = 0; 960084fd14fSBrian Behlendorf dfl.dfl_exts[0].dfle_start = zio->io_offset; 961084fd14fSBrian Behlendorf dfl.dfl_exts[0].dfle_length = zio->io_size; 962084fd14fSBrian Behlendorf 963084fd14fSBrian Behlendorf zio->io_error = ldi_ioctl(dvd->vd_lh, DKIOCFREE, 964084fd14fSBrian Behlendorf (uintptr_t)&dfl, FKIOCTL, kcred, NULL); 965084fd14fSBrian Behlendorf 966084fd14fSBrian Behlendorf if (zio->io_error == ENOTSUP || zio->io_error == ENOTTY) { 967084fd14fSBrian Behlendorf /* 968084fd14fSBrian Behlendorf * The device must have changed and now TRIM is 969084fd14fSBrian Behlendorf * no longer supported. 970084fd14fSBrian Behlendorf */ 971084fd14fSBrian Behlendorf vd->vdev_has_trim = B_FALSE; 972084fd14fSBrian Behlendorf } 973084fd14fSBrian Behlendorf 974084fd14fSBrian Behlendorf zio_interrupt(zio); 975084fd14fSBrian Behlendorf return; 976fa9e4066Sahrens } 977fa9e4066Sahrens 978f693d300SSteven Hartland ASSERT(zio->io_type == ZIO_TYPE_READ || zio->io_type == ZIO_TYPE_WRITE); 97997e81309SPrakash Surya zio->io_target_timestamp = zio_handle_io_delay(zio); 980f693d300SSteven Hartland 98131d7e8faSGeorge Wilson vb = kmem_alloc(sizeof (vdev_buf_t), KM_SLEEP); 982fa9e4066Sahrens 98331d7e8faSGeorge Wilson vb->vb_io = zio; 98431d7e8faSGeorge Wilson bp = &vb->vb_buf; 985fa9e4066Sahrens 986fa9e4066Sahrens bioinit(bp); 987e14bb325SJeff Bonwick bp->b_flags = B_BUSY | B_NOCACHE | 9888956713aSEric Schrock (zio->io_type == ZIO_TYPE_READ ? B_READ : B_WRITE); 9898956713aSEric Schrock if (!(zio->io_flags & (ZIO_FLAG_IO_RETRY | ZIO_FLAG_TRYHARD))) 9908956713aSEric Schrock bp->b_flags |= B_FAILFAST; 991fa9e4066Sahrens bp->b_bcount = zio->io_size; 992770499e1SDan Kimmel 993770499e1SDan Kimmel if (zio->io_type == ZIO_TYPE_READ) { 994770499e1SDan Kimmel bp->b_un.b_addr = 995770499e1SDan Kimmel abd_borrow_buf(zio->io_abd, zio->io_size); 996770499e1SDan Kimmel } else { 997770499e1SDan Kimmel bp->b_un.b_addr = 998770499e1SDan Kimmel abd_borrow_buf_copy(zio->io_abd, zio->io_size); 999770499e1SDan Kimmel } 1000770499e1SDan Kimmel 1001fa9e4066Sahrens bp->b_lblkno = lbtodb(zio->io_offset); 1002fa9e4066Sahrens bp->b_bufsize = zio->io_size; 1003c62757b2SToomas Soome bp->b_iodone = vdev_disk_io_intr; 1004fa9e4066Sahrens 1005fa88c70fSJerry Jelinek /* 1006fa88c70fSJerry Jelinek * In general we would expect ldi_strategy() to return non-zero only 1007fa88c70fSJerry Jelinek * because of programming errors, but we've also seen this fail shortly 1008fa88c70fSJerry Jelinek * after a disk dies. 1009fa88c70fSJerry Jelinek */ 1010fa88c70fSJerry Jelinek if (ldi_strategy(dvd->vd_lh, bp) != 0) { 1011fa88c70fSJerry Jelinek zio->io_error = ENXIO; 1012fa88c70fSJerry Jelinek zio_interrupt(zio); 1013fa88c70fSJerry Jelinek } 1014fa9e4066Sahrens } 1015fa9e4066Sahrens 1016e14bb325SJeff Bonwick static void 1017fa9e4066Sahrens vdev_disk_io_done(zio_t *zio) 1018fa9e4066Sahrens { 1019e14bb325SJeff Bonwick vdev_t *vd = zio->io_vd; 1020ea8dc4b6Seschrock 10213d7072f8Seschrock /* 10223d7072f8Seschrock * If the device returned EIO, then attempt a DKIOCSTATE ioctl to see if 10233d7072f8Seschrock * the device has been removed. If this is the case, then we trigger an 10240a4e9518Sgw * asynchronous removal of the device. Otherwise, probe the device and 10251f7ad2e1Sgw * make sure it's still accessible. 10263d7072f8Seschrock */ 10271d713200SEric Schrock if (zio->io_error == EIO && !vd->vdev_remove_wanted) { 10280a4e9518Sgw vdev_disk_t *dvd = vd->vdev_tsd; 1029e14bb325SJeff Bonwick int state = DKIO_NONE; 10300a4e9518Sgw 1031e14bb325SJeff Bonwick if (ldi_ioctl(dvd->vd_lh, DKIOCSTATE, (intptr_t)&state, 1032e14bb325SJeff Bonwick FKIOCTL, kcred, NULL) == 0 && state != DKIO_INSERTED) { 10331d713200SEric Schrock /* 10341d713200SEric Schrock * We post the resource as soon as possible, instead of 10351d713200SEric Schrock * when the async removal actually happens, because the 10361d713200SEric Schrock * DE is using this information to discard previous I/O 10371d713200SEric Schrock * errors. 10381d713200SEric Schrock */ 10391d713200SEric Schrock zfs_post_remove(zio->io_spa, vd); 10403d7072f8Seschrock vd->vdev_remove_wanted = B_TRUE; 10413d7072f8Seschrock spa_async_request(zio->io_spa, SPA_ASYNC_REMOVE); 104298d1cbfeSGeorge Wilson } else if (!vd->vdev_delayed_close) { 104398d1cbfeSGeorge Wilson vd->vdev_delayed_close = B_TRUE; 10443d7072f8Seschrock } 10453d7072f8Seschrock } 1046fa9e4066Sahrens } 1047fa9e4066Sahrens 1048fa9e4066Sahrens vdev_ops_t vdev_disk_ops = { 1049a3874b8bSToomas Soome .vdev_op_open = vdev_disk_open, 1050a3874b8bSToomas Soome .vdev_op_close = vdev_disk_close, 1051a3874b8bSToomas Soome .vdev_op_asize = vdev_default_asize, 1052a3874b8bSToomas Soome .vdev_op_io_start = vdev_disk_io_start, 1053a3874b8bSToomas Soome .vdev_op_io_done = vdev_disk_io_done, 1054a3874b8bSToomas Soome .vdev_op_state_change = NULL, 1055a3874b8bSToomas Soome .vdev_op_need_resilver = NULL, 1056a3874b8bSToomas Soome .vdev_op_hold = vdev_disk_hold, 1057a3874b8bSToomas Soome .vdev_op_rele = vdev_disk_rele, 1058a3874b8bSToomas Soome .vdev_op_remap = NULL, 1059a3874b8bSToomas Soome .vdev_op_xlate = vdev_default_xlate, 1060a3874b8bSToomas Soome .vdev_op_type = VDEV_TYPE_DISK, /* name of this vdev type */ 1061a3874b8bSToomas Soome .vdev_op_leaf = B_TRUE /* leaf vdev */ 1062fa9e4066Sahrens }; 1063e7cbe64fSgw 1064e7cbe64fSgw /* 1065051aabe6Staylor * Given the root disk device devid or pathname, read the label from 1066051aabe6Staylor * the device, and construct a configuration nvlist. 1067e7cbe64fSgw */ 1068f940fbb1SLin Ling int 1069f940fbb1SLin Ling vdev_disk_read_rootlabel(char *devpath, char *devid, nvlist_t **config) 1070e7cbe64fSgw { 1071e7cbe64fSgw ldi_handle_t vd_lh; 1072e7cbe64fSgw vdev_label_t *label; 1073e7cbe64fSgw uint64_t s, size; 1074e7cbe64fSgw int l; 1075051aabe6Staylor ddi_devid_t tmpdevid; 1076f4565e39SLin Ling int error = -1; 1077051aabe6Staylor char *minor_name; 1078e7cbe64fSgw 1079e7cbe64fSgw /* 1080e7cbe64fSgw * Read the device label and build the nvlist. 1081e7cbe64fSgw */ 1082f4565e39SLin Ling if (devid != NULL && ddi_devid_str_decode(devid, &tmpdevid, 1083051aabe6Staylor &minor_name) == 0) { 1084051aabe6Staylor error = ldi_open_by_devid(tmpdevid, minor_name, 10858ad4d6ddSJeff Bonwick FREAD, kcred, &vd_lh, zfs_li); 1086051aabe6Staylor ddi_devid_free(tmpdevid); 1087051aabe6Staylor ddi_devid_str_free(minor_name); 1088051aabe6Staylor } 1089051aabe6Staylor 1090f4565e39SLin Ling if (error && (error = ldi_open_by_name(devpath, FREAD, kcred, &vd_lh, 1091f4565e39SLin Ling zfs_li))) 1092f940fbb1SLin Ling return (error); 1093e7cbe64fSgw 1094bf82a41bSeschrock if (ldi_get_size(vd_lh, &s)) { 1095bf82a41bSeschrock (void) ldi_close(vd_lh, FREAD, kcred); 1096be6fd75aSMatthew Ahrens return (SET_ERROR(EIO)); 1097bf82a41bSeschrock } 1098e7cbe64fSgw 1099e7cbe64fSgw size = P2ALIGN_TYPED(s, sizeof (vdev_label_t), uint64_t); 1100e7cbe64fSgw label = kmem_alloc(sizeof (vdev_label_t), KM_SLEEP); 1101e7cbe64fSgw 110217f1e64aSEric Taylor *config = NULL; 1103e7cbe64fSgw for (l = 0; l < VDEV_LABELS; l++) { 1104e7cbe64fSgw uint64_t offset, state, txg = 0; 1105e7cbe64fSgw 1106e7cbe64fSgw /* read vdev label */ 1107e7cbe64fSgw offset = vdev_label_offset(size, l, 0); 1108810e43b2SBill Pijewski if (vdev_disk_ldi_physio(vd_lh, (caddr_t)label, 11092264ca7fSLin Ling VDEV_SKIP_SIZE + VDEV_PHYS_SIZE, offset, B_READ) != 0) 1110e7cbe64fSgw continue; 1111e7cbe64fSgw 1112e7cbe64fSgw if (nvlist_unpack(label->vl_vdev_phys.vp_nvlist, 1113f940fbb1SLin Ling sizeof (label->vl_vdev_phys.vp_nvlist), config, 0) != 0) { 1114f940fbb1SLin Ling *config = NULL; 1115e7cbe64fSgw continue; 1116e7cbe64fSgw } 1117e7cbe64fSgw 1118f940fbb1SLin Ling if (nvlist_lookup_uint64(*config, ZPOOL_CONFIG_POOL_STATE, 1119e7cbe64fSgw &state) != 0 || state >= POOL_STATE_DESTROYED) { 1120f940fbb1SLin Ling nvlist_free(*config); 1121f940fbb1SLin Ling *config = NULL; 1122e7cbe64fSgw continue; 1123e7cbe64fSgw } 1124e7cbe64fSgw 1125f940fbb1SLin Ling if (nvlist_lookup_uint64(*config, ZPOOL_CONFIG_POOL_TXG, 1126e7cbe64fSgw &txg) != 0 || txg == 0) { 1127f940fbb1SLin Ling nvlist_free(*config); 1128f940fbb1SLin Ling *config = NULL; 1129e7cbe64fSgw continue; 1130e7cbe64fSgw } 1131e7cbe64fSgw 1132e7cbe64fSgw break; 1133e7cbe64fSgw } 1134e7cbe64fSgw 1135e7cbe64fSgw kmem_free(label, sizeof (vdev_label_t)); 1136bf82a41bSeschrock (void) ldi_close(vd_lh, FREAD, kcred); 113717f1e64aSEric Taylor if (*config == NULL) 1138be6fd75aSMatthew Ahrens error = SET_ERROR(EIDRM); 1139bf82a41bSeschrock 1140f940fbb1SLin Ling return (error); 1141e7cbe64fSgw } 1142