xref: /illumos-gate/usr/src/uts/common/fs/zfs/vdev_disk.c (revision 30c304d9)
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.
251b500975SMike Gerdts  * Copyright 2020 Joyent, Inc.
26*30c304d9SJoshua M. Clulow  * Copyright 2020 Joshua M. Clulow <josh@sysmgr.org>
27fa9e4066Sahrens  */
28fa9e4066Sahrens 
29fa9e4066Sahrens #include <sys/zfs_context.h>
30dcba9f3fSGeorge Wilson #include <sys/spa_impl.h>
31e7cbe64fSgw #include <sys/refcount.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>
40ac04831dSMike Gerdts #include <sys/ddi.h>
41fa9e4066Sahrens 
42fb05b94aSJerry Jelinek /*
43fc5c75cfSJerry Jelinek  * Tunable to disable TRIM in case we're using a problematic SSD.
44fb05b94aSJerry Jelinek  */
45fc5c75cfSJerry Jelinek uint_t zfs_no_trim = 0;
46fb05b94aSJerry Jelinek 
47f8fdf681SPrakash Surya /*
48f8fdf681SPrakash Surya  * Tunable parameter for debugging or performance analysis. Setting this
49f8fdf681SPrakash Surya  * will cause pool corruption on power loss if a volatile out-of-order
50f8fdf681SPrakash Surya  * write cache is enabled.
51f8fdf681SPrakash Surya  */
52f8fdf681SPrakash Surya boolean_t zfs_nocacheflush = B_FALSE;
53f8fdf681SPrakash Surya 
54fa9e4066Sahrens /*
55fa9e4066Sahrens  * Virtual device vector for disks.
56fa9e4066Sahrens  */
57fa9e4066Sahrens 
58fa9e4066Sahrens extern ldi_ident_t zfs_li;
59fa9e4066Sahrens 
6039cddb10SJoshua M. Clulow static void vdev_disk_close(vdev_t *);
6139cddb10SJoshua M. Clulow 
62ac04831dSMike Gerdts typedef struct vdev_disk {
63ac04831dSMike Gerdts 	ddi_devid_t	vd_devid;
64ac04831dSMike Gerdts 	char		*vd_minor;
65ac04831dSMike Gerdts 	ldi_handle_t	vd_lh;
66ac04831dSMike Gerdts 	list_t		vd_ldi_cbs;
67ac04831dSMike Gerdts 	boolean_t	vd_ldi_offline;
68ac04831dSMike Gerdts } vdev_disk_t;
69ac04831dSMike Gerdts 
70ac04831dSMike Gerdts typedef struct vdev_disk_buf {
71ac04831dSMike Gerdts 	buf_t	vdb_buf;
72ac04831dSMike Gerdts 	zio_t	*vdb_io;
73ac04831dSMike Gerdts } vdev_disk_buf_t;
74ac04831dSMike Gerdts 
7539cddb10SJoshua M. Clulow typedef struct vdev_disk_ldi_cb {
7639cddb10SJoshua M. Clulow 	list_node_t		lcb_next;
7739cddb10SJoshua M. Clulow 	ldi_callback_id_t	lcb_id;
7839cddb10SJoshua M. Clulow } vdev_disk_ldi_cb_t;
7939cddb10SJoshua M. Clulow 
806fe4f300SPavel Zakharov /*
816fe4f300SPavel Zakharov  * Bypass the devid when opening a disk vdev.
826fe4f300SPavel Zakharov  * There have been issues where the devids of several devices were shuffled,
836fe4f300SPavel Zakharov  * causing pool open failures. Note, that this flag is intended to be used
846fe4f300SPavel Zakharov  * for pool recovery only.
856fe4f300SPavel Zakharov  *
866fe4f300SPavel Zakharov  * Note that if a pool is imported with the devids bypassed, all its vdevs will
876fe4f300SPavel Zakharov  * cease storing devid information permanently. In practice, the devid is rarely
886fe4f300SPavel Zakharov  * useful as vdev paths do not tend to change unless the hardware is
896fe4f300SPavel Zakharov  * reconfigured. That said, if the paths do change and a pool fails to open
906fe4f300SPavel Zakharov  * automatically at boot, a simple zpool import should re-scan the paths and fix
916fe4f300SPavel Zakharov  * the issue.
926fe4f300SPavel Zakharov  */
936fe4f300SPavel Zakharov boolean_t vdev_disk_bypass_devid = B_FALSE;
946fe4f300SPavel Zakharov 
9539cddb10SJoshua M. Clulow static void
vdev_disk_alloc(vdev_t * vd)9639cddb10SJoshua M. Clulow vdev_disk_alloc(vdev_t *vd)
9739cddb10SJoshua M. Clulow {
9839cddb10SJoshua M. Clulow 	vdev_disk_t *dvd;
9939cddb10SJoshua M. Clulow 
10039cddb10SJoshua M. Clulow 	dvd = vd->vdev_tsd = kmem_zalloc(sizeof (vdev_disk_t), KM_SLEEP);
10139cddb10SJoshua M. Clulow 	/*
10239cddb10SJoshua M. Clulow 	 * Create the LDI event callback list.
10339cddb10SJoshua M. Clulow 	 */
10439cddb10SJoshua M. Clulow 	list_create(&dvd->vd_ldi_cbs, sizeof (vdev_disk_ldi_cb_t),
10539cddb10SJoshua M. Clulow 	    offsetof(vdev_disk_ldi_cb_t, lcb_next));
10639cddb10SJoshua M. Clulow }
10739cddb10SJoshua M. Clulow 
10839cddb10SJoshua M. Clulow static void
vdev_disk_free(vdev_t * vd)10939cddb10SJoshua M. Clulow vdev_disk_free(vdev_t *vd)
11039cddb10SJoshua M. Clulow {
11139cddb10SJoshua M. Clulow 	vdev_disk_t *dvd = vd->vdev_tsd;
11239cddb10SJoshua M. Clulow 	vdev_disk_ldi_cb_t *lcb;
11339cddb10SJoshua M. Clulow 
11439cddb10SJoshua M. Clulow 	if (dvd == NULL)
11539cddb10SJoshua M. Clulow 		return;
11639cddb10SJoshua M. Clulow 
11739cddb10SJoshua M. Clulow 	/*
11839cddb10SJoshua M. Clulow 	 * We have already closed the LDI handle. Clean up the LDI event
11939cddb10SJoshua M. Clulow 	 * callbacks and free vd->vdev_tsd.
12039cddb10SJoshua M. Clulow 	 */
12139cddb10SJoshua M. Clulow 	while ((lcb = list_head(&dvd->vd_ldi_cbs)) != NULL) {
12239cddb10SJoshua M. Clulow 		list_remove(&dvd->vd_ldi_cbs, lcb);
12339cddb10SJoshua M. Clulow 		(void) ldi_ev_remove_callbacks(lcb->lcb_id);
12439cddb10SJoshua M. Clulow 		kmem_free(lcb, sizeof (vdev_disk_ldi_cb_t));
12539cddb10SJoshua M. Clulow 	}
12639cddb10SJoshua M. Clulow 	list_destroy(&dvd->vd_ldi_cbs);
12739cddb10SJoshua M. Clulow 	kmem_free(dvd, sizeof (vdev_disk_t));
12839cddb10SJoshua M. Clulow 	vd->vdev_tsd = NULL;
12939cddb10SJoshua M. Clulow }
13039cddb10SJoshua M. Clulow 
13139cddb10SJoshua M. Clulow static int
vdev_disk_off_notify(ldi_handle_t lh __unused,ldi_ev_cookie_t ecookie,void * arg,void * ev_data __unused)1321b500975SMike Gerdts vdev_disk_off_notify(ldi_handle_t lh __unused, ldi_ev_cookie_t ecookie,
1331b500975SMike Gerdts     void *arg, void *ev_data __unused)
13439cddb10SJoshua M. Clulow {
13539cddb10SJoshua M. Clulow 	vdev_t *vd = (vdev_t *)arg;
13639cddb10SJoshua M. Clulow 	vdev_disk_t *dvd = vd->vdev_tsd;
13739cddb10SJoshua M. Clulow 
13839cddb10SJoshua M. Clulow 	/*
13939cddb10SJoshua M. Clulow 	 * Ignore events other than offline.
14039cddb10SJoshua M. Clulow 	 */
14139cddb10SJoshua M. Clulow 	if (strcmp(ldi_ev_get_type(ecookie), LDI_EV_OFFLINE) != 0)
14239cddb10SJoshua M. Clulow 		return (LDI_EV_SUCCESS);
14339cddb10SJoshua M. Clulow 
14439cddb10SJoshua M. Clulow 	/*
1451b500975SMike Gerdts 	 * Tell any new threads that stumble upon this vdev that they should not
1461b500975SMike Gerdts 	 * try to do I/O.
14739cddb10SJoshua M. Clulow 	 */
14839cddb10SJoshua M. Clulow 	dvd->vd_ldi_offline = B_TRUE;
14939cddb10SJoshua M. Clulow 
15039cddb10SJoshua M. Clulow 	/*
1511b500975SMike Gerdts 	 * Request that the spa_async_thread mark the device as REMOVED and
1521b500975SMike Gerdts 	 * notify FMA of the removal.  This should also trigger a vdev_close()
1531b500975SMike Gerdts 	 * in the async thread.
15439cddb10SJoshua M. Clulow 	 */
15539cddb10SJoshua M. Clulow 	zfs_post_remove(vd->vdev_spa, vd);
15639cddb10SJoshua M. Clulow 	vd->vdev_remove_wanted = B_TRUE;
15739cddb10SJoshua M. Clulow 	spa_async_request(vd->vdev_spa, SPA_ASYNC_REMOVE);
15839cddb10SJoshua M. Clulow 
15939cddb10SJoshua M. Clulow 	return (LDI_EV_SUCCESS);
16039cddb10SJoshua M. Clulow }
16139cddb10SJoshua M. Clulow 
16239cddb10SJoshua M. Clulow static void
vdev_disk_off_finalize(ldi_handle_t lh __unused,ldi_ev_cookie_t ecookie,int ldi_result,void * arg,void * ev_data __unused)1631b500975SMike Gerdts vdev_disk_off_finalize(ldi_handle_t lh __unused, ldi_ev_cookie_t ecookie,
1641b500975SMike Gerdts     int ldi_result, void *arg, void *ev_data __unused)
16539cddb10SJoshua M. Clulow {
16639cddb10SJoshua M. Clulow 	vdev_t *vd = (vdev_t *)arg;
16739cddb10SJoshua M. Clulow 
16839cddb10SJoshua M. Clulow 	/*
16939cddb10SJoshua M. Clulow 	 * Ignore events other than offline.
17039cddb10SJoshua M. Clulow 	 */
17139cddb10SJoshua M. Clulow 	if (strcmp(ldi_ev_get_type(ecookie), LDI_EV_OFFLINE) != 0)
17239cddb10SJoshua M. Clulow 		return;
17339cddb10SJoshua M. Clulow 
17439cddb10SJoshua M. Clulow 	/*
17539cddb10SJoshua M. Clulow 	 * Request that the vdev be reopened if the offline state change was
17639cddb10SJoshua M. Clulow 	 * unsuccessful.
17739cddb10SJoshua M. Clulow 	 */
17839cddb10SJoshua M. Clulow 	if (ldi_result != LDI_EV_SUCCESS) {
17939cddb10SJoshua M. Clulow 		vd->vdev_probe_wanted = B_TRUE;
18039cddb10SJoshua M. Clulow 		spa_async_request(vd->vdev_spa, SPA_ASYNC_PROBE);
18139cddb10SJoshua M. Clulow 	}
18239cddb10SJoshua M. Clulow }
18339cddb10SJoshua M. Clulow 
18439cddb10SJoshua M. Clulow static ldi_ev_callback_t vdev_disk_off_callb = {
18539cddb10SJoshua M. Clulow 	.cb_vers = LDI_EV_CB_VERS,
18639cddb10SJoshua M. Clulow 	.cb_notify = vdev_disk_off_notify,
18739cddb10SJoshua M. Clulow 	.cb_finalize = vdev_disk_off_finalize
18839cddb10SJoshua M. Clulow };
18939cddb10SJoshua M. Clulow 
19039cddb10SJoshua M. Clulow static void
vdev_disk_dgrd_finalize(ldi_handle_t lh __unused,ldi_ev_cookie_t ecookie,int ldi_result,void * arg,void * ev_data __unused)1911b500975SMike Gerdts vdev_disk_dgrd_finalize(ldi_handle_t lh __unused, ldi_ev_cookie_t ecookie,
1921b500975SMike Gerdts     int ldi_result, void *arg, void *ev_data __unused)
19339cddb10SJoshua M. Clulow {
19439cddb10SJoshua M. Clulow 	vdev_t *vd = (vdev_t *)arg;
19539cddb10SJoshua M. Clulow 
19639cddb10SJoshua M. Clulow 	/*
19739cddb10SJoshua M. Clulow 	 * Ignore events other than degrade.
19839cddb10SJoshua M. Clulow 	 */
19939cddb10SJoshua M. Clulow 	if (strcmp(ldi_ev_get_type(ecookie), LDI_EV_DEGRADE) != 0)
20039cddb10SJoshua M. Clulow 		return;
20139cddb10SJoshua M. Clulow 
20239cddb10SJoshua M. Clulow 	/*
20339cddb10SJoshua M. Clulow 	 * Degrade events always succeed. Mark the vdev as degraded.
20439cddb10SJoshua M. Clulow 	 * This status is purely informative for the user.
20539cddb10SJoshua M. Clulow 	 */
20639cddb10SJoshua M. Clulow 	(void) vdev_degrade(vd->vdev_spa, vd->vdev_guid, 0);
20739cddb10SJoshua M. Clulow }
20839cddb10SJoshua M. Clulow 
20939cddb10SJoshua M. Clulow static ldi_ev_callback_t vdev_disk_dgrd_callb = {
21039cddb10SJoshua M. Clulow 	.cb_vers = LDI_EV_CB_VERS,
21139cddb10SJoshua M. Clulow 	.cb_notify = NULL,
21239cddb10SJoshua M. Clulow 	.cb_finalize = vdev_disk_dgrd_finalize
21339cddb10SJoshua M. Clulow };
21439cddb10SJoshua M. Clulow 
215dcba9f3fSGeorge Wilson static void
vdev_disk_hold(vdev_t * vd)216dcba9f3fSGeorge Wilson vdev_disk_hold(vdev_t *vd)
217dcba9f3fSGeorge Wilson {
218dcba9f3fSGeorge Wilson 	ddi_devid_t devid;
219dcba9f3fSGeorge Wilson 	char *minor;
220dcba9f3fSGeorge Wilson 
221dcba9f3fSGeorge Wilson 	ASSERT(spa_config_held(vd->vdev_spa, SCL_STATE, RW_WRITER));
222dcba9f3fSGeorge Wilson 
223dcba9f3fSGeorge Wilson 	/*
224dcba9f3fSGeorge Wilson 	 * We must have a pathname, and it must be absolute.
225dcba9f3fSGeorge Wilson 	 */
226dcba9f3fSGeorge Wilson 	if (vd->vdev_path == NULL || vd->vdev_path[0] != '/')
227dcba9f3fSGeorge Wilson 		return;
228dcba9f3fSGeorge Wilson 
229dcba9f3fSGeorge Wilson 	/*
230dcba9f3fSGeorge Wilson 	 * Only prefetch path and devid info if the device has
231dcba9f3fSGeorge Wilson 	 * never been opened.
232dcba9f3fSGeorge Wilson 	 */
233dcba9f3fSGeorge Wilson 	if (vd->vdev_tsd != NULL)
234dcba9f3fSGeorge Wilson 		return;
235dcba9f3fSGeorge Wilson 
236dcba9f3fSGeorge Wilson 	if (vd->vdev_wholedisk == -1ULL) {
237dcba9f3fSGeorge Wilson 		size_t len = strlen(vd->vdev_path) + 3;
238dcba9f3fSGeorge Wilson 		char *buf = kmem_alloc(len, KM_SLEEP);
239dcba9f3fSGeorge Wilson 
240dcba9f3fSGeorge Wilson 		(void) snprintf(buf, len, "%ss0", vd->vdev_path);
241dcba9f3fSGeorge Wilson 
242dcba9f3fSGeorge Wilson 		(void) ldi_vp_from_name(buf, &vd->vdev_name_vp);
243dcba9f3fSGeorge Wilson 		kmem_free(buf, len);
244dcba9f3fSGeorge Wilson 	}
245dcba9f3fSGeorge Wilson 
246dcba9f3fSGeorge Wilson 	if (vd->vdev_name_vp == NULL)
247dcba9f3fSGeorge Wilson 		(void) ldi_vp_from_name(vd->vdev_path, &vd->vdev_name_vp);
248dcba9f3fSGeorge Wilson 
249dcba9f3fSGeorge Wilson 	if (vd->vdev_devid != NULL &&
250dcba9f3fSGeorge Wilson 	    ddi_devid_str_decode(vd->vdev_devid, &devid, &minor) == 0) {
251dcba9f3fSGeorge Wilson 		(void) ldi_vp_from_devid(devid, minor, &vd->vdev_devid_vp);
252dcba9f3fSGeorge Wilson 		ddi_devid_str_free(minor);
253dcba9f3fSGeorge Wilson 		ddi_devid_free(devid);
254dcba9f3fSGeorge Wilson 	}
255dcba9f3fSGeorge Wilson }
256dcba9f3fSGeorge Wilson 
257dcba9f3fSGeorge Wilson static void
vdev_disk_rele(vdev_t * vd)258dcba9f3fSGeorge Wilson vdev_disk_rele(vdev_t *vd)
259dcba9f3fSGeorge Wilson {
260dcba9f3fSGeorge Wilson 	ASSERT(spa_config_held(vd->vdev_spa, SCL_STATE, RW_WRITER));
261dcba9f3fSGeorge Wilson 
262dcba9f3fSGeorge Wilson 	if (vd->vdev_name_vp) {
263dcba9f3fSGeorge Wilson 		VN_RELE_ASYNC(vd->vdev_name_vp,
264dcba9f3fSGeorge Wilson 		    dsl_pool_vnrele_taskq(vd->vdev_spa->spa_dsl_pool));
265dcba9f3fSGeorge Wilson 		vd->vdev_name_vp = NULL;
266dcba9f3fSGeorge Wilson 	}
267dcba9f3fSGeorge Wilson 	if (vd->vdev_devid_vp) {
268dcba9f3fSGeorge Wilson 		VN_RELE_ASYNC(vd->vdev_devid_vp,
269dcba9f3fSGeorge Wilson 		    dsl_pool_vnrele_taskq(vd->vdev_spa->spa_dsl_pool));
270dcba9f3fSGeorge Wilson 		vd->vdev_devid_vp = NULL;
271dcba9f3fSGeorge Wilson 	}
272dcba9f3fSGeorge Wilson }
273dcba9f3fSGeorge Wilson 
274a5b57771SDan McDonald /*
275a5b57771SDan McDonald  * We want to be loud in DEBUG kernels when DKIOCGMEDIAINFOEXT fails, or when
276a5b57771SDan McDonald  * even a fallback to DKIOCGMEDIAINFO fails.
277a5b57771SDan McDonald  */
278a5b57771SDan McDonald #ifdef DEBUG
279a5b57771SDan McDonald #define	VDEV_DEBUG(...)	cmn_err(CE_NOTE, __VA_ARGS__)
280a5b57771SDan McDonald #else
281a5b57771SDan McDonald #define	VDEV_DEBUG(...)	/* Nothing... */
282a5b57771SDan McDonald #endif
283a5b57771SDan McDonald 
284fa9e4066Sahrens static int
vdev_disk_open(vdev_t * vd,uint64_t * psize,uint64_t * max_psize,uint64_t * ashift)2854263d13fSGeorge Wilson vdev_disk_open(vdev_t *vd, uint64_t *psize, uint64_t *max_psize,
2864263d13fSGeorge Wilson     uint64_t *ashift)
287fa9e4066Sahrens {
2888ad4d6ddSJeff Bonwick 	spa_t *spa = vd->vdev_spa;
28939cddb10SJoshua M. Clulow 	vdev_disk_t *dvd = vd->vdev_tsd;
29039cddb10SJoshua M. Clulow 	ldi_ev_cookie_t ecookie;
29139cddb10SJoshua M. Clulow 	vdev_disk_ldi_cb_t *lcb;
292a5b57771SDan McDonald 	union {
293a5b57771SDan McDonald 		struct dk_minfo_ext ude;
294a5b57771SDan McDonald 		struct dk_minfo ud;
295a5b57771SDan McDonald 	} dks;
296a5b57771SDan McDonald 	struct dk_minfo_ext *dkmext = &dks.ude;
297a5b57771SDan McDonald 	struct dk_minfo *dkm = &dks.ud;
298084fd14fSBrian Behlendorf 	int error, can_free;
299e14bb325SJeff Bonwick 	dev_t dev;
300e14bb325SJeff Bonwick 	int otyp;
301fb02ae02SGeorge Wilson 	boolean_t validate_devid = B_FALSE;
302a5b57771SDan McDonald 	uint64_t capacity = 0, blksz = 0, pbsize;
303fa9e4066Sahrens 
304fa9e4066Sahrens 	/*
305fa9e4066Sahrens 	 * We must have a pathname, and it must be absolute.
306fa9e4066Sahrens 	 */
307fa9e4066Sahrens 	if (vd->vdev_path == NULL || vd->vdev_path[0] != '/') {
308fa9e4066Sahrens 		vd->vdev_stat.vs_aux = VDEV_AUX_BAD_LABEL;
309be6fd75aSMatthew Ahrens 		return (SET_ERROR(EINVAL));
310fa9e4066Sahrens 	}
311fa9e4066Sahrens 
312095bcd66SGeorge Wilson 	/*
313095bcd66SGeorge Wilson 	 * Reopen the device if it's not currently open. Otherwise,
314095bcd66SGeorge Wilson 	 * just update the physical size of the device.
315095bcd66SGeorge Wilson 	 */
31639cddb10SJoshua M. Clulow 	if (dvd != NULL) {
3171b500975SMike Gerdts 		ASSERT(vd->vdev_reopening);
3181b500975SMike Gerdts 		goto skip_open;
319095bcd66SGeorge Wilson 	}
320095bcd66SGeorge Wilson 
32139cddb10SJoshua M. Clulow 	/*
32239cddb10SJoshua M. Clulow 	 * Create vd->vdev_tsd.
32339cddb10SJoshua M. Clulow 	 */
32439cddb10SJoshua M. Clulow 	vdev_disk_alloc(vd);
32539cddb10SJoshua M. Clulow 	dvd = vd->vdev_tsd;
326fa9e4066Sahrens 
3276fe4f300SPavel Zakharov 	/*
3286fe4f300SPavel Zakharov 	 * Allow bypassing the devid.
3296fe4f300SPavel Zakharov 	 */
3306fe4f300SPavel Zakharov 	if (vd->vdev_devid != NULL && vdev_disk_bypass_devid) {
3316fe4f300SPavel Zakharov 		vdev_dbgmsg(vd, "vdev_disk_open, devid %s bypassed",
3326fe4f300SPavel Zakharov 		    vd->vdev_devid);
3336fe4f300SPavel Zakharov 		spa_strfree(vd->vdev_devid);
3346fe4f300SPavel Zakharov 		vd->vdev_devid = NULL;
3356fe4f300SPavel Zakharov 	}
3366fe4f300SPavel Zakharov 
337fa9e4066Sahrens 	/*
338fa9e4066Sahrens 	 * When opening a disk device, we want to preserve the user's original
339fa9e4066Sahrens 	 * intent.  We always want to open the device by the path the user gave
3401724dc7bSJoshua M. Clulow 	 * us, even if it is one of multiple paths to the same device.  But we
341fa9e4066Sahrens 	 * also want to be able to survive disks being removed/recabled.
342fa9e4066Sahrens 	 * Therefore the sequence of opening devices is:
343fa9e4066Sahrens 	 *
344afefbcddSeschrock 	 * 1. Try opening the device by path.  For legacy pools without the
345afefbcddSeschrock 	 *    'whole_disk' property, attempt to fix the path by appending 's0'.
346fa9e4066Sahrens 	 *
347fa9e4066Sahrens 	 * 2. If the devid of the device matches the stored value, return
348fa9e4066Sahrens 	 *    success.
349fa9e4066Sahrens 	 *
350fa9e4066Sahrens 	 * 3. Otherwise, the device may have moved.  Try opening the device
351fa9e4066Sahrens 	 *    by the devid instead.
352fa9e4066Sahrens 	 */
353fa9e4066Sahrens 	if (vd->vdev_devid != NULL) {
354fa9e4066Sahrens 		if (ddi_devid_str_decode(vd->vdev_devid, &dvd->vd_devid,
355fa9e4066Sahrens 		    &dvd->vd_minor) != 0) {
356fa9e4066Sahrens 			vd->vdev_stat.vs_aux = VDEV_AUX_BAD_LABEL;
3573ee8c80cSPavel Zakharov 			vdev_dbgmsg(vd, "vdev_disk_open: invalid "
3583ee8c80cSPavel Zakharov 			    "vdev_devid '%s'", vd->vdev_devid);
359be6fd75aSMatthew Ahrens 			return (SET_ERROR(EINVAL));
360fa9e4066Sahrens 		}
361fa9e4066Sahrens 	}
362fa9e4066Sahrens 
363fa9e4066Sahrens 	error = EINVAL;		/* presume failure */
364fa9e4066Sahrens 
365095bcd66SGeorge Wilson 	if (vd->vdev_path != NULL) {
366afefbcddSeschrock 		if (vd->vdev_wholedisk == -1ULL) {
367afefbcddSeschrock 			size_t len = strlen(vd->vdev_path) + 3;
368afefbcddSeschrock 			char *buf = kmem_alloc(len, KM_SLEEP);
369afefbcddSeschrock 
370afefbcddSeschrock 			(void) snprintf(buf, len, "%ss0", vd->vdev_path);
371afefbcddSeschrock 
37239cddb10SJoshua M. Clulow 			error = ldi_open_by_name(buf, spa_mode(spa), kcred,
37339cddb10SJoshua M. Clulow 			    &dvd->vd_lh, zfs_li);
37439cddb10SJoshua M. Clulow 			if (error == 0) {
375afefbcddSeschrock 				spa_strfree(vd->vdev_path);
376afefbcddSeschrock 				vd->vdev_path = buf;
377afefbcddSeschrock 				vd->vdev_wholedisk = 1ULL;
378afefbcddSeschrock 			} else {
379afefbcddSeschrock 				kmem_free(buf, len);
380afefbcddSeschrock 			}
381afefbcddSeschrock 		}
382fa9e4066Sahrens 
38339cddb10SJoshua M. Clulow 		/*
38439cddb10SJoshua M. Clulow 		 * If we have not yet opened the device, try to open it by the
38539cddb10SJoshua M. Clulow 		 * specified path.
38639cddb10SJoshua M. Clulow 		 */
38739cddb10SJoshua M. Clulow 		if (error != 0) {
38839cddb10SJoshua M. Clulow 			error = ldi_open_by_name(vd->vdev_path, spa_mode(spa),
38939cddb10SJoshua M. Clulow 			    kcred, &dvd->vd_lh, zfs_li);
39039cddb10SJoshua M. Clulow 		}
391fa9e4066Sahrens 
392fa9e4066Sahrens 		/*
393fa9e4066Sahrens 		 * Compare the devid to the stored value.
394fa9e4066Sahrens 		 */
3956af23589SJoshua M. Clulow 		if (error == 0 && vd->vdev_devid != NULL) {
3966af23589SJoshua M. Clulow 			ddi_devid_t devid = NULL;
3976af23589SJoshua M. Clulow 
3986af23589SJoshua M. Clulow 			if (ldi_get_devid(dvd->vd_lh, &devid) != 0) {
3996af23589SJoshua M. Clulow 				/*
4006af23589SJoshua M. Clulow 				 * We expected a devid on this device but it no
4016af23589SJoshua M. Clulow 				 * longer appears to have one.  The validation
4026af23589SJoshua M. Clulow 				 * step may need to remove it from the
4036af23589SJoshua M. Clulow 				 * configuration.
4046af23589SJoshua M. Clulow 				 */
4056af23589SJoshua M. Clulow 				validate_devid = B_TRUE;
4066af23589SJoshua M. Clulow 
4076af23589SJoshua M. Clulow 			} else if (ddi_devid_compare(devid, dvd->vd_devid) !=
4086af23589SJoshua M. Clulow 			    0) {
4096fe4f300SPavel Zakharov 				/*
4106fe4f300SPavel Zakharov 				 * A mismatch here is unexpected, log it.
4116fe4f300SPavel Zakharov 				 */
4126fe4f300SPavel Zakharov 				char *devid_str = ddi_devid_str_encode(devid,
4136fe4f300SPavel Zakharov 				    dvd->vd_minor);
4146fe4f300SPavel Zakharov 				vdev_dbgmsg(vd, "vdev_disk_open: devid "
4156fe4f300SPavel Zakharov 				    "mismatch: %s != %s", vd->vdev_devid,
4166fe4f300SPavel Zakharov 				    devid_str);
4176fe4f300SPavel Zakharov 				cmn_err(CE_NOTE, "vdev_disk_open %s: devid "
4186fe4f300SPavel Zakharov 				    "mismatch: %s != %s", vd->vdev_path,
4196fe4f300SPavel Zakharov 				    vd->vdev_devid, devid_str);
4206fe4f300SPavel Zakharov 				ddi_devid_str_free(devid_str);
4216fe4f300SPavel Zakharov 
422be6fd75aSMatthew Ahrens 				error = SET_ERROR(EINVAL);
4238ad4d6ddSJeff Bonwick 				(void) ldi_close(dvd->vd_lh, spa_mode(spa),
4248ad4d6ddSJeff Bonwick 				    kcred);
425fa9e4066Sahrens 				dvd->vd_lh = NULL;
426fa9e4066Sahrens 			}
4276af23589SJoshua M. Clulow 
4286af23589SJoshua M. Clulow 			if (devid != NULL) {
4296af23589SJoshua M. Clulow 				ddi_devid_free(devid);
4306af23589SJoshua M. Clulow 			}
431fa9e4066Sahrens 		}
432afefbcddSeschrock 
433afefbcddSeschrock 		/*
434afefbcddSeschrock 		 * If we succeeded in opening the device, but 'vdev_wholedisk'
435afefbcddSeschrock 		 * is not yet set, then this must be a slice.
436afefbcddSeschrock 		 */
437afefbcddSeschrock 		if (error == 0 && vd->vdev_wholedisk == -1ULL)
438afefbcddSeschrock 			vd->vdev_wholedisk = 0;
439fa9e4066Sahrens 	}
440fa9e4066Sahrens 
441fa9e4066Sahrens 	/*
442fa9e4066Sahrens 	 * If we were unable to open by path, or the devid check fails, open by
443fa9e4066Sahrens 	 * devid instead.
444fa9e4066Sahrens 	 */
445fb02ae02SGeorge Wilson 	if (error != 0 && vd->vdev_devid != NULL) {
446fa9e4066Sahrens 		error = ldi_open_by_devid(dvd->vd_devid, dvd->vd_minor,
4478ad4d6ddSJeff Bonwick 		    spa_mode(spa), kcred, &dvd->vd_lh, zfs_li);
4486fe4f300SPavel Zakharov 		if (error != 0) {
4496fe4f300SPavel Zakharov 			vdev_dbgmsg(vd, "Failed to open by devid (%s)",
4506fe4f300SPavel Zakharov 			    vd->vdev_devid);
4516fe4f300SPavel Zakharov 		}
452fb02ae02SGeorge Wilson 	}
453fa9e4066Sahrens 
4543d7072f8Seschrock 	/*
4553d7072f8Seschrock 	 * If all else fails, then try opening by physical path (if available)
4563d7072f8Seschrock 	 * or the logical path (if we failed due to the devid check).  While not
4573d7072f8Seschrock 	 * as reliable as the devid, this will give us something, and the higher
4583d7072f8Seschrock 	 * level vdev validation will prevent us from opening the wrong device.
4593d7072f8Seschrock 	 */
4606af23589SJoshua M. Clulow 	if (error != 0) {
4616af23589SJoshua M. Clulow 		validate_devid = B_TRUE;
462fb02ae02SGeorge Wilson 
4633d7072f8Seschrock 		if (vd->vdev_physpath != NULL &&
4646af23589SJoshua M. Clulow 		    (dev = ddi_pathname_to_dev_t(vd->vdev_physpath)) != NODEV) {
4658ad4d6ddSJeff Bonwick 			error = ldi_open_by_dev(&dev, OTYP_BLK, spa_mode(spa),
4663d7072f8Seschrock 			    kcred, &dvd->vd_lh, zfs_li);
4676af23589SJoshua M. Clulow 		}
4683d7072f8Seschrock 
4693d7072f8Seschrock 		/*
4703d7072f8Seschrock 		 * Note that we don't support the legacy auto-wholedisk support
4713d7072f8Seschrock 		 * as above.  This hasn't been used in a very long time and we
4723d7072f8Seschrock 		 * don't need to propagate its oddities to this edge condition.
4733d7072f8Seschrock 		 */
4746af23589SJoshua M. Clulow 		if (error != 0 && vd->vdev_path != NULL) {
4758ad4d6ddSJeff Bonwick 			error = ldi_open_by_name(vd->vdev_path, spa_mode(spa),
4768ad4d6ddSJeff Bonwick 			    kcred, &dvd->vd_lh, zfs_li);
4776af23589SJoshua M. Clulow 		}
4783d7072f8Seschrock 	}
4793d7072f8Seschrock 
480*30c304d9SJoshua M. Clulow 	/*
481*30c304d9SJoshua M. Clulow 	 * If this is early in boot, a sweep of available block devices may
482*30c304d9SJoshua M. Clulow 	 * locate an alternative path that we can try.
483*30c304d9SJoshua M. Clulow 	 */
484*30c304d9SJoshua M. Clulow 	if (error != 0) {
485*30c304d9SJoshua M. Clulow 		const char *altdevpath = vdev_disk_preroot_lookup(
486*30c304d9SJoshua M. Clulow 		    spa_guid(spa), vd->vdev_guid);
487*30c304d9SJoshua M. Clulow 
488*30c304d9SJoshua M. Clulow 		if (altdevpath != NULL) {
489*30c304d9SJoshua M. Clulow 			vdev_dbgmsg(vd, "Trying alternate preroot path (%s)",
490*30c304d9SJoshua M. Clulow 			    altdevpath);
491*30c304d9SJoshua M. Clulow 
492*30c304d9SJoshua M. Clulow 			validate_devid = B_TRUE;
493*30c304d9SJoshua M. Clulow 
494*30c304d9SJoshua M. Clulow 			if ((error = ldi_open_by_name((char *)altdevpath,
495*30c304d9SJoshua M. Clulow 			    spa_mode(spa), kcred, &dvd->vd_lh, zfs_li)) != 0) {
496*30c304d9SJoshua M. Clulow 				vdev_dbgmsg(vd, "Failed to open by preroot "
497*30c304d9SJoshua M. Clulow 				    "path (%s)", altdevpath);
498*30c304d9SJoshua M. Clulow 			}
499*30c304d9SJoshua M. Clulow 		}
500*30c304d9SJoshua M. Clulow 	}
501*30c304d9SJoshua M. Clulow 
5026af23589SJoshua M. Clulow 	if (error != 0) {
503fa9e4066Sahrens 		vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED;
5043ee8c80cSPavel Zakharov 		vdev_dbgmsg(vd, "vdev_disk_open: failed to open [error=%d]",
5053ee8c80cSPavel Zakharov 		    error);
506fa9e4066Sahrens 		return (error);
507e14bb325SJeff Bonwick 	}
508fa9e4066Sahrens 
509fb02ae02SGeorge Wilson 	/*
510fb02ae02SGeorge Wilson 	 * Now that the device has been successfully opened, update the devid
511fb02ae02SGeorge Wilson 	 * if necessary.
512fb02ae02SGeorge Wilson 	 */
5136af23589SJoshua M. Clulow 	if (validate_devid) {
5146af23589SJoshua M. Clulow 		ddi_devid_t devid = NULL;
5156af23589SJoshua M. Clulow 		char *minorname = NULL;
5166af23589SJoshua M. Clulow 		char *vd_devid = NULL;
5176af23589SJoshua M. Clulow 		boolean_t remove = B_FALSE, update = B_FALSE;
5186af23589SJoshua M. Clulow 
5196af23589SJoshua M. Clulow 		/*
5206af23589SJoshua M. Clulow 		 * Get the current devid and minor name for the device we
5216af23589SJoshua M. Clulow 		 * opened.
5226af23589SJoshua M. Clulow 		 */
5236af23589SJoshua M. Clulow 		if (ldi_get_devid(dvd->vd_lh, &devid) != 0 ||
5246af23589SJoshua M. Clulow 		    ldi_get_minor_name(dvd->vd_lh, &minorname) != 0) {
5256af23589SJoshua M. Clulow 			/*
5266af23589SJoshua M. Clulow 			 * If we are unable to get the devid or the minor name
5276af23589SJoshua M. Clulow 			 * for the device, we need to remove them from the
5286af23589SJoshua M. Clulow 			 * configuration to prevent potential inconsistencies.
5296af23589SJoshua M. Clulow 			 */
5306af23589SJoshua M. Clulow 			if (dvd->vd_minor != NULL || dvd->vd_devid != NULL ||
5316af23589SJoshua M. Clulow 			    vd->vdev_devid != NULL) {
5326af23589SJoshua M. Clulow 				/*
5336af23589SJoshua M. Clulow 				 * We only need to remove the devid if one
5346af23589SJoshua M. Clulow 				 * exists.
5356af23589SJoshua M. Clulow 				 */
5366af23589SJoshua M. Clulow 				remove = B_TRUE;
5376af23589SJoshua M. Clulow 			}
538fb02ae02SGeorge Wilson 
5396af23589SJoshua M. Clulow 		} else if (dvd->vd_devid == NULL || dvd->vd_minor == NULL) {
5406af23589SJoshua M. Clulow 			/*
5416af23589SJoshua M. Clulow 			 * There was previously no devid at all so we need to
5426af23589SJoshua M. Clulow 			 * add one.
5436af23589SJoshua M. Clulow 			 */
5446af23589SJoshua M. Clulow 			update = B_TRUE;
5456af23589SJoshua M. Clulow 
5466af23589SJoshua M. Clulow 		} else if (ddi_devid_compare(devid, dvd->vd_devid) != 0 ||
5476af23589SJoshua M. Clulow 		    strcmp(minorname, dvd->vd_minor) != 0) {
5486af23589SJoshua M. Clulow 			/*
5496af23589SJoshua M. Clulow 			 * The devid or minor name on file does not match the
5506af23589SJoshua M. Clulow 			 * one from the opened device.
5516af23589SJoshua M. Clulow 			 */
5526af23589SJoshua M. Clulow 			update = B_TRUE;
5536af23589SJoshua M. Clulow 		}
5546af23589SJoshua M. Clulow 
5556af23589SJoshua M. Clulow 		if (update) {
5566af23589SJoshua M. Clulow 			/*
5576af23589SJoshua M. Clulow 			 * Render the new devid and minor name as a string for
5586af23589SJoshua M. Clulow 			 * logging and to store in the vdev configuration.
5596af23589SJoshua M. Clulow 			 */
5606af23589SJoshua M. Clulow 			vd_devid = ddi_devid_str_encode(devid, minorname);
5616af23589SJoshua M. Clulow 		}
5626af23589SJoshua M. Clulow 
5636af23589SJoshua M. Clulow 		if (update || remove) {
5643ee8c80cSPavel Zakharov 			vdev_dbgmsg(vd, "vdev_disk_open: update devid from "
5656af23589SJoshua M. Clulow 			    "'%s' to '%s'",
5666af23589SJoshua M. Clulow 			    vd->vdev_devid != NULL ? vd->vdev_devid : "<none>",
5676af23589SJoshua M. Clulow 			    vd_devid != NULL ? vd_devid : "<none>");
5686fe4f300SPavel Zakharov 			cmn_err(CE_NOTE, "vdev_disk_open %s: update devid "
5696af23589SJoshua M. Clulow 			    "from '%s' to '%s'",
5706af23589SJoshua M. Clulow 			    vd->vdev_path != NULL ? vd->vdev_path : "?",
5716af23589SJoshua M. Clulow 			    vd->vdev_devid != NULL ? vd->vdev_devid : "<none>",
5726af23589SJoshua M. Clulow 			    vd_devid != NULL ? vd_devid : "<none>");
5736af23589SJoshua M. Clulow 
5746af23589SJoshua M. Clulow 			/*
5756af23589SJoshua M. Clulow 			 * Remove and free any existing values.
5766af23589SJoshua M. Clulow 			 */
5776af23589SJoshua M. Clulow 			if (dvd->vd_minor != NULL) {
5786af23589SJoshua M. Clulow 				ddi_devid_str_free(dvd->vd_minor);
5796af23589SJoshua M. Clulow 				dvd->vd_minor = NULL;
5806af23589SJoshua M. Clulow 			}
5816af23589SJoshua M. Clulow 			if (dvd->vd_devid != NULL) {
5826af23589SJoshua M. Clulow 				ddi_devid_free(dvd->vd_devid);
5836af23589SJoshua M. Clulow 				dvd->vd_devid = NULL;
5846af23589SJoshua M. Clulow 			}
5856af23589SJoshua M. Clulow 			if (vd->vdev_devid != NULL) {
5866af23589SJoshua M. Clulow 				spa_strfree(vd->vdev_devid);
5876af23589SJoshua M. Clulow 				vd->vdev_devid = NULL;
5886af23589SJoshua M. Clulow 			}
5896af23589SJoshua M. Clulow 		}
5906af23589SJoshua M. Clulow 
5916af23589SJoshua M. Clulow 		if (update) {
5926af23589SJoshua M. Clulow 			/*
5936af23589SJoshua M. Clulow 			 * Install the new values.
5946af23589SJoshua M. Clulow 			 */
5956af23589SJoshua M. Clulow 			vd->vdev_devid = vd_devid;
5966af23589SJoshua M. Clulow 			dvd->vd_minor = minorname;
5976af23589SJoshua M. Clulow 			dvd->vd_devid = devid;
5986af23589SJoshua M. Clulow 
5996af23589SJoshua M. Clulow 		} else {
6006af23589SJoshua M. Clulow 			if (devid != NULL) {
6016af23589SJoshua M. Clulow 				ddi_devid_free(devid);
6026af23589SJoshua M. Clulow 			}
6036af23589SJoshua M. Clulow 			if (minorname != NULL) {
6046af23589SJoshua M. Clulow 				kmem_free(minorname, strlen(minorname) + 1);
6056af23589SJoshua M. Clulow 			}
606fb02ae02SGeorge Wilson 		}
607fb02ae02SGeorge Wilson 	}
608fb02ae02SGeorge Wilson 
6093d7072f8Seschrock 	/*
6103d7072f8Seschrock 	 * Once a device is opened, verify that the physical device path (if
6113d7072f8Seschrock 	 * available) is up to date.
6123d7072f8Seschrock 	 */
6133d7072f8Seschrock 	if (ldi_get_dev(dvd->vd_lh, &dev) == 0 &&
6143d7072f8Seschrock 	    ldi_get_otyp(dvd->vd_lh, &otyp) == 0) {
6150a4e9518Sgw 		char *physpath, *minorname;
6160a4e9518Sgw 
6173d7072f8Seschrock 		physpath = kmem_alloc(MAXPATHLEN, KM_SLEEP);
6183d7072f8Seschrock 		minorname = NULL;
6193d7072f8Seschrock 		if (ddi_dev_pathname(dev, otyp, physpath) == 0 &&
6203d7072f8Seschrock 		    ldi_get_minor_name(dvd->vd_lh, &minorname) == 0 &&
6213d7072f8Seschrock 		    (vd->vdev_physpath == NULL ||
6223d7072f8Seschrock 		    strcmp(vd->vdev_physpath, physpath) != 0)) {
6233d7072f8Seschrock 			if (vd->vdev_physpath)
6243d7072f8Seschrock 				spa_strfree(vd->vdev_physpath);
6253d7072f8Seschrock 			(void) strlcat(physpath, ":", MAXPATHLEN);
6263d7072f8Seschrock 			(void) strlcat(physpath, minorname, MAXPATHLEN);
6273d7072f8Seschrock 			vd->vdev_physpath = spa_strdup(physpath);
6283d7072f8Seschrock 		}
6293d7072f8Seschrock 		if (minorname)
6303d7072f8Seschrock 			kmem_free(minorname, strlen(minorname) + 1);
6313d7072f8Seschrock 		kmem_free(physpath, MAXPATHLEN);
6323d7072f8Seschrock 	}
6333d7072f8Seschrock 
63439cddb10SJoshua M. Clulow 	/*
63539cddb10SJoshua M. Clulow 	 * Register callbacks for the LDI offline event.
63639cddb10SJoshua M. Clulow 	 */
63739cddb10SJoshua M. Clulow 	if (ldi_ev_get_cookie(dvd->vd_lh, LDI_EV_OFFLINE, &ecookie) ==
63839cddb10SJoshua M. Clulow 	    LDI_EV_SUCCESS) {
63939cddb10SJoshua M. Clulow 		lcb = kmem_zalloc(sizeof (vdev_disk_ldi_cb_t), KM_SLEEP);
64039cddb10SJoshua M. Clulow 		list_insert_tail(&dvd->vd_ldi_cbs, lcb);
64139cddb10SJoshua M. Clulow 		(void) ldi_ev_register_callbacks(dvd->vd_lh, ecookie,
64239cddb10SJoshua M. Clulow 		    &vdev_disk_off_callb, (void *) vd, &lcb->lcb_id);
64339cddb10SJoshua M. Clulow 	}
64439cddb10SJoshua M. Clulow 
64539cddb10SJoshua M. Clulow 	/*
64639cddb10SJoshua M. Clulow 	 * Register callbacks for the LDI degrade event.
64739cddb10SJoshua M. Clulow 	 */
64839cddb10SJoshua M. Clulow 	if (ldi_ev_get_cookie(dvd->vd_lh, LDI_EV_DEGRADE, &ecookie) ==
64939cddb10SJoshua M. Clulow 	    LDI_EV_SUCCESS) {
65039cddb10SJoshua M. Clulow 		lcb = kmem_zalloc(sizeof (vdev_disk_ldi_cb_t), KM_SLEEP);
65139cddb10SJoshua M. Clulow 		list_insert_tail(&dvd->vd_ldi_cbs, lcb);
65239cddb10SJoshua M. Clulow 		(void) ldi_ev_register_callbacks(dvd->vd_lh, ecookie,
65339cddb10SJoshua M. Clulow 		    &vdev_disk_dgrd_callb, (void *) vd, &lcb->lcb_id);
65439cddb10SJoshua M. Clulow 	}
655084fd14fSBrian Behlendorf 
656095bcd66SGeorge Wilson skip_open:
657fa9e4066Sahrens 	/*
658fa9e4066Sahrens 	 * Determine the actual size of the device.
659fa9e4066Sahrens 	 */
660fa9e4066Sahrens 	if (ldi_get_size(dvd->vd_lh, psize) != 0) {
661fa9e4066Sahrens 		vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED;
6623ee8c80cSPavel Zakharov 		vdev_dbgmsg(vd, "vdev_disk_open: failed to get size");
663be6fd75aSMatthew Ahrens 		return (SET_ERROR(EINVAL));
664fa9e4066Sahrens 	}
665fa9e4066Sahrens 
666a5b57771SDan McDonald 	*max_psize = *psize;
667a5b57771SDan McDonald 
668ecc2d604Sbonwick 	/*
669ecc2d604Sbonwick 	 * Determine the device's minimum transfer size.
670ecc2d604Sbonwick 	 * If the ioctl isn't supported, assume DEV_BSIZE.
671ecc2d604Sbonwick 	 */
672a5b57771SDan McDonald 	if ((error = ldi_ioctl(dvd->vd_lh, DKIOCGMEDIAINFOEXT,
673a5b57771SDan McDonald 	    (intptr_t)dkmext, FKIOCTL, kcred, NULL)) == 0) {
674a5b57771SDan McDonald 		capacity = dkmext->dki_capacity - 1;
675a5b57771SDan McDonald 		blksz = dkmext->dki_lbsize;
676a5b57771SDan McDonald 		pbsize = dkmext->dki_pbsize;
677a5b57771SDan McDonald 	} else if ((error = ldi_ioctl(dvd->vd_lh, DKIOCGMEDIAINFO,
678a5b57771SDan McDonald 	    (intptr_t)dkm, FKIOCTL, kcred, NULL)) == 0) {
679a5b57771SDan McDonald 		VDEV_DEBUG(
680a5b57771SDan McDonald 		    "vdev_disk_open(\"%s\"): fallback to DKIOCGMEDIAINFO\n",
681a5b57771SDan McDonald 		    vd->vdev_path);
682a5b57771SDan McDonald 		capacity = dkm->dki_capacity - 1;
683a5b57771SDan McDonald 		blksz = dkm->dki_lbsize;
684a5b57771SDan McDonald 		pbsize = blksz;
685a5b57771SDan McDonald 	} else {
686a5b57771SDan McDonald 		VDEV_DEBUG("vdev_disk_open(\"%s\"): "
687a5b57771SDan McDonald 		    "both DKIOCGMEDIAINFO{,EXT} calls failed, %d\n",
688a5b57771SDan McDonald 		    vd->vdev_path, error);
689a5b57771SDan McDonald 		pbsize = DEV_BSIZE;
690a5b57771SDan McDonald 	}
691bef6b7d2Swebaker 
692bf16b11eSMatthew Ahrens 	*ashift = highbit64(MAX(pbsize, SPA_MINBLOCKSIZE)) - 1;
693bef6b7d2Swebaker 
6944263d13fSGeorge Wilson 	if (vd->vdev_wholedisk == 1) {
6954263d13fSGeorge Wilson 		int wce = 1;
6964263d13fSGeorge Wilson 
697a5b57771SDan McDonald 		if (error == 0) {
698a5b57771SDan McDonald 			/*
699a5b57771SDan McDonald 			 * If we have the capability to expand, we'd have
700a5b57771SDan McDonald 			 * found out via success from DKIOCGMEDIAINFO{,EXT}.
701