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> 33*084fd14fSBrian 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 41f8fdf681SPrakash Surya /* 42f8fdf681SPrakash Surya * Tunable parameter for debugging or performance analysis. Setting this 43f8fdf681SPrakash Surya * will cause pool corruption on power loss if a volatile out-of-order 44f8fdf681SPrakash Surya * write cache is enabled. 45f8fdf681SPrakash Surya */ 46f8fdf681SPrakash Surya boolean_t zfs_nocacheflush = B_FALSE; 47f8fdf681SPrakash Surya 48fa9e4066Sahrens /* 49fa9e4066Sahrens * Virtual device vector for disks. 50fa9e4066Sahrens */ 51fa9e4066Sahrens 52fa9e4066Sahrens extern ldi_ident_t zfs_li; 53fa9e4066Sahrens 5439cddb10SJoshua M. Clulow static void vdev_disk_close(vdev_t *); 5539cddb10SJoshua M. Clulow 5639cddb10SJoshua M. Clulow typedef struct vdev_disk_ldi_cb { 5739cddb10SJoshua M. Clulow list_node_t lcb_next; 5839cddb10SJoshua M. Clulow ldi_callback_id_t lcb_id; 5939cddb10SJoshua M. Clulow } vdev_disk_ldi_cb_t; 6039cddb10SJoshua M. Clulow 616fe4f300SPavel Zakharov /* 626fe4f300SPavel Zakharov * Bypass the devid when opening a disk vdev. 636fe4f300SPavel Zakharov * There have been issues where the devids of several devices were shuffled, 646fe4f300SPavel Zakharov * causing pool open failures. Note, that this flag is intended to be used 656fe4f300SPavel Zakharov * for pool recovery only. 666fe4f300SPavel Zakharov * 676fe4f300SPavel Zakharov * Note that if a pool is imported with the devids bypassed, all its vdevs will 686fe4f300SPavel Zakharov * cease storing devid information permanently. In practice, the devid is rarely 696fe4f300SPavel Zakharov * useful as vdev paths do not tend to change unless the hardware is 706fe4f300SPavel Zakharov * reconfigured. That said, if the paths do change and a pool fails to open 716fe4f300SPavel Zakharov * automatically at boot, a simple zpool import should re-scan the paths and fix 726fe4f300SPavel Zakharov * the issue. 736fe4f300SPavel Zakharov */ 746fe4f300SPavel Zakharov boolean_t vdev_disk_bypass_devid = B_FALSE; 756fe4f300SPavel Zakharov 7639cddb10SJoshua M. Clulow static void 7739cddb10SJoshua M. Clulow vdev_disk_alloc(vdev_t *vd) 7839cddb10SJoshua M. Clulow { 7939cddb10SJoshua M. Clulow vdev_disk_t *dvd; 8039cddb10SJoshua M. Clulow 8139cddb10SJoshua M. Clulow dvd = vd->vdev_tsd = kmem_zalloc(sizeof (vdev_disk_t), KM_SLEEP); 8239cddb10SJoshua M. Clulow /* 8339cddb10SJoshua M. Clulow * Create the LDI event callback list. 8439cddb10SJoshua M. Clulow */ 8539cddb10SJoshua M. Clulow list_create(&dvd->vd_ldi_cbs, sizeof (vdev_disk_ldi_cb_t), 8639cddb10SJoshua M. Clulow offsetof(vdev_disk_ldi_cb_t, lcb_next)); 8739cddb10SJoshua M. Clulow } 8839cddb10SJoshua M. Clulow 8939cddb10SJoshua M. Clulow static void 9039cddb10SJoshua M. Clulow vdev_disk_free(vdev_t *vd) 9139cddb10SJoshua M. Clulow { 9239cddb10SJoshua M. Clulow vdev_disk_t *dvd = vd->vdev_tsd; 9339cddb10SJoshua M. Clulow vdev_disk_ldi_cb_t *lcb; 9439cddb10SJoshua M. Clulow 9539cddb10SJoshua M. Clulow if (dvd == NULL) 9639cddb10SJoshua M. Clulow return; 9739cddb10SJoshua M. Clulow 9839cddb10SJoshua M. Clulow /* 9939cddb10SJoshua M. Clulow * We have already closed the LDI handle. Clean up the LDI event 10039cddb10SJoshua M. Clulow * callbacks and free vd->vdev_tsd. 10139cddb10SJoshua M. Clulow */ 10239cddb10SJoshua M. Clulow while ((lcb = list_head(&dvd->vd_ldi_cbs)) != NULL) { 10339cddb10SJoshua M. Clulow list_remove(&dvd->vd_ldi_cbs, lcb); 10439cddb10SJoshua M. Clulow (void) ldi_ev_remove_callbacks(lcb->lcb_id); 10539cddb10SJoshua M. Clulow kmem_free(lcb, sizeof (vdev_disk_ldi_cb_t)); 10639cddb10SJoshua M. Clulow } 10739cddb10SJoshua M. Clulow list_destroy(&dvd->vd_ldi_cbs); 10839cddb10SJoshua M. Clulow kmem_free(dvd, sizeof (vdev_disk_t)); 10939cddb10SJoshua M. Clulow vd->vdev_tsd = NULL; 11039cddb10SJoshua M. Clulow } 11139cddb10SJoshua M. Clulow 11239cddb10SJoshua M. Clulow /* ARGSUSED */ 11339cddb10SJoshua M. Clulow static int 11439cddb10SJoshua M. Clulow vdev_disk_off_notify(ldi_handle_t lh, ldi_ev_cookie_t ecookie, void *arg, 11539cddb10SJoshua M. Clulow void *ev_data) 11639cddb10SJoshua M. Clulow { 11739cddb10SJoshua M. Clulow vdev_t *vd = (vdev_t *)arg; 11839cddb10SJoshua M. Clulow vdev_disk_t *dvd = vd->vdev_tsd; 11939cddb10SJoshua M. Clulow 12039cddb10SJoshua M. Clulow /* 12139cddb10SJoshua M. Clulow * Ignore events other than offline. 12239cddb10SJoshua M. Clulow */ 12339cddb10SJoshua M. Clulow if (strcmp(ldi_ev_get_type(ecookie), LDI_EV_OFFLINE) != 0) 12439cddb10SJoshua M. Clulow return (LDI_EV_SUCCESS); 12539cddb10SJoshua M. Clulow 12639cddb10SJoshua M. Clulow /* 12739cddb10SJoshua M. Clulow * All LDI handles must be closed for the state change to succeed, so 12839cddb10SJoshua M. Clulow * call on vdev_disk_close() to do this. 12939cddb10SJoshua M. Clulow * 13039cddb10SJoshua M. Clulow * We inform vdev_disk_close that it is being called from offline 13139cddb10SJoshua M. Clulow * notify context so it will defer cleanup of LDI event callbacks and 13239cddb10SJoshua M. Clulow * freeing of vd->vdev_tsd to the offline finalize or a reopen. 13339cddb10SJoshua M. Clulow */ 13439cddb10SJoshua M. Clulow dvd->vd_ldi_offline = B_TRUE; 13539cddb10SJoshua M. Clulow vdev_disk_close(vd); 13639cddb10SJoshua M. Clulow 13739cddb10SJoshua M. Clulow /* 13839cddb10SJoshua M. Clulow * Now that the device is closed, request that the spa_async_thread 13939cddb10SJoshua M. Clulow * mark the device as REMOVED and notify FMA of the removal. 14039cddb10SJoshua M. Clulow */ 14139cddb10SJoshua M. Clulow zfs_post_remove(vd->vdev_spa, vd); 14239cddb10SJoshua M. Clulow vd->vdev_remove_wanted = B_TRUE; 14339cddb10SJoshua M. Clulow spa_async_request(vd->vdev_spa, SPA_ASYNC_REMOVE); 14439cddb10SJoshua M. Clulow 14539cddb10SJoshua M. Clulow return (LDI_EV_SUCCESS); 14639cddb10SJoshua M. Clulow } 14739cddb10SJoshua M. Clulow 14839cddb10SJoshua M. Clulow /* ARGSUSED */ 14939cddb10SJoshua M. Clulow static void 15039cddb10SJoshua M. Clulow vdev_disk_off_finalize(ldi_handle_t lh, ldi_ev_cookie_t ecookie, 15139cddb10SJoshua M. Clulow int ldi_result, void *arg, void *ev_data) 15239cddb10SJoshua M. Clulow { 15339cddb10SJoshua M. Clulow vdev_t *vd = (vdev_t *)arg; 15439cddb10SJoshua M. Clulow 15539cddb10SJoshua M. Clulow /* 15639cddb10SJoshua M. Clulow * Ignore events other than offline. 15739cddb10SJoshua M. Clulow */ 15839cddb10SJoshua M. Clulow if (strcmp(ldi_ev_get_type(ecookie), LDI_EV_OFFLINE) != 0) 15939cddb10SJoshua M. Clulow return; 16039cddb10SJoshua M. Clulow 16139cddb10SJoshua M. Clulow /* 16239cddb10SJoshua M. Clulow * We have already closed the LDI handle in notify. 16339cddb10SJoshua M. Clulow * Clean up the LDI event callbacks and free vd->vdev_tsd. 16439cddb10SJoshua M. Clulow */ 16539cddb10SJoshua M. Clulow vdev_disk_free(vd); 16639cddb10SJoshua M. Clulow 16739cddb10SJoshua M. Clulow /* 16839cddb10SJoshua M. Clulow * Request that the vdev be reopened if the offline state change was 16939cddb10SJoshua M. Clulow * unsuccessful. 17039cddb10SJoshua M. Clulow */ 17139cddb10SJoshua M. Clulow if (ldi_result != LDI_EV_SUCCESS) { 17239cddb10SJoshua M. Clulow vd->vdev_probe_wanted = B_TRUE; 17339cddb10SJoshua M. Clulow spa_async_request(vd->vdev_spa, SPA_ASYNC_PROBE); 17439cddb10SJoshua M. Clulow } 17539cddb10SJoshua M. Clulow } 17639cddb10SJoshua M. Clulow 17739cddb10SJoshua M. Clulow static ldi_ev_callback_t vdev_disk_off_callb = { 17839cddb10SJoshua M. Clulow .cb_vers = LDI_EV_CB_VERS, 17939cddb10SJoshua M. Clulow .cb_notify = vdev_disk_off_notify, 18039cddb10SJoshua M. Clulow .cb_finalize = vdev_disk_off_finalize 18139cddb10SJoshua M. Clulow }; 18239cddb10SJoshua M. Clulow 18339cddb10SJoshua M. Clulow /* ARGSUSED */ 18439cddb10SJoshua M. Clulow static void 18539cddb10SJoshua M. Clulow vdev_disk_dgrd_finalize(ldi_handle_t lh, ldi_ev_cookie_t ecookie, 18639cddb10SJoshua M. Clulow int ldi_result, void *arg, void *ev_data) 18739cddb10SJoshua M. Clulow { 18839cddb10SJoshua M. Clulow vdev_t *vd = (vdev_t *)arg; 18939cddb10SJoshua M. Clulow 19039cddb10SJoshua M. Clulow /* 19139cddb10SJoshua M. Clulow * Ignore events other than degrade. 19239cddb10SJoshua M. Clulow */ 19339cddb10SJoshua M. Clulow if (strcmp(ldi_ev_get_type(ecookie), LDI_EV_DEGRADE) != 0) 19439cddb10SJoshua M. Clulow return; 19539cddb10SJoshua M. Clulow 19639cddb10SJoshua M. Clulow /* 19739cddb10SJoshua M. Clulow * Degrade events always succeed. Mark the vdev as degraded. 19839cddb10SJoshua M. Clulow * This status is purely informative for the user. 19939cddb10SJoshua M. Clulow */ 20039cddb10SJoshua M. Clulow (void) vdev_degrade(vd->vdev_spa, vd->vdev_guid, 0); 20139cddb10SJoshua M. Clulow } 20239cddb10SJoshua M. Clulow 20339cddb10SJoshua M. Clulow static ldi_ev_callback_t vdev_disk_dgrd_callb = { 20439cddb10SJoshua M. Clulow .cb_vers = LDI_EV_CB_VERS, 20539cddb10SJoshua M. Clulow .cb_notify = NULL, 20639cddb10SJoshua M. Clulow .cb_finalize = vdev_disk_dgrd_finalize 20739cddb10SJoshua M. Clulow }; 20839cddb10SJoshua M. Clulow 209dcba9f3fSGeorge Wilson static void 210dcba9f3fSGeorge Wilson vdev_disk_hold(vdev_t *vd) 211dcba9f3fSGeorge Wilson { 212dcba9f3fSGeorge Wilson ddi_devid_t devid; 213dcba9f3fSGeorge Wilson char *minor; 214dcba9f3fSGeorge Wilson 215dcba9f3fSGeorge Wilson ASSERT(spa_config_held(vd->vdev_spa, SCL_STATE, RW_WRITER)); 216dcba9f3fSGeorge Wilson 217dcba9f3fSGeorge Wilson /* 218dcba9f3fSGeorge Wilson * We must have a pathname, and it must be absolute. 219dcba9f3fSGeorge Wilson */ 220dcba9f3fSGeorge Wilson if (vd->vdev_path == NULL || vd->vdev_path[0] != '/') 221dcba9f3fSGeorge Wilson return; 222dcba9f3fSGeorge Wilson 223dcba9f3fSGeorge Wilson /* 224dcba9f3fSGeorge Wilson * Only prefetch path and devid info if the device has 225dcba9f3fSGeorge Wilson * never been opened. 226dcba9f3fSGeorge Wilson */ 227dcba9f3fSGeorge Wilson if (vd->vdev_tsd != NULL) 228dcba9f3fSGeorge Wilson return; 229dcba9f3fSGeorge Wilson 230dcba9f3fSGeorge Wilson if (vd->vdev_wholedisk == -1ULL) { 231dcba9f3fSGeorge Wilson size_t len = strlen(vd->vdev_path) + 3; 232dcba9f3fSGeorge Wilson char *buf = kmem_alloc(len, KM_SLEEP); 233dcba9f3fSGeorge Wilson 234dcba9f3fSGeorge Wilson (void) snprintf(buf, len, "%ss0", vd->vdev_path); 235dcba9f3fSGeorge Wilson 236dcba9f3fSGeorge Wilson (void) ldi_vp_from_name(buf, &vd->vdev_name_vp); 237dcba9f3fSGeorge Wilson kmem_free(buf, len); 238dcba9f3fSGeorge Wilson } 239dcba9f3fSGeorge Wilson 240dcba9f3fSGeorge Wilson if (vd->vdev_name_vp == NULL) 241dcba9f3fSGeorge Wilson (void) ldi_vp_from_name(vd->vdev_path, &vd->vdev_name_vp); 242dcba9f3fSGeorge Wilson 243dcba9f3fSGeorge Wilson if (vd->vdev_devid != NULL && 244dcba9f3fSGeorge Wilson ddi_devid_str_decode(vd->vdev_devid, &devid, &minor) == 0) { 245dcba9f3fSGeorge Wilson (void) ldi_vp_from_devid(devid, minor, &vd->vdev_devid_vp); 246dcba9f3fSGeorge Wilson ddi_devid_str_free(minor); 247dcba9f3fSGeorge Wilson ddi_devid_free(devid); 248dcba9f3fSGeorge Wilson } 249dcba9f3fSGeorge Wilson } 250dcba9f3fSGeorge Wilson 251dcba9f3fSGeorge Wilson static void 252dcba9f3fSGeorge Wilson vdev_disk_rele(vdev_t *vd) 253dcba9f3fSGeorge Wilson { 254dcba9f3fSGeorge Wilson ASSERT(spa_config_held(vd->vdev_spa, SCL_STATE, RW_WRITER)); 255dcba9f3fSGeorge Wilson 256dcba9f3fSGeorge Wilson if (vd->vdev_name_vp) { 257dcba9f3fSGeorge Wilson VN_RELE_ASYNC(vd->vdev_name_vp, 258dcba9f3fSGeorge Wilson dsl_pool_vnrele_taskq(vd->vdev_spa->spa_dsl_pool)); 259dcba9f3fSGeorge Wilson vd->vdev_name_vp = NULL; 260dcba9f3fSGeorge Wilson } 261dcba9f3fSGeorge Wilson if (vd->vdev_devid_vp) { 262dcba9f3fSGeorge Wilson VN_RELE_ASYNC(vd->vdev_devid_vp, 263dcba9f3fSGeorge Wilson dsl_pool_vnrele_taskq(vd->vdev_spa->spa_dsl_pool)); 264dcba9f3fSGeorge Wilson vd->vdev_devid_vp = NULL; 265dcba9f3fSGeorge Wilson } 266dcba9f3fSGeorge Wilson } 267dcba9f3fSGeorge Wilson 268a5b57771SDan McDonald /* 269a5b57771SDan McDonald * We want to be loud in DEBUG kernels when DKIOCGMEDIAINFOEXT fails, or when 270a5b57771SDan McDonald * even a fallback to DKIOCGMEDIAINFO fails. 271a5b57771SDan McDonald */ 272a5b57771SDan McDonald #ifdef DEBUG 273a5b57771SDan McDonald #define VDEV_DEBUG(...) cmn_err(CE_NOTE, __VA_ARGS__) 274a5b57771SDan McDonald #else 275a5b57771SDan McDonald #define VDEV_DEBUG(...) /* Nothing... */ 276a5b57771SDan McDonald #endif 277a5b57771SDan McDonald 278fa9e4066Sahrens static int 2794263d13fSGeorge Wilson vdev_disk_open(vdev_t *vd, uint64_t *psize, uint64_t *max_psize, 2804263d13fSGeorge Wilson uint64_t *ashift) 281fa9e4066Sahrens { 2828ad4d6ddSJeff Bonwick spa_t *spa = vd->vdev_spa; 28339cddb10SJoshua M. Clulow vdev_disk_t *dvd = vd->vdev_tsd; 28439cddb10SJoshua M. Clulow ldi_ev_cookie_t ecookie; 28539cddb10SJoshua M. Clulow vdev_disk_ldi_cb_t *lcb; 286a5b57771SDan McDonald union { 287a5b57771SDan McDonald struct dk_minfo_ext ude; 288a5b57771SDan McDonald struct dk_minfo ud; 289a5b57771SDan McDonald } dks; 290a5b57771SDan McDonald struct dk_minfo_ext *dkmext = &dks.ude; 291a5b57771SDan McDonald struct dk_minfo *dkm = &dks.ud; 292*084fd14fSBrian Behlendorf int error, can_free; 293e14bb325SJeff Bonwick dev_t dev; 294e14bb325SJeff Bonwick int otyp; 295fb02ae02SGeorge Wilson boolean_t validate_devid = B_FALSE; 296a5b57771SDan McDonald uint64_t capacity = 0, blksz = 0, pbsize; 297fa9e4066Sahrens 298fa9e4066Sahrens /* 299fa9e4066Sahrens * We must have a pathname, and it must be absolute. 300fa9e4066Sahrens */ 301fa9e4066Sahrens if (vd->vdev_path == NULL || vd->vdev_path[0] != '/') { 302fa9e4066Sahrens vd->vdev_stat.vs_aux = VDEV_AUX_BAD_LABEL; 303be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 304fa9e4066Sahrens } 305fa9e4066Sahrens 306095bcd66SGeorge Wilson /* 307095bcd66SGeorge Wilson * Reopen the device if it's not currently open. Otherwise, 308095bcd66SGeorge Wilson * just update the physical size of the device. 309095bcd66SGeorge Wilson */ 31039cddb10SJoshua M. Clulow if (dvd != NULL) { 31139cddb10SJoshua M. Clulow if (dvd->vd_ldi_offline && dvd->vd_lh == NULL) { 31239cddb10SJoshua M. Clulow /* 31339cddb10SJoshua M. Clulow * If we are opening a device in its offline notify 31439cddb10SJoshua M. Clulow * context, the LDI handle was just closed. Clean 31539cddb10SJoshua M. Clulow * up the LDI event callbacks and free vd->vdev_tsd. 31639cddb10SJoshua M. Clulow */ 31739cddb10SJoshua M. Clulow vdev_disk_free(vd); 31839cddb10SJoshua M. Clulow } else { 31939cddb10SJoshua M. Clulow ASSERT(vd->vdev_reopening); 32039cddb10SJoshua M. Clulow goto skip_open; 32139cddb10SJoshua M. Clulow } 322095bcd66SGeorge Wilson } 323095bcd66SGeorge Wilson 32439cddb10SJoshua M. Clulow /* 32539cddb10SJoshua M. Clulow * Create vd->vdev_tsd. 32639cddb10SJoshua M. Clulow */ 32739cddb10SJoshua M. Clulow vdev_disk_alloc(vd); 32839cddb10SJoshua M. Clulow dvd = vd->vdev_tsd; 329fa9e4066Sahrens 3306fe4f300SPavel Zakharov /* 3316fe4f300SPavel Zakharov * Allow bypassing the devid. 3326fe4f300SPavel Zakharov */ 3336fe4f300SPavel Zakharov if (vd->vdev_devid != NULL && vdev_disk_bypass_devid) { 3346fe4f300SPavel Zakharov vdev_dbgmsg(vd, "vdev_disk_open, devid %s bypassed", 3356fe4f300SPavel Zakharov vd->vdev_devid); 3366fe4f300SPavel Zakharov spa_strfree(vd->vdev_devid); 3376fe4f300SPavel Zakharov vd->vdev_devid = NULL; 3386fe4f300SPavel Zakharov } 3396fe4f300SPavel Zakharov 340fa9e4066Sahrens /* 341fa9e4066Sahrens * When opening a disk device, we want to preserve the user's original 342fa9e4066Sahrens * intent. We always want to open the device by the path the user gave 3431724dc7bSJoshua M. Clulow * us, even if it is one of multiple paths to the same device. But we 344fa9e4066Sahrens * also want to be able to survive disks being removed/recabled. 345fa9e4066Sahrens * Therefore the sequence of opening devices is: 346fa9e4066Sahrens * 347afefbcddSeschrock * 1. Try opening the device by path. For legacy pools without the 348afefbcddSeschrock * 'whole_disk' property, attempt to fix the path by appending 's0'. 349fa9e4066Sahrens * 350fa9e4066Sahrens * 2. If the devid of the device matches the stored value, return 351fa9e4066Sahrens * success. 352fa9e4066Sahrens * 353fa9e4066Sahrens * 3. Otherwise, the device may have moved. Try opening the device 354fa9e4066Sahrens * by the devid instead. 355fa9e4066Sahrens */ 356fa9e4066Sahrens if (vd->vdev_devid != NULL) { 357fa9e4066Sahrens if (ddi_devid_str_decode(vd->vdev_devid, &dvd->vd_devid, 358fa9e4066Sahrens &dvd->vd_minor) != 0) { 359fa9e4066Sahrens vd->vdev_stat.vs_aux = VDEV_AUX_BAD_LABEL; 3603ee8c80cSPavel Zakharov vdev_dbgmsg(vd, "vdev_disk_open: invalid " 3613ee8c80cSPavel Zakharov "vdev_devid '%s'", vd->vdev_devid); 362be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 363fa9e4066Sahrens } 364fa9e4066Sahrens } 365fa9e4066Sahrens 366fa9e4066Sahrens error = EINVAL; /* presume failure */ 367fa9e4066Sahrens 368095bcd66SGeorge Wilson if (vd->vdev_path != NULL) { 369fa9e4066Sahrens 370afefbcddSeschrock if (vd->vdev_wholedisk == -1ULL) { 371afefbcddSeschrock size_t len = strlen(vd->vdev_path) + 3; 372afefbcddSeschrock char *buf = kmem_alloc(len, KM_SLEEP); 373afefbcddSeschrock 374afefbcddSeschrock (void) snprintf(buf, len, "%ss0", vd->vdev_path); 375afefbcddSeschrock 37639cddb10SJoshua M. Clulow error = ldi_open_by_name(buf, spa_mode(spa), kcred, 37739cddb10SJoshua M. Clulow &dvd->vd_lh, zfs_li); 37839cddb10SJoshua M. Clulow if (error == 0) { 379afefbcddSeschrock spa_strfree(vd->vdev_path); 380afefbcddSeschrock vd->vdev_path = buf; 381afefbcddSeschrock vd->vdev_wholedisk = 1ULL; 382afefbcddSeschrock } else { 383afefbcddSeschrock kmem_free(buf, len); 384afefbcddSeschrock } 385afefbcddSeschrock } 386fa9e4066Sahrens 38739cddb10SJoshua M. Clulow /* 38839cddb10SJoshua M. Clulow * If we have not yet opened the device, try to open it by the 38939cddb10SJoshua M. Clulow * specified path. 39039cddb10SJoshua M. Clulow */ 39139cddb10SJoshua M. Clulow if (error != 0) { 39239cddb10SJoshua M. Clulow error = ldi_open_by_name(vd->vdev_path, spa_mode(spa), 39339cddb10SJoshua M. Clulow kcred, &dvd->vd_lh, zfs_li); 39439cddb10SJoshua M. Clulow } 395fa9e4066Sahrens 396fa9e4066Sahrens /* 397fa9e4066Sahrens * Compare the devid to the stored value. 398fa9e4066Sahrens */ 3996af23589SJoshua M. Clulow if (error == 0 && vd->vdev_devid != NULL) { 4006af23589SJoshua M. Clulow ddi_devid_t devid = NULL; 4016af23589SJoshua M. Clulow 4026af23589SJoshua M. Clulow if (ldi_get_devid(dvd->vd_lh, &devid) != 0) { 4036af23589SJoshua M. Clulow /* 4046af23589SJoshua M. Clulow * We expected a devid on this device but it no 4056af23589SJoshua M. Clulow * longer appears to have one. The validation 4066af23589SJoshua M. Clulow * step may need to remove it from the 4076af23589SJoshua M. Clulow * configuration. 4086af23589SJoshua M. Clulow */ 4096af23589SJoshua M. Clulow validate_devid = B_TRUE; 4106af23589SJoshua M. Clulow 4116af23589SJoshua M. Clulow } else if (ddi_devid_compare(devid, dvd->vd_devid) != 4126af23589SJoshua M. Clulow 0) { 4136fe4f300SPavel Zakharov /* 4146fe4f300SPavel Zakharov * A mismatch here is unexpected, log it. 4156fe4f300SPavel Zakharov */ 4166fe4f300SPavel Zakharov char *devid_str = ddi_devid_str_encode(devid, 4176fe4f300SPavel Zakharov dvd->vd_minor); 4186fe4f300SPavel Zakharov vdev_dbgmsg(vd, "vdev_disk_open: devid " 4196fe4f300SPavel Zakharov "mismatch: %s != %s", vd->vdev_devid, 4206fe4f300SPavel Zakharov devid_str); 4216fe4f300SPavel Zakharov cmn_err(CE_NOTE, "vdev_disk_open %s: devid " 4226fe4f300SPavel Zakharov "mismatch: %s != %s", vd->vdev_path, 4236fe4f300SPavel Zakharov vd->vdev_devid, devid_str); 4246fe4f300SPavel Zakharov ddi_devid_str_free(devid_str); 4256fe4f300SPavel Zakharov 426be6fd75aSMatthew Ahrens error = SET_ERROR(EINVAL); 4278ad4d6ddSJeff Bonwick (void) ldi_close(dvd->vd_lh, spa_mode(spa), 4288ad4d6ddSJeff Bonwick kcred); 429fa9e4066Sahrens dvd->vd_lh = NULL; 430fa9e4066Sahrens } 4316af23589SJoshua M. Clulow 4326af23589SJoshua M. Clulow if (devid != NULL) { 4336af23589SJoshua M. Clulow ddi_devid_free(devid); 4346af23589SJoshua M. Clulow } 435fa9e4066Sahrens } 436afefbcddSeschrock 437afefbcddSeschrock /* 438afefbcddSeschrock * If we succeeded in opening the device, but 'vdev_wholedisk' 439afefbcddSeschrock * is not yet set, then this must be a slice. 440afefbcddSeschrock */ 441afefbcddSeschrock if (error == 0 && vd->vdev_wholedisk == -1ULL) 442afefbcddSeschrock vd->vdev_wholedisk = 0; 443fa9e4066Sahrens } 444fa9e4066Sahrens 445fa9e4066Sahrens /* 446fa9e4066Sahrens * If we were unable to open by path, or the devid check fails, open by 447fa9e4066Sahrens * devid instead. 448fa9e4066Sahrens */ 449fb02ae02SGeorge Wilson if (error != 0 && vd->vdev_devid != NULL) { 450fa9e4066Sahrens error = ldi_open_by_devid(dvd->vd_devid, dvd->vd_minor, 4518ad4d6ddSJeff Bonwick spa_mode(spa), kcred, &dvd->vd_lh, zfs_li); 4526fe4f300SPavel Zakharov if (error != 0) { 4536fe4f300SPavel Zakharov vdev_dbgmsg(vd, "Failed to open by devid (%s)", 4546fe4f300SPavel Zakharov vd->vdev_devid); 4556fe4f300SPavel Zakharov } 456fb02ae02SGeorge Wilson } 457fa9e4066Sahrens 4583d7072f8Seschrock /* 4593d7072f8Seschrock * If all else fails, then try opening by physical path (if available) 4603d7072f8Seschrock * or the logical path (if we failed due to the devid check). While not 4613d7072f8Seschrock * as reliable as the devid, this will give us something, and the higher 4623d7072f8Seschrock * level vdev validation will prevent us from opening the wrong device. 4633d7072f8Seschrock */ 4646af23589SJoshua M. Clulow if (error != 0) { 4656af23589SJoshua M. Clulow validate_devid = B_TRUE; 466fb02ae02SGeorge Wilson 4673d7072f8Seschrock if (vd->vdev_physpath != NULL && 4686af23589SJoshua M. Clulow (dev = ddi_pathname_to_dev_t(vd->vdev_physpath)) != NODEV) { 4698ad4d6ddSJeff Bonwick error = ldi_open_by_dev(&dev, OTYP_BLK, spa_mode(spa), 4703d7072f8Seschrock kcred, &dvd->vd_lh, zfs_li); 4716af23589SJoshua M. Clulow } 4723d7072f8Seschrock 4733d7072f8Seschrock /* 4743d7072f8Seschrock * Note that we don't support the legacy auto-wholedisk support 4753d7072f8Seschrock * as above. This hasn't been used in a very long time and we 4763d7072f8Seschrock * don't need to propagate its oddities to this edge condition. 4773d7072f8Seschrock */ 4786af23589SJoshua M. Clulow if (error != 0 && vd->vdev_path != NULL) { 4798ad4d6ddSJeff Bonwick error = ldi_open_by_name(vd->vdev_path, spa_mode(spa), 4808ad4d6ddSJeff Bonwick kcred, &dvd->vd_lh, zfs_li); 4816af23589SJoshua M. Clulow } 4823d7072f8Seschrock } 4833d7072f8Seschrock 4846af23589SJoshua M. Clulow if (error != 0) { 485fa9e4066Sahrens vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED; 4863ee8c80cSPavel Zakharov vdev_dbgmsg(vd, "vdev_disk_open: failed to open [error=%d]", 4873ee8c80cSPavel Zakharov error); 488fa9e4066Sahrens return (error); 489e14bb325SJeff Bonwick } 490fa9e4066Sahrens 491fb02ae02SGeorge Wilson /* 492fb02ae02SGeorge Wilson * Now that the device has been successfully opened, update the devid 493fb02ae02SGeorge Wilson * if necessary. 494fb02ae02SGeorge Wilson */ 4956af23589SJoshua M. Clulow if (validate_devid) { 4966af23589SJoshua M. Clulow ddi_devid_t devid = NULL; 4976af23589SJoshua M. Clulow char *minorname = NULL; 4986af23589SJoshua M. Clulow char *vd_devid = NULL; 4996af23589SJoshua M. Clulow boolean_t remove = B_FALSE, update = B_FALSE; 5006af23589SJoshua M. Clulow 5016af23589SJoshua M. Clulow /* 5026af23589SJoshua M. Clulow * Get the current devid and minor name for the device we 5036af23589SJoshua M. Clulow * opened. 5046af23589SJoshua M. Clulow */ 5056af23589SJoshua M. Clulow if (ldi_get_devid(dvd->vd_lh, &devid) != 0 || 5066af23589SJoshua M. Clulow ldi_get_minor_name(dvd->vd_lh, &minorname) != 0) { 5076af23589SJoshua M. Clulow /* 5086af23589SJoshua M. Clulow * If we are unable to get the devid or the minor name 5096af23589SJoshua M. Clulow * for the device, we need to remove them from the 5106af23589SJoshua M. Clulow * configuration to prevent potential inconsistencies. 5116af23589SJoshua M. Clulow */ 5126af23589SJoshua M. Clulow if (dvd->vd_minor != NULL || dvd->vd_devid != NULL || 5136af23589SJoshua M. Clulow vd->vdev_devid != NULL) { 5146af23589SJoshua M. Clulow /* 5156af23589SJoshua M. Clulow * We only need to remove the devid if one 5166af23589SJoshua M. Clulow * exists. 5176af23589SJoshua M. Clulow */ 5186af23589SJoshua M. Clulow remove = B_TRUE; 5196af23589SJoshua M. Clulow } 520fb02ae02SGeorge Wilson 5216af23589SJoshua M. Clulow } else if (dvd->vd_devid == NULL || dvd->vd_minor == NULL) { 5226af23589SJoshua M. Clulow /* 5236af23589SJoshua M. Clulow * There was previously no devid at all so we need to 5246af23589SJoshua M. Clulow * add one. 5256af23589SJoshua M. Clulow */ 5266af23589SJoshua M. Clulow update = B_TRUE; 5276af23589SJoshua M. Clulow 5286af23589SJoshua M. Clulow } else if (ddi_devid_compare(devid, dvd->vd_devid) != 0 || 5296af23589SJoshua M. Clulow strcmp(minorname, dvd->vd_minor) != 0) { 5306af23589SJoshua M. Clulow /* 5316af23589SJoshua M. Clulow * The devid or minor name on file does not match the 5326af23589SJoshua M. Clulow * one from the opened device. 5336af23589SJoshua M. Clulow */ 5346af23589SJoshua M. Clulow update = B_TRUE; 5356af23589SJoshua M. Clulow } 5366af23589SJoshua M. Clulow 5376af23589SJoshua M. Clulow if (update) { 5386af23589SJoshua M. Clulow /* 5396af23589SJoshua M. Clulow * Render the new devid and minor name as a string for 5406af23589SJoshua M. Clulow * logging and to store in the vdev configuration. 5416af23589SJoshua M. Clulow */ 5426af23589SJoshua M. Clulow vd_devid = ddi_devid_str_encode(devid, minorname); 5436af23589SJoshua M. Clulow } 5446af23589SJoshua M. Clulow 5456af23589SJoshua M. Clulow if (update || remove) { 5463ee8c80cSPavel Zakharov vdev_dbgmsg(vd, "vdev_disk_open: update devid from " 5476af23589SJoshua M. Clulow "'%s' to '%s'", 5486af23589SJoshua M. Clulow vd->vdev_devid != NULL ? vd->vdev_devid : "<none>", 5496af23589SJoshua M. Clulow vd_devid != NULL ? vd_devid : "<none>"); 5506fe4f300SPavel Zakharov cmn_err(CE_NOTE, "vdev_disk_open %s: update devid " 5516af23589SJoshua M. Clulow "from '%s' to '%s'", 5526af23589SJoshua M. Clulow vd->vdev_path != NULL ? vd->vdev_path : "?", 5536af23589SJoshua M. Clulow vd->vdev_devid != NULL ? vd->vdev_devid : "<none>", 5546af23589SJoshua M. Clulow vd_devid != NULL ? vd_devid : "<none>"); 5556af23589SJoshua M. Clulow 5566af23589SJoshua M. Clulow /* 5576af23589SJoshua M. Clulow * Remove and free any existing values. 5586af23589SJoshua M. Clulow */ 5596af23589SJoshua M. Clulow if (dvd->vd_minor != NULL) { 5606af23589SJoshua M. Clulow ddi_devid_str_free(dvd->vd_minor); 5616af23589SJoshua M. Clulow dvd->vd_minor = NULL; 5626af23589SJoshua M. Clulow } 5636af23589SJoshua M. Clulow if (dvd->vd_devid != NULL) { 5646af23589SJoshua M. Clulow ddi_devid_free(dvd->vd_devid); 5656af23589SJoshua M. Clulow dvd->vd_devid = NULL; 5666af23589SJoshua M. Clulow } 5676af23589SJoshua M. Clulow if (vd->vdev_devid != NULL) { 5686af23589SJoshua M. Clulow spa_strfree(vd->vdev_devid); 5696af23589SJoshua M. Clulow vd->vdev_devid = NULL; 5706af23589SJoshua M. Clulow } 5716af23589SJoshua M. Clulow } 5726af23589SJoshua M. Clulow 5736af23589SJoshua M. Clulow if (update) { 5746af23589SJoshua M. Clulow /* 5756af23589SJoshua M. Clulow * Install the new values. 5766af23589SJoshua M. Clulow */ 5776af23589SJoshua M. Clulow vd->vdev_devid = vd_devid; 5786af23589SJoshua M. Clulow dvd->vd_minor = minorname; 5796af23589SJoshua M. Clulow dvd->vd_devid = devid; 5806af23589SJoshua M. Clulow 5816af23589SJoshua M. Clulow } else { 5826af23589SJoshua M. Clulow if (devid != NULL) { 5836af23589SJoshua M. Clulow ddi_devid_free(devid); 5846af23589SJoshua M. Clulow } 5856af23589SJoshua M. Clulow if (minorname != NULL) { 5866af23589SJoshua M. Clulow kmem_free(minorname, strlen(minorname) + 1); 5876af23589SJoshua M. Clulow } 588fb02ae02SGeorge Wilson } 589fb02ae02SGeorge Wilson } 590fb02ae02SGeorge Wilson 5913d7072f8Seschrock /* 5923d7072f8Seschrock * Once a device is opened, verify that the physical device path (if 5933d7072f8Seschrock * available) is up to date. 5943d7072f8Seschrock */ 5953d7072f8Seschrock if (ldi_get_dev(dvd->vd_lh, &dev) == 0 && 5963d7072f8Seschrock ldi_get_otyp(dvd->vd_lh, &otyp) == 0) { 5970a4e9518Sgw char *physpath, *minorname; 5980a4e9518Sgw 5993d7072f8Seschrock physpath = kmem_alloc(MAXPATHLEN, KM_SLEEP); 6003d7072f8Seschrock minorname = NULL; 6013d7072f8Seschrock if (ddi_dev_pathname(dev, otyp, physpath) == 0 && 6023d7072f8Seschrock ldi_get_minor_name(dvd->vd_lh, &minorname) == 0 && 6033d7072f8Seschrock (vd->vdev_physpath == NULL || 6043d7072f8Seschrock strcmp(vd->vdev_physpath, physpath) != 0)) { 6053d7072f8Seschrock if (vd->vdev_physpath) 6063d7072f8Seschrock spa_strfree(vd->vdev_physpath); 6073d7072f8Seschrock (void) strlcat(physpath, ":", MAXPATHLEN); 6083d7072f8Seschrock (void) strlcat(physpath, minorname, MAXPATHLEN); 6093d7072f8Seschrock vd->vdev_physpath = spa_strdup(physpath); 6103d7072f8Seschrock } 6113d7072f8Seschrock if (minorname) 6123d7072f8Seschrock kmem_free(minorname, strlen(minorname) + 1); 6133d7072f8Seschrock kmem_free(physpath, MAXPATHLEN); 6143d7072f8Seschrock } 6153d7072f8Seschrock 61639cddb10SJoshua M. Clulow /* 61739cddb10SJoshua M. Clulow * Register callbacks for the LDI offline event. 61839cddb10SJoshua M. Clulow */ 61939cddb10SJoshua M. Clulow if (ldi_ev_get_cookie(dvd->vd_lh, LDI_EV_OFFLINE, &ecookie) == 62039cddb10SJoshua M. Clulow LDI_EV_SUCCESS) { 62139cddb10SJoshua M. Clulow lcb = kmem_zalloc(sizeof (vdev_disk_ldi_cb_t), KM_SLEEP); 62239cddb10SJoshua M. Clulow list_insert_tail(&dvd->vd_ldi_cbs, lcb); 62339cddb10SJoshua M. Clulow (void) ldi_ev_register_callbacks(dvd->vd_lh, ecookie, 62439cddb10SJoshua M. Clulow &vdev_disk_off_callb, (void *) vd, &lcb->lcb_id); 62539cddb10SJoshua M. Clulow } 62639cddb10SJoshua M. Clulow 62739cddb10SJoshua M. Clulow /* 62839cddb10SJoshua M. Clulow * Register callbacks for the LDI degrade event. 62939cddb10SJoshua M. Clulow */ 63039cddb10SJoshua M. Clulow if (ldi_ev_get_cookie(dvd->vd_lh, LDI_EV_DEGRADE, &ecookie) == 63139cddb10SJoshua M. Clulow LDI_EV_SUCCESS) { 63239cddb10SJoshua M. Clulow lcb = kmem_zalloc(sizeof (vdev_disk_ldi_cb_t), KM_SLEEP); 63339cddb10SJoshua M. Clulow list_insert_tail(&dvd->vd_ldi_cbs, lcb); 63439cddb10SJoshua M. Clulow (void) ldi_ev_register_callbacks(dvd->vd_lh, ecookie, 63539cddb10SJoshua M. Clulow &vdev_disk_dgrd_callb, (void *) vd, &lcb->lcb_id); 63639cddb10SJoshua M. Clulow } 637*084fd14fSBrian Behlendorf 638095bcd66SGeorge Wilson skip_open: 639fa9e4066Sahrens /* 640fa9e4066Sahrens * Determine the actual size of the device. 641fa9e4066Sahrens */ 642fa9e4066Sahrens if (ldi_get_size(dvd->vd_lh, psize) != 0) { 643fa9e4066Sahrens vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED; 6443ee8c80cSPavel Zakharov vdev_dbgmsg(vd, "vdev_disk_open: failed to get size"); 645be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 646fa9e4066Sahrens } 647fa9e4066Sahrens 648a5b57771SDan McDonald *max_psize = *psize; 649a5b57771SDan McDonald 650ecc2d604Sbonwick /* 651ecc2d604Sbonwick * Determine the device's minimum transfer size. 652ecc2d604Sbonwick * If the ioctl isn't supported, assume DEV_BSIZE. 653ecc2d604Sbonwick */ 654a5b57771SDan McDonald if ((error = ldi_ioctl(dvd->vd_lh, DKIOCGMEDIAINFOEXT, 655a5b57771SDan McDonald (intptr_t)dkmext, FKIOCTL, kcred, NULL)) == 0) { 656a5b57771SDan McDonald capacity = dkmext->dki_capacity - 1; 657a5b57771SDan McDonald blksz = dkmext->dki_lbsize; 658a5b57771SDan McDonald pbsize = dkmext->dki_pbsize; 659a5b57771SDan McDonald } else if ((error = ldi_ioctl(dvd->vd_lh, DKIOCGMEDIAINFO, 660a5b57771SDan McDonald (intptr_t)dkm, FKIOCTL, kcred, NULL)) == 0) { 661a5b57771SDan McDonald VDEV_DEBUG( 662a5b57771SDan McDonald "vdev_disk_open(\"%s\"): fallback to DKIOCGMEDIAINFO\n", 663a5b57771SDan McDonald vd->vdev_path); 664a5b57771SDan McDonald capacity = dkm->dki_capacity - 1; 665a5b57771SDan McDonald blksz = dkm->dki_lbsize; 666a5b57771SDan McDonald pbsize = blksz; 667a5b57771SDan McDonald } else { 668a5b57771SDan McDonald VDEV_DEBUG("vdev_disk_open(\"%s\"): " 669a5b57771SDan McDonald "both DKIOCGMEDIAINFO{,EXT} calls failed, %d\n", 670a5b57771SDan McDonald vd->vdev_path, error); 671a5b57771SDan McDonald pbsize = DEV_BSIZE; 672a5b57771SDan McDonald } 673bef6b7d2Swebaker 674bf16b11eSMatthew Ahrens *ashift = highbit64(MAX(pbsize, SPA_MINBLOCKSIZE)) - 1; 675bef6b7d2Swebaker 6764263d13fSGeorge Wilson if (vd->vdev_wholedisk == 1) { 6774263d13fSGeorge Wilson int wce = 1; 6784263d13fSGeorge Wilson 679a5b57771SDan McDonald if (error == 0) { 680a5b57771SDan McDonald /* 681a5b57771SDan McDonald * If we have the capability to expand, we'd have 682a5b57771SDan McDonald * found out via success from DKIOCGMEDIAINFO{,EXT}. 683a5b57771SDan McDonald * Adjust max_psize upward accordingly since we know 684a5b57771SDan McDonald * we own the whole disk now. 685a5b57771SDan McDonald */ 686c39a2aaeSGeorge Wilson *max_psize = capacity * blksz; 687a5b57771SDan McDonald } 688a5b57771SDan McDonald 6894263d13fSGeorge Wilson /* 690a5b57771SDan McDonald * Since we own the whole disk, try to enable disk write 691a5b57771SDan McDonald * caching. We ignore errors because it's OK if we can't do it. 6924263d13fSGeorge Wilson */ 6934263d13fSGeorge Wilson (void) ldi_ioctl(dvd->vd_lh, DKIOCSETWCE, (intptr_t)&wce, 6944263d13fSGeorge Wilson FKIOCTL, kcred, NULL); 6954263d13fSGeorge Wilson } 6964263d13fSGeorge Wilson 697b468a217Seschrock /* 698b468a217Seschrock * Clear the nowritecache bit, so that on a vdev_reopen() we will 699b468a217Seschrock * try again. 700b468a217Seschrock */ 701b468a217Seschrock vd->vdev_nowritecache = B_FALSE; 702b468a217Seschrock 703*084fd14fSBrian Behlendorf if (ldi_ioctl(dvd->vd_lh, DKIOC_CANFREE, (intptr_t)&can_free, FKIOCTL, 704*084fd14fSBrian Behlendorf kcred, NULL) == 0 && can_free == 1) { 705*084fd14fSBrian Behlendorf vd->vdev_has_trim = B_TRUE; 706*084fd14fSBrian Behlendorf } else { 707*084fd14fSBrian Behlendorf vd->vdev_has_trim = B_FALSE; 708*084fd14fSBrian Behlendorf } 709*084fd14fSBrian Behlendorf 710*084fd14fSBrian Behlendorf /* Currently only supported for ZoL. */ 711*084fd14fSBrian Behlendorf vd->vdev_has_securetrim = B_FALSE; 712*084fd14fSBrian Behlendorf 71312a8814cSTom Caputi /* Inform the ZIO pipeline that we are non-rotational */ 71412a8814cSTom Caputi vd->vdev_nonrot = B_FALSE; 71512a8814cSTom Caputi if (ldi_prop_exists(dvd->vd_lh, DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, 71612a8814cSTom Caputi "device-solid-state")) { 71712a8814cSTom Caputi if (ldi_prop_get_int(dvd->vd_lh, 71812a8814cSTom Caputi LDI_DEV_T_ANY | DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, 71912a8814cSTom Caputi "device-solid-state", B_FALSE) != 0) 72012a8814cSTom Caputi vd->vdev_nonrot = B_TRUE; 72112a8814cSTom Caputi } 72212a8814cSTom Caputi 723fa9e4066Sahrens return (0); 724fa9e4066Sahrens } 725fa9e4066Sahrens 726fa9e4066Sahrens static void 727fa9e4066Sahrens vdev_disk_close(vdev_t *vd) 728fa9e4066Sahrens { 729fa9e4066Sahrens vdev_disk_t *dvd = vd->vdev_tsd; 730fa9e4066Sahrens 731095bcd66SGeorge Wilson if (vd->vdev_reopening || dvd == NULL) 732fa9e4066Sahrens return; 733fa9e4066Sahrens 73439cddb10SJoshua M. Clulow if (dvd->vd_minor != NULL) { 735fa9e4066Sahrens ddi_devid_str_free(dvd->vd_minor); 73639cddb10SJoshua M. Clulow dvd->vd_minor = NULL; 73739cddb10SJoshua M. Clulow } 738fa9e4066Sahrens 73939cddb10SJoshua M. Clulow if (dvd->vd_devid != NULL) { 740fa9e4066Sahrens ddi_devid_free(dvd->vd_devid); 74139cddb10SJoshua M. Clulow dvd->vd_devid = NULL; 74239cddb10SJoshua M. Clulow } 743fa9e4066Sahrens 74439cddb10SJoshua M. Clulow if (dvd->vd_lh != NULL) { 7458ad4d6ddSJeff Bonwick (void) ldi_close(dvd->vd_lh, spa_mode(vd->vdev_spa), kcred); 74639cddb10SJoshua M. Clulow dvd->vd_lh = NULL; 74739cddb10SJoshua M. Clulow } 748fa9e4066Sahrens 74998d1cbfeSGeorge Wilson vd->vdev_delayed_close = B_FALSE; 75039cddb10SJoshua M. Clulow /* 75139cddb10SJoshua M. Clulow * If we closed the LDI handle due to an offline notify from LDI, 75239cddb10SJoshua M. Clulow * don't free vd->vdev_tsd or unregister the callbacks here; 75339cddb10SJoshua M. Clulow * the offline finalize callback or a reopen will take care of it. 75439cddb10SJoshua M. Clulow */ 75539cddb10SJoshua M. Clulow if (dvd->vd_ldi_offline) 75639cddb10SJoshua M. Clulow return; 75739cddb10SJoshua M. Clulow 75839cddb10SJoshua M. Clulow vdev_disk_free(vd); 759fa9e4066Sahrens } 760fa9e4066Sahrens 761e7cbe64fSgw int 762810e43b2SBill Pijewski vdev_disk_physio(vdev_t *vd, caddr_t data, 763810e43b2SBill Pijewski size_t size, uint64_t offset, int flags, boolean_t isdump) 764810e43b2SBill Pijewski { 765810e43b2SBill Pijewski vdev_disk_t *dvd = vd->vdev_tsd; 766810e43b2SBill Pijewski 76739cddb10SJoshua M. Clulow /* 76839cddb10SJoshua M. Clulow * If the vdev is closed, it's likely in the REMOVED or FAULTED state. 76939cddb10SJoshua M. Clulow * Nothing to be done here but return failure. 77039cddb10SJoshua M. Clulow */ 77139cddb10SJoshua M. Clulow if (dvd == NULL || (dvd->vd_ldi_offline && dvd->vd_lh == NULL)) 77239cddb10SJoshua M. Clulow return (EIO); 77339cddb10SJoshua M. Clulow 774810e43b2SBill Pijewski ASSERT(vd->vdev_ops == &vdev_disk_ops); 775810e43b2SBill Pijewski 776810e43b2SBill Pijewski /* 777810e43b2SBill Pijewski * If in the context of an active crash dump, use the ldi_dump(9F) 778810e43b2SBill Pijewski * call instead of ldi_strategy(9F) as usual. 779810e43b2SBill Pijewski */ 780810e43b2SBill Pijewski if (isdump) { 781810e43b2SBill Pijewski ASSERT3P(dvd, !=, NULL); 782810e43b2SBill Pijewski return (ldi_dump(dvd->vd_lh, data, lbtodb(offset), 783810e43b2SBill Pijewski lbtodb(size))); 784810e43b2SBill Pijewski } 785810e43b2SBill Pijewski 786810e43b2SBill Pijewski return (vdev_disk_ldi_physio(dvd->vd_lh, data, size, offset, flags)); 787810e43b2SBill Pijewski } 788810e43b2SBill Pijewski 789810e43b2SBill Pijewski int 790810e43b2SBill Pijewski vdev_disk_ldi_physio(ldi_handle_t vd_lh, caddr_t data, 791810e43b2SBill Pijewski size_t size, uint64_t offset, int flags) 792e7cbe64fSgw { 793e7cbe64fSgw buf_t *bp; 794e7cbe64fSgw int error = 0; 795e7cbe64fSgw 796e7cbe64fSgw if (vd_lh == NULL) 797be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 798e7cbe64fSgw 799e7cbe64fSgw ASSERT(flags & B_READ || flags & B_WRITE); 800e7cbe64fSgw 801e7cbe64fSgw bp = getrbuf(KM_SLEEP); 802e7cbe64fSgw bp->b_flags = flags | B_BUSY | B_NOCACHE | B_FAILFAST; 803e7cbe64fSgw bp->b_bcount = size; 804e7cbe64fSgw bp->b_un.b_addr = (void *)data; 805e7cbe64fSgw bp->b_lblkno = lbtodb(offset); 806e7cbe64fSgw bp->b_bufsize = size; 807e7cbe64fSgw 808e7cbe64fSgw error = ldi_strategy(vd_lh, bp); 809e7cbe64fSgw ASSERT(error == 0); 810e7cbe64fSgw if ((error = biowait(bp)) == 0 && bp->b_resid != 0) 811be6fd75aSMatthew Ahrens error = SET_ERROR(EIO); 812e7cbe64fSgw freerbuf(bp); 813e7cbe64fSgw 814e7cbe64fSgw return (error); 815e7cbe64fSgw } 816e7cbe64fSgw 817c62757b2SToomas Soome static int 818fa9e4066Sahrens vdev_disk_io_intr(buf_t *bp) 819fa9e4066Sahrens { 82031d7e8faSGeorge Wilson vdev_buf_t *vb = (vdev_buf_t *)bp; 82131d7e8faSGeorge Wilson zio_t *zio = vb->vb_io; 822fa9e4066Sahrens 82351ece835Seschrock /* 82451ece835Seschrock * The rest of the zio stack only deals with EIO, ECKSUM, and ENXIO. 82551ece835Seschrock * Rather than teach the rest of the stack about other error 82651ece835Seschrock * possibilities (EFAULT, etc), we normalize the error value here. 82751ece835Seschrock */ 82851ece835Seschrock zio->io_error = (geterror(bp) != 0 ? EIO : 0); 82951ece835Seschrock 83051ece835Seschrock if (zio->io_error == 0 && bp->b_resid != 0) 831be6fd75aSMatthew Ahrens zio->io_error = SET_ERROR(EIO); 832fa9e4066Sahrens 833770499e1SDan Kimmel if (zio->io_type == ZIO_TYPE_READ) { 834770499e1SDan Kimmel abd_return_buf_copy(zio->io_abd, bp->b_un.b_addr, zio->io_size); 835770499e1SDan Kimmel } else { 836770499e1SDan Kimmel abd_return_buf(zio->io_abd, bp->b_un.b_addr, zio->io_size); 837770499e1SDan Kimmel } 838770499e1SDan Kimmel 83931d7e8faSGeorge Wilson kmem_free(vb, sizeof (vdev_buf_t)); 840fa9e4066Sahrens 84197e81309SPrakash Surya zio_delay_interrupt(zio); 842c62757b2SToomas Soome return (0); 843fa9e4066Sahrens } 844fa9e4066Sahrens 845f4a72450SJeff Bonwick static void 846f4a72450SJeff Bonwick vdev_disk_ioctl_free(zio_t *zio) 847f4a72450SJeff Bonwick { 848f4a72450SJeff Bonwick kmem_free(zio->io_vsd, sizeof (struct dk_callback)); 849f4a72450SJeff Bonwick } 850f4a72450SJeff Bonwick 85122fe2c88SJonathan Adams static const zio_vsd_ops_t vdev_disk_vsd_ops = { 85222fe2c88SJonathan Adams vdev_disk_ioctl_free, 85322fe2c88SJonathan Adams zio_vsd_default_cksum_report 85422fe2c88SJonathan Adams }; 85522fe2c88SJonathan Adams 856fa9e4066Sahrens static void 857fa9e4066Sahrens vdev_disk_ioctl_done(void *zio_arg, int error) 858fa9e4066Sahrens { 859fa9e4066Sahrens zio_t *zio = zio_arg; 860fa9e4066Sahrens 861fa9e4066Sahrens zio->io_error = error; 862fa9e4066Sahrens 863e05725b1Sbonwick zio_interrupt(zio); 864fa9e4066Sahrens } 865fa9e4066Sahrens 866738f37bcSGeorge Wilson static void 867fa9e4066Sahrens vdev_disk_io_start(zio_t *zio) 868fa9e4066Sahrens { 869fa9e4066Sahrens vdev_t *vd = zio->io_vd; 870fa9e4066Sahrens vdev_disk_t *dvd = vd->vdev_tsd; 871*084fd14fSBrian Behlendorf unsigned long trim_flags = 0; 87231d7e8faSGeorge Wilson vdev_buf_t *vb; 873e14bb325SJeff Bonwick struct dk_callback *dkc; 874fa9e4066Sahrens buf_t *bp; 875e14bb325SJeff Bonwick int error; 876fa9e4066Sahrens 87739cddb10SJoshua M. Clulow /* 87839cddb10SJoshua M. Clulow * If the vdev is closed, it's likely in the REMOVED or FAULTED state. 87939cddb10SJoshua M. Clulow * Nothing to be done here but return failure. 88039cddb10SJoshua M. Clulow */ 88139cddb10SJoshua M. Clulow if (dvd == NULL || (dvd->vd_ldi_offline && dvd->vd_lh == NULL)) { 88239cddb10SJoshua M. Clulow zio->io_error = ENXIO; 883738f37bcSGeorge Wilson zio_interrupt(zio); 884738f37bcSGeorge Wilson return; 88539cddb10SJoshua M. Clulow } 88639cddb10SJoshua M. Clulow 887*084fd14fSBrian Behlendorf switch (zio->io_type) { 888*084fd14fSBrian Behlendorf case ZIO_TYPE_IOCTL: 889fa9e4066Sahrens /* XXPOLICY */ 8900a4e9518Sgw if (!vdev_readable(vd)) { 891be6fd75aSMatthew Ahrens zio->io_error = SET_ERROR(ENXIO); 892738f37bcSGeorge Wilson zio_interrupt(zio); 893738f37bcSGeorge Wilson return; 894fa9e4066Sahrens } 895fa9e4066Sahrens 896fa9e4066Sahrens switch (zio->io_cmd) { 897fa9e4066Sahrens 898fa9e4066Sahrens case DKIOCFLUSHWRITECACHE: 899fa9e4066Sahrens 900a2eea2e1Sahrens if (zfs_nocacheflush) 901a2eea2e1Sahrens break; 902a2eea2e1Sahrens 903b468a217Seschrock if (vd->vdev_nowritecache) { 904be6fd75aSMatthew Ahrens zio->io_error = SET_ERROR(ENOTSUP); 905b468a217Seschrock break; 906b468a217Seschrock } 907b468a217Seschrock 908e14bb325SJeff Bonwick zio->io_vsd = dkc = kmem_alloc(sizeof (*dkc), KM_SLEEP); 90922fe2c88SJonathan Adams zio->io_vsd_ops = &vdev_disk_vsd_ops; 910e14bb325SJeff Bonwick 911e14bb325SJeff Bonwick dkc->dkc_callback = vdev_disk_ioctl_done; 912e14bb325SJeff Bonwick dkc->dkc_flag = FLUSH_VOLATILE; 913e14bb325SJeff Bonwick dkc->dkc_cookie = zio; 914fa9e4066Sahrens 915fa9e4066Sahrens error = ldi_ioctl(dvd->vd_lh, zio->io_cmd, 916e14bb325SJeff Bonwick (uintptr_t)dkc, FKIOCTL, kcred, NULL); 917fa9e4066Sahrens 918fa9e4066Sahrens if (error == 0) { 919fa9e4066Sahrens /* 920fa9e4066Sahrens * The ioctl will be done asychronously, 921fa9e4066Sahrens * and will call vdev_disk_ioctl_done() 922fa9e4066Sahrens * upon completion. 923fa9e4066Sahrens */ 924738f37bcSGeorge Wilson return; 925e05725b1Sbonwick } 926e05725b1Sbonwick 927fa9e4066Sahrens zio->io_error = error; 928b468a217Seschrock 929fa9e4066Sahrens break; 930fa9e4066Sahrens 931fa9e4066Sahrens default: 932be6fd75aSMatthew Ahrens zio->io_error = SET_ERROR(ENOTSUP); 933fa9e4066Sahrens } 934fa9e4066Sahrens 935738f37bcSGeorge Wilson zio_execute(zio); 936738f37bcSGeorge Wilson return; 937*084fd14fSBrian Behlendorf 938*084fd14fSBrian Behlendorf case ZIO_TYPE_TRIM: 939*084fd14fSBrian Behlendorf if (!vd->vdev_has_trim) { 940*084fd14fSBrian Behlendorf zio->io_error = SET_ERROR(ENOTSUP); 941*084fd14fSBrian Behlendorf zio_execute(zio); 942*084fd14fSBrian Behlendorf return; 943*084fd14fSBrian Behlendorf } 944*084fd14fSBrian Behlendorf /* Currently only supported on ZoL. */ 945*084fd14fSBrian Behlendorf ASSERT0(zio->io_trim_flags & ZIO_TRIM_SECURE); 946*084fd14fSBrian Behlendorf 947*084fd14fSBrian Behlendorf /* dkioc_free_list_t is already declared to hold one entry */ 948*084fd14fSBrian Behlendorf dkioc_free_list_t dfl; 949*084fd14fSBrian Behlendorf dfl.dfl_flags = 0; 950*084fd14fSBrian Behlendorf dfl.dfl_num_exts = 1; 951*084fd14fSBrian Behlendorf dfl.dfl_offset = VDEV_LABEL_START_SIZE; 952*084fd14fSBrian Behlendorf dfl.dfl_exts[0].dfle_start = zio->io_offset; 953*084fd14fSBrian Behlendorf dfl.dfl_exts[0].dfle_length = zio->io_size; 954*084fd14fSBrian Behlendorf 955*084fd14fSBrian Behlendorf zio->io_error = ldi_ioctl(dvd->vd_lh, DKIOCFREE, 956*084fd14fSBrian Behlendorf (uintptr_t)&dfl, FKIOCTL, kcred, NULL); 957*084fd14fSBrian Behlendorf 958*084fd14fSBrian Behlendorf if (zio->io_error == ENOTSUP || zio->io_error == ENOTTY) { 959*084fd14fSBrian Behlendorf /* 960*084fd14fSBrian Behlendorf * The device must have changed and now TRIM is 961*084fd14fSBrian Behlendorf * no longer supported. 962*084fd14fSBrian Behlendorf */ 963*084fd14fSBrian Behlendorf vd->vdev_has_trim = B_FALSE; 964*084fd14fSBrian Behlendorf } 965*084fd14fSBrian Behlendorf 966*084fd14fSBrian Behlendorf zio_interrupt(zio); 967*084fd14fSBrian Behlendorf return; 968fa9e4066Sahrens } 969fa9e4066Sahrens 970f693d300SSteven Hartland ASSERT(zio->io_type == ZIO_TYPE_READ || zio->io_type == ZIO_TYPE_WRITE); 97197e81309SPrakash Surya zio->io_target_timestamp = zio_handle_io_delay(zio); 972f693d300SSteven Hartland 97331d7e8faSGeorge Wilson vb = kmem_alloc(sizeof (vdev_buf_t), KM_SLEEP); 974fa9e4066Sahrens 97531d7e8faSGeorge Wilson vb->vb_io = zio; 97631d7e8faSGeorge Wilson bp = &vb->vb_buf; 977fa9e4066Sahrens 978fa9e4066Sahrens bioinit(bp); 979e14bb325SJeff Bonwick bp->b_flags = B_BUSY | B_NOCACHE | 9808956713aSEric Schrock (zio->io_type == ZIO_TYPE_READ ? B_READ : B_WRITE); 9818956713aSEric Schrock if (!(zio->io_flags & (ZIO_FLAG_IO_RETRY | ZIO_FLAG_TRYHARD))) 9828956713aSEric Schrock bp->b_flags |= B_FAILFAST; 983fa9e4066Sahrens bp->b_bcount = zio->io_size; 984770499e1SDan Kimmel 985770499e1SDan Kimmel if (zio->io_type == ZIO_TYPE_READ) { 986770499e1SDan Kimmel bp->b_un.b_addr = 987770499e1SDan Kimmel abd_borrow_buf(zio->io_abd, zio->io_size); 988770499e1SDan Kimmel } else { 989770499e1SDan Kimmel bp->b_un.b_addr = 990770499e1SDan Kimmel abd_borrow_buf_copy(zio->io_abd, zio->io_size); 991770499e1SDan Kimmel } 992770499e1SDan Kimmel 993fa9e4066Sahrens bp->b_lblkno = lbtodb(zio->io_offset); 994fa9e4066Sahrens bp->b_bufsize = zio->io_size; 995c62757b2SToomas Soome bp->b_iodone = vdev_disk_io_intr; 996fa9e4066Sahrens 997fa88c70fSJerry Jelinek /* 998fa88c70fSJerry Jelinek * In general we would expect ldi_strategy() to return non-zero only 999fa88c70fSJerry Jelinek * because of programming errors, but we've also seen this fail shortly 1000fa88c70fSJerry Jelinek * after a disk dies. 1001fa88c70fSJerry Jelinek */ 1002fa88c70fSJerry Jelinek if (ldi_strategy(dvd->vd_lh, bp) != 0) { 1003fa88c70fSJerry Jelinek zio->io_error = ENXIO; 1004fa88c70fSJerry Jelinek zio_interrupt(zio); 1005fa88c70fSJerry Jelinek } 1006fa9e4066Sahrens } 1007fa9e4066Sahrens 1008e14bb325SJeff Bonwick static void 1009fa9e4066Sahrens vdev_disk_io_done(zio_t *zio) 1010fa9e4066Sahrens { 1011e14bb325SJeff Bonwick vdev_t *vd = zio->io_vd; 1012ea8dc4b6Seschrock 10133d7072f8Seschrock /* 10143d7072f8Seschrock * If the device returned EIO, then attempt a DKIOCSTATE ioctl to see if 10153d7072f8Seschrock * the device has been removed. If this is the case, then we trigger an 10160a4e9518Sgw * asynchronous removal of the device. Otherwise, probe the device and 10171f7ad2e1Sgw * make sure it's still accessible. 10183d7072f8Seschrock */ 10191d713200SEric Schrock if (zio->io_error == EIO && !vd->vdev_remove_wanted) { 10200a4e9518Sgw vdev_disk_t *dvd = vd->vdev_tsd; 1021e14bb325SJeff Bonwick int state = DKIO_NONE; 10220a4e9518Sgw 1023e14bb325SJeff Bonwick if (ldi_ioctl(dvd->vd_lh, DKIOCSTATE, (intptr_t)&state, 1024e14bb325SJeff Bonwick FKIOCTL, kcred, NULL) == 0 && state != DKIO_INSERTED) { 10251d713200SEric Schrock /* 10261d713200SEric Schrock * We post the resource as soon as possible, instead of 10271d713200SEric Schrock * when the async removal actually happens, because the 10281d713200SEric Schrock * DE is using this information to discard previous I/O 10291d713200SEric Schrock * errors. 10301d713200SEric Schrock */ 10311d713200SEric Schrock zfs_post_remove(zio->io_spa, vd); 10323d7072f8Seschrock vd->vdev_remove_wanted = B_TRUE; 10333d7072f8Seschrock spa_async_request(zio->io_spa, SPA_ASYNC_REMOVE); 103498d1cbfeSGeorge Wilson } else if (!vd->vdev_delayed_close) { 103598d1cbfeSGeorge Wilson vd->vdev_delayed_close = B_TRUE; 10363d7072f8Seschrock } 10373d7072f8Seschrock } 1038fa9e4066Sahrens } 1039fa9e4066Sahrens 1040fa9e4066Sahrens vdev_ops_t vdev_disk_ops = { 1041a3874b8bSToomas Soome .vdev_op_open = vdev_disk_open, 1042a3874b8bSToomas Soome .vdev_op_close = vdev_disk_close, 1043a3874b8bSToomas Soome .vdev_op_asize = vdev_default_asize, 1044a3874b8bSToomas Soome .vdev_op_io_start = vdev_disk_io_start, 1045a3874b8bSToomas Soome .vdev_op_io_done = vdev_disk_io_done, 1046a3874b8bSToomas Soome .vdev_op_state_change = NULL, 1047a3874b8bSToomas Soome .vdev_op_need_resilver = NULL, 1048a3874b8bSToomas Soome .vdev_op_hold = vdev_disk_hold, 1049a3874b8bSToomas Soome .vdev_op_rele = vdev_disk_rele, 1050a3874b8bSToomas Soome .vdev_op_remap = NULL, 1051a3874b8bSToomas Soome .vdev_op_xlate = vdev_default_xlate, 1052a3874b8bSToomas Soome .vdev_op_type = VDEV_TYPE_DISK, /* name of this vdev type */ 1053a3874b8bSToomas Soome .vdev_op_leaf = B_TRUE /* leaf vdev */ 1054fa9e4066Sahrens }; 1055e7cbe64fSgw 1056e7cbe64fSgw /* 1057051aabe6Staylor * Given the root disk device devid or pathname, read the label from 1058051aabe6Staylor * the device, and construct a configuration nvlist. 1059e7cbe64fSgw */ 1060f940fbb1SLin Ling int 1061f940fbb1SLin Ling vdev_disk_read_rootlabel(char *devpath, char *devid, nvlist_t **config) 1062e7cbe64fSgw { 1063e7cbe64fSgw ldi_handle_t vd_lh; 1064e7cbe64fSgw vdev_label_t *label; 1065e7cbe64fSgw uint64_t s, size; 1066e7cbe64fSgw int l; 1067051aabe6Staylor ddi_devid_t tmpdevid; 1068f4565e39SLin Ling int error = -1; 1069051aabe6Staylor char *minor_name; 1070e7cbe64fSgw 1071e7cbe64fSgw /* 1072e7cbe64fSgw * Read the device label and build the nvlist. 1073e7cbe64fSgw */ 1074f4565e39SLin Ling if (devid != NULL && ddi_devid_str_decode(devid, &tmpdevid, 1075051aabe6Staylor &minor_name) == 0) { 1076051aabe6Staylor error = ldi_open_by_devid(tmpdevid, minor_name, 10778ad4d6ddSJeff Bonwick FREAD, kcred, &vd_lh, zfs_li); 1078051aabe6Staylor ddi_devid_free(tmpdevid); 1079051aabe6Staylor ddi_devid_str_free(minor_name); 1080051aabe6Staylor } 1081051aabe6Staylor 1082f4565e39SLin Ling if (error && (error = ldi_open_by_name(devpath, FREAD, kcred, &vd_lh, 1083f4565e39SLin Ling zfs_li))) 1084f940fbb1SLin Ling return (error); 1085e7cbe64fSgw 1086bf82a41bSeschrock if (ldi_get_size(vd_lh, &s)) { 1087bf82a41bSeschrock (void) ldi_close(vd_lh, FREAD, kcred); 1088be6fd75aSMatthew Ahrens return (SET_ERROR(EIO)); 1089bf82a41bSeschrock } 1090e7cbe64fSgw 1091e7cbe64fSgw size = P2ALIGN_TYPED(s, sizeof (vdev_label_t), uint64_t); 1092e7cbe64fSgw label = kmem_alloc(sizeof (vdev_label_t), KM_SLEEP); 1093e7cbe64fSgw 109417f1e64aSEric Taylor *config = NULL; 1095e7cbe64fSgw for (l = 0; l < VDEV_LABELS; l++) { 1096e7cbe64fSgw uint64_t offset, state, txg = 0; 1097e7cbe64fSgw 1098e7cbe64fSgw /* read vdev label */ 1099e7cbe64fSgw offset = vdev_label_offset(size, l, 0); 1100810e43b2SBill Pijewski if (vdev_disk_ldi_physio(vd_lh, (caddr_t)label, 11012264ca7fSLin Ling VDEV_SKIP_SIZE + VDEV_PHYS_SIZE, offset, B_READ) != 0) 1102e7cbe64fSgw continue; 1103e7cbe64fSgw 1104e7cbe64fSgw if (nvlist_unpack(label->vl_vdev_phys.vp_nvlist, 1105f940fbb1SLin Ling sizeof (label->vl_vdev_phys.vp_nvlist), config, 0) != 0) { 1106f940fbb1SLin Ling *config = NULL; 1107e7cbe64fSgw continue; 1108e7cbe64fSgw } 1109e7cbe64fSgw 1110f940fbb1SLin Ling if (nvlist_lookup_uint64(*config, ZPOOL_CONFIG_POOL_STATE, 1111e7cbe64fSgw &state) != 0 || state >= POOL_STATE_DESTROYED) { 1112f940fbb1SLin Ling nvlist_free(*config); 1113f940fbb1SLin Ling *config = NULL; 1114e7cbe64fSgw continue; 1115e7cbe64fSgw } 1116e7cbe64fSgw 1117f940fbb1SLin Ling if (nvlist_lookup_uint64(*config, ZPOOL_CONFIG_POOL_TXG, 1118e7cbe64fSgw &txg) != 0 || txg == 0) { 1119f940fbb1SLin Ling nvlist_free(*config); 1120f940fbb1SLin Ling *config = NULL; 1121e7cbe64fSgw continue; 1122e7cbe64fSgw } 1123e7cbe64fSgw 1124e7cbe64fSgw break; 1125e7cbe64fSgw } 1126e7cbe64fSgw 1127e7cbe64fSgw kmem_free(label, sizeof (vdev_label_t)); 1128bf82a41bSeschrock (void) ldi_close(vd_lh, FREAD, kcred); 112917f1e64aSEric Taylor if (*config == NULL) 1130be6fd75aSMatthew Ahrens error = SET_ERROR(EIDRM); 1131bf82a41bSeschrock 1132f940fbb1SLin Ling return (error); 1133e7cbe64fSgw } 1134