1*b8aa3defSJoshua M. Clulow /*
2*b8aa3defSJoshua M. Clulow  * This file and its contents are supplied under the terms of the
3*b8aa3defSJoshua M. Clulow  * Common Development and Distribution License ("CDDL"), version 1.0.
4*b8aa3defSJoshua M. Clulow  * You may only use this file in accordance with the terms of version
5*b8aa3defSJoshua M. Clulow  * 1.0 of the CDDL.
6*b8aa3defSJoshua M. Clulow  *
7*b8aa3defSJoshua M. Clulow  * A full copy of the text of the CDDL should have accompanied this
8*b8aa3defSJoshua M. Clulow  * source.  A copy of the CDDL is also available via the Internet at
9*b8aa3defSJoshua M. Clulow  * http://www.illumos.org/license/CDDL.
10*b8aa3defSJoshua M. Clulow  */
11*b8aa3defSJoshua M. Clulow 
12*b8aa3defSJoshua M. Clulow /*
13*b8aa3defSJoshua M. Clulow  * Copyright (c) 2017 Joyent, Inc.
14*b8aa3defSJoshua M. Clulow  */
15*b8aa3defSJoshua M. Clulow 
16*b8aa3defSJoshua M. Clulow #include <sys/scsi/adapters/smrt/smrt.h>
17*b8aa3defSJoshua M. Clulow 
18*b8aa3defSJoshua M. Clulow static void
smrt_physical_free(smrt_physical_t * smpt)19*b8aa3defSJoshua M. Clulow smrt_physical_free(smrt_physical_t *smpt)
20*b8aa3defSJoshua M. Clulow {
21*b8aa3defSJoshua M. Clulow 	VERIFY(list_is_empty(&smpt->smpt_targets));
22*b8aa3defSJoshua M. Clulow 	VERIFY(smpt->smpt_info != NULL);
23*b8aa3defSJoshua M. Clulow 
24*b8aa3defSJoshua M. Clulow 	kmem_free(smpt->smpt_info, sizeof (*smpt->smpt_info));
25*b8aa3defSJoshua M. Clulow 	list_destroy(&smpt->smpt_targets);
26*b8aa3defSJoshua M. Clulow 	kmem_free(smpt, sizeof (*smpt));
27*b8aa3defSJoshua M. Clulow }
28*b8aa3defSJoshua M. Clulow 
29*b8aa3defSJoshua M. Clulow /*
30*b8aa3defSJoshua M. Clulow  * Determine if a physical device enumerated should be shown to the world. There
31*b8aa3defSJoshua M. Clulow  * are three conditions to satisfy for this to be true.
32*b8aa3defSJoshua M. Clulow  *
33*b8aa3defSJoshua M. Clulow  * 1. The device (SAS, SATA, SES, etc.) must not have a masked CISS address.  A
34*b8aa3defSJoshua M. Clulow  * masked CISS address indicates a device that we should not be performing I/O
35*b8aa3defSJoshua M. Clulow  * to.
36*b8aa3defSJoshua M. Clulow  * 2. The drive (SAS or SATA device) must not be marked as a member of a logical
37*b8aa3defSJoshua M. Clulow  * volume.
38*b8aa3defSJoshua M. Clulow  * 3. The drive (SAS or SATA device) must not be marked as a spare.
39*b8aa3defSJoshua M. Clulow  */
40*b8aa3defSJoshua M. Clulow static boolean_t
smrt_physical_visible(PhysDevAddr_t * addr,smrt_identify_physical_drive_t * info)41*b8aa3defSJoshua M. Clulow smrt_physical_visible(PhysDevAddr_t *addr, smrt_identify_physical_drive_t *info)
42*b8aa3defSJoshua M. Clulow {
43*b8aa3defSJoshua M. Clulow 	if (addr->Mode == SMRT_CISS_MODE_MASKED) {
44*b8aa3defSJoshua M. Clulow 		return (B_FALSE);
45*b8aa3defSJoshua M. Clulow 	}
46*b8aa3defSJoshua M. Clulow 
47*b8aa3defSJoshua M. Clulow 	if ((info->sipd_more_flags & (SMRT_MORE_FLAGS_LOGVOL |
48*b8aa3defSJoshua M. Clulow 	    SMRT_MORE_FLAGS_SPARE)) != 0) {
49*b8aa3defSJoshua M. Clulow 		return (B_FALSE);
50*b8aa3defSJoshua M. Clulow 	}
51*b8aa3defSJoshua M. Clulow 
52*b8aa3defSJoshua M. Clulow 	return (B_TRUE);
53*b8aa3defSJoshua M. Clulow }
54*b8aa3defSJoshua M. Clulow 
55*b8aa3defSJoshua M. Clulow /*
56*b8aa3defSJoshua M. Clulow  * Note, the caller is responsible for making sure that the unit-address form of
57*b8aa3defSJoshua M. Clulow  * the WWN is pased in.  Any additional information to target a specific LUN
58*b8aa3defSJoshua M. Clulow  * will be ignored.
59*b8aa3defSJoshua M. Clulow  */
60*b8aa3defSJoshua M. Clulow smrt_physical_t *
smrt_phys_lookup_by_ua(smrt_t * smrt,const char * ua)61*b8aa3defSJoshua M. Clulow smrt_phys_lookup_by_ua(smrt_t *smrt, const char *ua)
62*b8aa3defSJoshua M. Clulow {
63*b8aa3defSJoshua M. Clulow 	VERIFY(MUTEX_HELD(&smrt->smrt_mutex));
64*b8aa3defSJoshua M. Clulow 
65*b8aa3defSJoshua M. Clulow 	/*
66*b8aa3defSJoshua M. Clulow 	 * Sanity check that the caller has provided us enough bytes for a
67*b8aa3defSJoshua M. Clulow 	 * properly formed unit-address form of a WWN.
68*b8aa3defSJoshua M. Clulow 	 */
69*b8aa3defSJoshua M. Clulow 	if (strlen(ua) < SCSI_WWN_UA_STRLEN)
70*b8aa3defSJoshua M. Clulow 		return (NULL);
71*b8aa3defSJoshua M. Clulow 
72*b8aa3defSJoshua M. Clulow 	for (smrt_physical_t *smpt = list_head(&smrt->smrt_physicals);
73*b8aa3defSJoshua M. Clulow 	    smpt != NULL; smpt = list_next(&smrt->smrt_physicals, smpt)) {
74*b8aa3defSJoshua M. Clulow 		char wwnstr[SCSI_WWN_BUFLEN];
75*b8aa3defSJoshua M. Clulow 
76*b8aa3defSJoshua M. Clulow 		(void) scsi_wwn_to_wwnstr(smpt->smpt_wwn, 1, wwnstr);
77*b8aa3defSJoshua M. Clulow 		if (strncmp(wwnstr, ua, SCSI_WWN_UA_STRLEN) != 0)
78*b8aa3defSJoshua M. Clulow 			continue;
79*b8aa3defSJoshua M. Clulow 
80*b8aa3defSJoshua M. Clulow 		/*
81*b8aa3defSJoshua M. Clulow 		 * Verify that the UA string is either a comma or null there.
82*b8aa3defSJoshua M. Clulow 		 * We accept the comma in case it's being used as part of a
83*b8aa3defSJoshua M. Clulow 		 * normal UA with a LUN.
84*b8aa3defSJoshua M. Clulow 		 */
85*b8aa3defSJoshua M. Clulow 		if (ua[SCSI_WWN_UA_STRLEN] != '\0' &&
86*b8aa3defSJoshua M. Clulow 		    ua[SCSI_WWN_UA_STRLEN] != ',') {
87*b8aa3defSJoshua M. Clulow 			continue;
88*b8aa3defSJoshua M. Clulow 		}
89*b8aa3defSJoshua M. Clulow 
90*b8aa3defSJoshua M. Clulow 		return (smpt);
91*b8aa3defSJoshua M. Clulow 	}
92*b8aa3defSJoshua M. Clulow 
93*b8aa3defSJoshua M. Clulow 	return (NULL);
94*b8aa3defSJoshua M. Clulow }
95*b8aa3defSJoshua M. Clulow 
96*b8aa3defSJoshua M. Clulow static smrt_physical_t *
smrt_phys_lookup_by_wwn(smrt_t * smrt,uint64_t wwn)97*b8aa3defSJoshua M. Clulow smrt_phys_lookup_by_wwn(smrt_t *smrt, uint64_t wwn)
98*b8aa3defSJoshua M. Clulow {
99*b8aa3defSJoshua M. Clulow 	VERIFY(MUTEX_HELD(&smrt->smrt_mutex));
100*b8aa3defSJoshua M. Clulow 
101*b8aa3defSJoshua M. Clulow 	for (smrt_physical_t *smpt = list_head(&smrt->smrt_physicals);
102*b8aa3defSJoshua M. Clulow 	    smpt != NULL; smpt = list_next(&smrt->smrt_physicals, smpt)) {
103*b8aa3defSJoshua M. Clulow 		if (wwn == smpt->smpt_wwn)
104*b8aa3defSJoshua M. Clulow 			return (smpt);
105*b8aa3defSJoshua M. Clulow 	}
106*b8aa3defSJoshua M. Clulow 
107*b8aa3defSJoshua M. Clulow 	return (NULL);
108*b8aa3defSJoshua M. Clulow }
109*b8aa3defSJoshua M. Clulow 
110*b8aa3defSJoshua M. Clulow static int
smrt_phys_identify(smrt_t * smrt,smrt_identify_physical_drive_t * info,uint16_t bmic,uint16_t timeout)111*b8aa3defSJoshua M. Clulow smrt_phys_identify(smrt_t *smrt, smrt_identify_physical_drive_t *info,
112*b8aa3defSJoshua M. Clulow     uint16_t bmic, uint16_t timeout)
113*b8aa3defSJoshua M. Clulow {
114*b8aa3defSJoshua M. Clulow 	smrt_command_t *smcm = NULL;
115*b8aa3defSJoshua M. Clulow 	smrt_identify_physical_drive_t *sipd;
116*b8aa3defSJoshua M. Clulow 	smrt_identify_physical_drive_req_t sipdr;
117*b8aa3defSJoshua M. Clulow 	int ret;
118*b8aa3defSJoshua M. Clulow 	size_t sz, copysz;
119*b8aa3defSJoshua M. Clulow 
120*b8aa3defSJoshua M. Clulow 	sz = sizeof (smrt_identify_physical_drive_t);
121*b8aa3defSJoshua M. Clulow 	sz = P2ROUNDUP_TYPED(sz, 512, size_t);
122*b8aa3defSJoshua M. Clulow 	if ((smcm = smrt_command_alloc(smrt, SMRT_CMDTYPE_INTERNAL,
123*b8aa3defSJoshua M. Clulow 	    KM_NOSLEEP)) == NULL || smrt_command_attach_internal(smrt, smcm,
124*b8aa3defSJoshua M. Clulow 	    sizeof (*sipd), KM_NOSLEEP) != 0) {
125*b8aa3defSJoshua M. Clulow 		ret = ENOMEM;
126*b8aa3defSJoshua M. Clulow 		goto out;
127*b8aa3defSJoshua M. Clulow 	}
128*b8aa3defSJoshua M. Clulow 
129*b8aa3defSJoshua M. Clulow 	sipd = smcm->smcm_internal->smcmi_va;
130*b8aa3defSJoshua M. Clulow 
131*b8aa3defSJoshua M. Clulow 	smrt_write_controller_lun_addr(&smcm->smcm_va_cmd->Header.LUN);
132*b8aa3defSJoshua M. Clulow 
133*b8aa3defSJoshua M. Clulow 	smcm->smcm_va_cmd->Request.CDBLen = sizeof (sipdr);
134*b8aa3defSJoshua M. Clulow 	smcm->smcm_va_cmd->Request.Timeout = LE_16(timeout);
135*b8aa3defSJoshua M. Clulow 	smcm->smcm_va_cmd->Request.Type.Type = CISS_TYPE_CMD;
136*b8aa3defSJoshua M. Clulow 	smcm->smcm_va_cmd->Request.Type.Attribute = CISS_ATTR_SIMPLE;
137*b8aa3defSJoshua M. Clulow 	smcm->smcm_va_cmd->Request.Type.Direction = CISS_XFER_READ;
138*b8aa3defSJoshua M. Clulow 
139*b8aa3defSJoshua M. Clulow 	/*
140*b8aa3defSJoshua M. Clulow 	 * Construct the IDENTIFY PHYSICAL DEVICE request CDB.  Note that any
141*b8aa3defSJoshua M. Clulow 	 * reserved fields in the request must be filled with zeroes.
142*b8aa3defSJoshua M. Clulow 	 */
143*b8aa3defSJoshua M. Clulow 	bzero(&sipdr, sizeof (sipdr));
144*b8aa3defSJoshua M. Clulow 	sipdr.sipdr_opcode = CISS_SCMD_BMIC_READ;
145*b8aa3defSJoshua M. Clulow 	sipdr.sipdr_lun = 0;
146*b8aa3defSJoshua M. Clulow 	sipdr.sipdr_bmic_index1 = bmic & 0x00ff;
147*b8aa3defSJoshua M. Clulow 	sipdr.sipdr_command = CISS_BMIC_IDENTIFY_PHYSICAL_DEVICE;
148*b8aa3defSJoshua M. Clulow 	sipdr.sipdr_bmic_index2 = (bmic & 0xff00) >> 8;
149*b8aa3defSJoshua M. Clulow 	bcopy(&sipdr, &smcm->smcm_va_cmd->Request.CDB[0],
150*b8aa3defSJoshua M. Clulow 	    MIN(CISS_CDBLEN, sizeof (sipdr)));
151*b8aa3defSJoshua M. Clulow 
152*b8aa3defSJoshua M. Clulow 	mutex_enter(&smrt->smrt_mutex);
153*b8aa3defSJoshua M. Clulow 
154*b8aa3defSJoshua M. Clulow 	/*
155*b8aa3defSJoshua M. Clulow 	 * Send the command to the device.
156*b8aa3defSJoshua M. Clulow 	 */
157*b8aa3defSJoshua M. Clulow 	smcm->smcm_status |= SMRT_CMD_STATUS_POLLED;
158*b8aa3defSJoshua M. Clulow 	if ((ret = smrt_submit(smrt, smcm)) != 0) {
159*b8aa3defSJoshua M. Clulow 		mutex_exit(&smrt->smrt_mutex);
160*b8aa3defSJoshua M. Clulow 		goto out;
161*b8aa3defSJoshua M. Clulow 	}
162*b8aa3defSJoshua M. Clulow 
163*b8aa3defSJoshua M. Clulow 	/*
164*b8aa3defSJoshua M. Clulow 	 * Poll for completion.
165*b8aa3defSJoshua M. Clulow 	 */
166*b8aa3defSJoshua M. Clulow 	smcm->smcm_expiry = gethrtime() + timeout * NANOSEC;
167*b8aa3defSJoshua M. Clulow 	if ((ret = smrt_poll_for(smrt, smcm)) != 0) {
168*b8aa3defSJoshua M. Clulow 		VERIFY3S(ret, ==, ETIMEDOUT);
169*b8aa3defSJoshua M. Clulow 		VERIFY0(smcm->smcm_status & SMRT_CMD_STATUS_POLL_COMPLETE);
170*b8aa3defSJoshua M. Clulow 
171*b8aa3defSJoshua M. Clulow 		/*
172*b8aa3defSJoshua M. Clulow 		 * The command timed out; abandon it now.  Remove the POLLED
173*b8aa3defSJoshua M. Clulow 		 * flag so that the periodic routine will send an abort to
174*b8aa3defSJoshua M. Clulow 		 * clean it up next time around.
175*b8aa3defSJoshua M. Clulow 		 */
176*b8aa3defSJoshua M. Clulow 		smcm->smcm_status |= SMRT_CMD_STATUS_ABANDONED;
177*b8aa3defSJoshua M. Clulow 		smcm->smcm_status &= ~SMRT_CMD_STATUS_POLLED;
178*b8aa3defSJoshua M. Clulow 		smcm = NULL;
179*b8aa3defSJoshua M. Clulow 		mutex_exit(&smrt->smrt_mutex);
180*b8aa3defSJoshua M. Clulow 		goto out;
181*b8aa3defSJoshua M. Clulow 	}
182*b8aa3defSJoshua M. Clulow 	mutex_exit(&smrt->smrt_mutex);
183*b8aa3defSJoshua M. Clulow 
184*b8aa3defSJoshua M. Clulow 	if (smcm->smcm_status & SMRT_CMD_STATUS_RESET_SENT) {
185*b8aa3defSJoshua M. Clulow 		/*
186*b8aa3defSJoshua M. Clulow 		 * The controller was reset while we were trying to discover
187*b8aa3defSJoshua M. Clulow 		 * physical volumes.  Report failure.
188*b8aa3defSJoshua M. Clulow 		 */
189*b8aa3defSJoshua M. Clulow 		ret = EIO;
190*b8aa3defSJoshua M. Clulow 		goto out;
191*b8aa3defSJoshua M. Clulow 	}
192*b8aa3defSJoshua M. Clulow 
193*b8aa3defSJoshua M. Clulow 	if (smcm->smcm_status & SMRT_CMD_STATUS_ERROR) {
194*b8aa3defSJoshua M. Clulow 		ErrorInfo_t *ei = smcm->smcm_va_err;
195*b8aa3defSJoshua M. Clulow 
196*b8aa3defSJoshua M. Clulow 		if (ei->CommandStatus != CISS_CMD_DATA_UNDERRUN) {
197*b8aa3defSJoshua M. Clulow 			dev_err(smrt->smrt_dip, CE_WARN, "identify physical "
198*b8aa3defSJoshua M. Clulow 			    "device error: status 0x%x", ei->CommandStatus);
199*b8aa3defSJoshua M. Clulow 			ret = EIO;
200*b8aa3defSJoshua M. Clulow 			goto out;
201*b8aa3defSJoshua M. Clulow 		}
202*b8aa3defSJoshua M. Clulow 
203*b8aa3defSJoshua M. Clulow 		copysz = MIN(sizeof (*sipd), sz - ei->ResidualCnt);
204*b8aa3defSJoshua M. Clulow 	} else {
205*b8aa3defSJoshua M. Clulow 		copysz = sizeof (*sipd);
206*b8aa3defSJoshua M. Clulow 	}
207*b8aa3defSJoshua M. Clulow 
208*b8aa3defSJoshua M. Clulow 
209*b8aa3defSJoshua M. Clulow 	sz = MIN(sizeof (*sipd), copysz);
210*b8aa3defSJoshua M. Clulow 	bcopy(sipd, info, sizeof (*sipd));
211*b8aa3defSJoshua M. Clulow 
212*b8aa3defSJoshua M. Clulow 	ret = 0;
213*b8aa3defSJoshua M. Clulow out:
214*b8aa3defSJoshua M. Clulow 	if (smcm != NULL) {
215*b8aa3defSJoshua M. Clulow 		smrt_command_free(smcm);
216*b8aa3defSJoshua M. Clulow 	}
217*b8aa3defSJoshua M. Clulow 
218*b8aa3defSJoshua M. Clulow 	return (ret);
219*b8aa3defSJoshua M. Clulow }
220*b8aa3defSJoshua M. Clulow 
221*b8aa3defSJoshua M. Clulow static int
smrt_read_phys_ext(smrt_t * smrt,smrt_report_physical_lun_t * smrpl,uint16_t timeout,uint64_t gen)222*b8aa3defSJoshua M. Clulow smrt_read_phys_ext(smrt_t *smrt, smrt_report_physical_lun_t *smrpl,
223*b8aa3defSJoshua M. Clulow     uint16_t timeout, uint64_t gen)
224*b8aa3defSJoshua M. Clulow {
225*b8aa3defSJoshua M. Clulow 	smrt_report_physical_lun_extent_t *extents = smrpl->smrpl_data.extents;
226*b8aa3defSJoshua M. Clulow 	uint32_t count = BE_32(smrpl->smrpl_datasize) /
227*b8aa3defSJoshua M. Clulow 	    sizeof (smrt_report_physical_lun_extent_t);
228*b8aa3defSJoshua M. Clulow 	uint32_t i;
229*b8aa3defSJoshua M. Clulow 
230*b8aa3defSJoshua M. Clulow 	VERIFY(MUTEX_HELD(&smrt->smrt_mutex));
231*b8aa3defSJoshua M. Clulow 
232*b8aa3defSJoshua M. Clulow 	if (count > SMRT_MAX_PHYSDEV) {
233*b8aa3defSJoshua M. Clulow 		count = SMRT_MAX_PHYSDEV;
234*b8aa3defSJoshua M. Clulow 	}
235*b8aa3defSJoshua M. Clulow 
236*b8aa3defSJoshua M. Clulow 	for (i = 0; i < count; i++) {
237*b8aa3defSJoshua M. Clulow 		int ret;
238*b8aa3defSJoshua M. Clulow 		smrt_physical_t *smpt;
239*b8aa3defSJoshua M. Clulow 		smrt_identify_physical_drive_t *info;
240*b8aa3defSJoshua M. Clulow 		smrt_report_physical_opdi_t *opdi;
241*b8aa3defSJoshua M. Clulow 		uint16_t bmic;
242*b8aa3defSJoshua M. Clulow 		uint64_t wwn, satawwn;
243*b8aa3defSJoshua M. Clulow 		char name[SCSI_MAXNAMELEN];
244*b8aa3defSJoshua M. Clulow 
245*b8aa3defSJoshua M. Clulow 		opdi = &extents[i].srple_extdata.srple_opdi;
246*b8aa3defSJoshua M. Clulow 
247*b8aa3defSJoshua M. Clulow 		mutex_exit(&smrt->smrt_mutex);
248*b8aa3defSJoshua M. Clulow 
249*b8aa3defSJoshua M. Clulow 		/*
250*b8aa3defSJoshua M. Clulow 		 * Get the extended information about this device.
251*b8aa3defSJoshua M. Clulow 		 */
252*b8aa3defSJoshua M. Clulow 		info = kmem_zalloc(sizeof (*info), KM_NOSLEEP);
253*b8aa3defSJoshua M. Clulow 		if (info == NULL) {
254*b8aa3defSJoshua M. Clulow 			mutex_enter(&smrt->smrt_mutex);
255*b8aa3defSJoshua M. Clulow 			return (ENOMEM);
256*b8aa3defSJoshua M. Clulow 		}
257*b8aa3defSJoshua M. Clulow 
258*b8aa3defSJoshua M. Clulow 		bmic = smrt_lun_addr_to_bmic(&extents[i].srple_addr);
259*b8aa3defSJoshua M. Clulow 		ret = smrt_phys_identify(smrt, info, bmic, timeout);
260*b8aa3defSJoshua M. Clulow 		if (ret != 0) {
261*b8aa3defSJoshua M. Clulow 			mutex_enter(&smrt->smrt_mutex);
262*b8aa3defSJoshua M. Clulow 			kmem_free(info, sizeof (*info));
263*b8aa3defSJoshua M. Clulow 			return (ret);
264*b8aa3defSJoshua M. Clulow 		}
265*b8aa3defSJoshua M. Clulow 
266*b8aa3defSJoshua M. Clulow 		wwn = *(uint64_t *)opdi->srpo_wwid;
267*b8aa3defSJoshua M. Clulow 		wwn = BE_64(wwn);
268*b8aa3defSJoshua M. Clulow 
269*b8aa3defSJoshua M. Clulow 		/*
270*b8aa3defSJoshua M. Clulow 		 * SATA devices may not have a proper WWN returned from firmware
271*b8aa3defSJoshua M. Clulow 		 * based on the SATL specification.  Try to fetch the proper id
272*b8aa3defSJoshua M. Clulow 		 * for SATA devices, if the drive has one.  If the drive doesn't
273*b8aa3defSJoshua M. Clulow 		 * have one or the SATL refuses to give us one, we use whatever
274*b8aa3defSJoshua M. Clulow 		 * the controller told us.
275*b8aa3defSJoshua M. Clulow 		 */
276*b8aa3defSJoshua M. Clulow 		if (opdi->srpo_dtype == SMRT_DTYPE_SATA &&
277*b8aa3defSJoshua M. Clulow 		    smrt_sata_determine_wwn(smrt, &extents[i].srple_addr,
278*b8aa3defSJoshua M. Clulow 		    &satawwn, timeout) == 0) {
279*b8aa3defSJoshua M. Clulow 			wwn = satawwn;
280*b8aa3defSJoshua M. Clulow 		}
281*b8aa3defSJoshua M. Clulow 
282*b8aa3defSJoshua M. Clulow 		mutex_enter(&smrt->smrt_mutex);
283*b8aa3defSJoshua M. Clulow 		smpt = smrt_phys_lookup_by_wwn(smrt, wwn);
284*b8aa3defSJoshua M. Clulow 		if (smpt != NULL) {
285*b8aa3defSJoshua M. Clulow 			/*
286*b8aa3defSJoshua M. Clulow 			 * Sanity check that the model and serial number of this
287*b8aa3defSJoshua M. Clulow 			 * device is the same for this WWN.  If it's not, the
288*b8aa3defSJoshua M. Clulow 			 * controller is probably lying about something.
289*b8aa3defSJoshua M. Clulow 			 */
290*b8aa3defSJoshua M. Clulow 			if (bcmp(smpt->smpt_info->sipd_model, info->sipd_model,
291*b8aa3defSJoshua M. Clulow 			    sizeof (info->sipd_model)) != 0 ||
292*b8aa3defSJoshua M. Clulow 			    bcmp(smpt->smpt_info->sipd_serial,
293*b8aa3defSJoshua M. Clulow 			    info->sipd_serial, sizeof (info->sipd_serial)) !=
294*b8aa3defSJoshua M. Clulow 			    0 || smpt->smpt_dtype != opdi->srpo_dtype) {
295*b8aa3defSJoshua M. Clulow 				dev_err(smrt->smrt_dip, CE_PANIC, "physical "
296*b8aa3defSJoshua M. Clulow 				    "target with wwn 0x%" PRIx64 " changed "
297*b8aa3defSJoshua M. Clulow 				    "model, serial, or type unexpectedly: "
298*b8aa3defSJoshua M. Clulow 				    "smrt_physical_t %p, phys info: %p", wwn,
299*b8aa3defSJoshua M. Clulow 				    smpt, info);
300*b8aa3defSJoshua M. Clulow 			}
301*b8aa3defSJoshua M. Clulow 
302*b8aa3defSJoshua M. Clulow 			/*
303*b8aa3defSJoshua M. Clulow 			 * When panicking, we don't allow a device's visibility
304*b8aa3defSJoshua M. Clulow 			 * to change to being invisible and be able to actually
305*b8aa3defSJoshua M. Clulow 			 * panic.  We only worry about devices which are used
306*b8aa3defSJoshua M. Clulow 			 * for I/O.  We purposefully ignore SES devices.
307*b8aa3defSJoshua M. Clulow 			 */
308*b8aa3defSJoshua M. Clulow 			if (ddi_in_panic() &&
309*b8aa3defSJoshua M. Clulow 			    (opdi->srpo_dtype == SMRT_DTYPE_SATA ||
310*b8aa3defSJoshua M. Clulow 			    opdi->srpo_dtype == SMRT_DTYPE_SAS)) {
311*b8aa3defSJoshua M. Clulow 				boolean_t visible;
312*b8aa3defSJoshua M. Clulow 
313*b8aa3defSJoshua M. Clulow 				visible = smrt_physical_visible(
314*b8aa3defSJoshua M. Clulow 				    &smpt->smpt_addr.PhysDev, smpt->smpt_info);
315*b8aa3defSJoshua M. Clulow 
316*b8aa3defSJoshua M. Clulow 				if (visible != smpt->smpt_visible) {
317*b8aa3defSJoshua M. Clulow 					dev_err(smrt->smrt_dip, CE_PANIC,
318*b8aa3defSJoshua M. Clulow 					    "physical target with wwn 0x%"
319*b8aa3defSJoshua M. Clulow 					    PRIx64 " changed visibility status "
320*b8aa3defSJoshua M. Clulow 					    "unexpectedly", wwn);
321*b8aa3defSJoshua M. Clulow 				}
322*b8aa3defSJoshua M. Clulow 			}
323*b8aa3defSJoshua M. Clulow 
324*b8aa3defSJoshua M. Clulow 			kmem_free(smpt->smpt_info, sizeof (*smpt->smpt_info));
325*b8aa3defSJoshua M. Clulow 			smpt->smpt_info = NULL;
326*b8aa3defSJoshua M. Clulow 		} else {
327*b8aa3defSJoshua M. Clulow 			smpt = kmem_zalloc(sizeof (smrt_physical_t),
328*b8aa3defSJoshua M. Clulow 			    KM_NOSLEEP);
329*b8aa3defSJoshua M. Clulow 			if (smpt == NULL) {
330*b8aa3defSJoshua M. Clulow 				kmem_free(info, sizeof (*info));
331*b8aa3defSJoshua M. Clulow 				return (ENOMEM);
332*b8aa3defSJoshua M. Clulow 			}
333*b8aa3defSJoshua M. Clulow 
334*b8aa3defSJoshua M. Clulow 			smpt->smpt_wwn = wwn;
335*b8aa3defSJoshua M. Clulow 			smpt->smpt_dtype = opdi->srpo_dtype;
336*b8aa3defSJoshua M. Clulow 			list_create(&smpt->smpt_targets, sizeof (smrt_target_t),
337*b8aa3defSJoshua M. Clulow 			    offsetof(smrt_target_t, smtg_link_lun));
338*b8aa3defSJoshua M. Clulow 			smpt->smpt_ctlr = smrt;
339*b8aa3defSJoshua M. Clulow 			list_insert_tail(&smrt->smrt_physicals, smpt);
340*b8aa3defSJoshua M. Clulow 		}
341*b8aa3defSJoshua M. Clulow 
342*b8aa3defSJoshua M. Clulow 		VERIFY3P(smpt->smpt_info, ==, NULL);
343*b8aa3defSJoshua M. Clulow 
344*b8aa3defSJoshua M. Clulow 		/*
345*b8aa3defSJoshua M. Clulow 		 * Determine if this device is supported and if it's visible to
346*b8aa3defSJoshua M. Clulow 		 * the system.  Some devices may not be visible to the system
347*b8aa3defSJoshua M. Clulow 		 * because they're used in logical volumes or spares.
348*b8aa3defSJoshua M. Clulow 		 * Unsupported devices are also not visible.
349*b8aa3defSJoshua M. Clulow 		 */
350*b8aa3defSJoshua M. Clulow 		switch (smpt->smpt_dtype) {
351*b8aa3defSJoshua M. Clulow 		case SMRT_DTYPE_SATA:
352*b8aa3defSJoshua M. Clulow 		case SMRT_DTYPE_SAS:
353*b8aa3defSJoshua M. Clulow 			smpt->smpt_supported = B_TRUE;
354*b8aa3defSJoshua M. Clulow 			smpt->smpt_visible =
355*b8aa3defSJoshua M. Clulow 			    smrt_physical_visible(&extents[i].srple_addr, info);
356*b8aa3defSJoshua M. Clulow 			break;
357*b8aa3defSJoshua M. Clulow 		case SMRT_DTYPE_SES:
358*b8aa3defSJoshua M. Clulow 			smpt->smpt_supported = B_TRUE;
359*b8aa3defSJoshua M. Clulow 			smpt->smpt_visible =
360*b8aa3defSJoshua M. Clulow 			    smrt_physical_visible(&extents[i].srple_addr, info);
361*b8aa3defSJoshua M. Clulow 			break;
362*b8aa3defSJoshua M. Clulow 		default:
363*b8aa3defSJoshua M. Clulow 			smpt->smpt_visible = B_FALSE;
364*b8aa3defSJoshua M. Clulow 			smpt->smpt_supported = B_FALSE;
365*b8aa3defSJoshua M. Clulow 		}
366*b8aa3defSJoshua M. Clulow 
367*b8aa3defSJoshua M. Clulow 		smpt->smpt_info = info;
368*b8aa3defSJoshua M. Clulow 		smpt->smpt_addr.PhysDev = extents[i].srple_addr;
369*b8aa3defSJoshua M. Clulow 		smpt->smpt_bmic = bmic;
370*b8aa3defSJoshua M. Clulow 		smpt->smpt_gen = gen;
371*b8aa3defSJoshua M. Clulow 		(void) scsi_wwn_to_wwnstr(smpt->smpt_wwn, 1, name);
372*b8aa3defSJoshua M. Clulow 		if (!ddi_in_panic() && smpt->smpt_visible &&
373*b8aa3defSJoshua M. Clulow 		    scsi_hba_tgtmap_set_add(smrt->smrt_phys_tgtmap,
374*b8aa3defSJoshua M. Clulow 		    SCSI_TGT_SCSI_DEVICE, name, NULL) != DDI_SUCCESS) {
375*b8aa3defSJoshua M. Clulow 			return (EIO);
376*b8aa3defSJoshua M. Clulow 		}
377*b8aa3defSJoshua M. Clulow 	}
378*b8aa3defSJoshua M. Clulow 
379*b8aa3defSJoshua M. Clulow 	return (0);
380*b8aa3defSJoshua M. Clulow }
381*b8aa3defSJoshua M. Clulow 
382*b8aa3defSJoshua M. Clulow int
smrt_phys_discover(smrt_t * smrt,uint16_t timeout,uint64_t gen)383*b8aa3defSJoshua M. Clulow smrt_phys_discover(smrt_t *smrt, uint16_t timeout, uint64_t gen)
384*b8aa3defSJoshua M. Clulow {
385*b8aa3defSJoshua M. Clulow 	smrt_command_t *smcm;
386*b8aa3defSJoshua M. Clulow 	smrt_report_physical_lun_t *smrpl;
387*b8aa3defSJoshua M. Clulow 	smrt_report_physical_lun_req_t smrplr;
388*b8aa3defSJoshua M. Clulow 	int r;
389*b8aa3defSJoshua M. Clulow 
390*b8aa3defSJoshua M. Clulow 	/*
391*b8aa3defSJoshua M. Clulow 	 * Allocate the command to send to the device, including buffer space
392*b8aa3defSJoshua M. Clulow 	 * for the returned list of Physical Volumes.
393*b8aa3defSJoshua M. Clulow 	 */
394*b8aa3defSJoshua M. Clulow 	if ((smcm = smrt_command_alloc(smrt, SMRT_CMDTYPE_INTERNAL,
395*b8aa3defSJoshua M. Clulow 	    KM_NOSLEEP)) == NULL || smrt_command_attach_internal(smrt, smcm,
396*b8aa3defSJoshua M. Clulow 	    sizeof (*smrpl), KM_NOSLEEP) != 0) {
397*b8aa3defSJoshua M. Clulow 		r = ENOMEM;
398*b8aa3defSJoshua M. Clulow 		mutex_enter(&smrt->smrt_mutex);
399*b8aa3defSJoshua M. Clulow 		goto out;
400*b8aa3defSJoshua M. Clulow 	}
401*b8aa3defSJoshua M. Clulow 
402*b8aa3defSJoshua M. Clulow 	smrpl = smcm->smcm_internal->smcmi_va;
403*b8aa3defSJoshua M. Clulow 
404*b8aa3defSJoshua M. Clulow 	smrt_write_controller_lun_addr(&smcm->smcm_va_cmd->Header.LUN);
405*b8aa3defSJoshua M. Clulow 
406*b8aa3defSJoshua M. Clulow 	smcm->smcm_va_cmd->Request.CDBLen = sizeof (smrplr);
407*b8aa3defSJoshua M. Clulow 	smcm->smcm_va_cmd->Request.Timeout = LE_16(timeout);
408*b8aa3defSJoshua M. Clulow 	smcm->smcm_va_cmd->Request.Type.Type = CISS_TYPE_CMD;
409*b8aa3defSJoshua M. Clulow 	smcm->smcm_va_cmd->Request.Type.Attribute = CISS_ATTR_SIMPLE;
410*b8aa3defSJoshua M. Clulow 	smcm->smcm_va_cmd->Request.Type.Direction = CISS_XFER_READ;
411*b8aa3defSJoshua M. Clulow 
412*b8aa3defSJoshua M. Clulow 	/*
413*b8aa3defSJoshua M. Clulow 	 * The Report Physical LUNs command is essentially a vendor-specific
414*b8aa3defSJoshua M. Clulow 	 * SCSI command, which we assemble into the CDB region of the command
415*b8aa3defSJoshua M. Clulow 	 * block.
416*b8aa3defSJoshua M. Clulow 	 */
417*b8aa3defSJoshua M. Clulow 	bzero(&smrplr, sizeof (smrplr));
418*b8aa3defSJoshua M. Clulow 	smrplr.smrplr_opcode = CISS_SCMD_REPORT_PHYSICAL_LUNS;
419*b8aa3defSJoshua M. Clulow 	smrplr.smrplr_extflag = SMRT_REPORT_PHYSICAL_LUN_EXT_OPDI;
420*b8aa3defSJoshua M. Clulow 	smrplr.smrplr_datasize = BE_32(sizeof (smrt_report_physical_lun_t));
421*b8aa3defSJoshua M. Clulow 	bcopy(&smrplr, &smcm->smcm_va_cmd->Request.CDB[0],
422*b8aa3defSJoshua M. Clulow 	    MIN(CISS_CDBLEN, sizeof (smrplr)));
423*b8aa3defSJoshua M. Clulow 
424*b8aa3defSJoshua M. Clulow 	mutex_enter(&smrt->smrt_mutex);
425*b8aa3defSJoshua M. Clulow 
426*b8aa3defSJoshua M. Clulow 	/*
427*b8aa3defSJoshua M. Clulow 	 * Send the command to the device.
428*b8aa3defSJoshua M. Clulow 	 */
429*b8aa3defSJoshua M. Clulow 	smcm->smcm_status |= SMRT_CMD_STATUS_POLLED;
430*b8aa3defSJoshua M. Clulow 	if ((r = smrt_submit(smrt, smcm)) != 0) {
431*b8aa3defSJoshua M. Clulow 		goto out;
432*b8aa3defSJoshua M. Clulow 	}
433*b8aa3defSJoshua M. Clulow 
434*b8aa3defSJoshua M. Clulow 	/*
435*b8aa3defSJoshua M. Clulow 	 * Poll for completion.
436*b8aa3defSJoshua M. Clulow 	 */
437*b8aa3defSJoshua M. Clulow 	smcm->smcm_expiry = gethrtime() + timeout * NANOSEC;
438*b8aa3defSJoshua M. Clulow 	if ((r = smrt_poll_for(smrt, smcm)) != 0) {
439*b8aa3defSJoshua M. Clulow 		VERIFY3S(r, ==, ETIMEDOUT);
440*b8aa3defSJoshua M. Clulow 		VERIFY0(smcm->smcm_status & SMRT_CMD_STATUS_POLL_COMPLETE);
441*b8aa3defSJoshua M. Clulow 
442*b8aa3defSJoshua M. Clulow 		/*
443*b8aa3defSJoshua M. Clulow 		 * The command timed out; abandon it now.  Remove the POLLED
444*b8aa3defSJoshua M. Clulow 		 * flag so that the periodic routine will send an abort to
445*b8aa3defSJoshua M. Clulow 		 * clean it up next time around.
446*b8aa3defSJoshua M. Clulow 		 */
447*b8aa3defSJoshua M. Clulow 		smcm->smcm_status |= SMRT_CMD_STATUS_ABANDONED;
448*b8aa3defSJoshua M. Clulow 		smcm->smcm_status &= ~SMRT_CMD_STATUS_POLLED;
449*b8aa3defSJoshua M. Clulow 		smcm = NULL;
450*b8aa3defSJoshua M. Clulow 		goto out;
451*b8aa3defSJoshua M. Clulow 	}
452*b8aa3defSJoshua M. Clulow 
453*b8aa3defSJoshua M. Clulow 	if (smcm->smcm_status & SMRT_CMD_STATUS_RESET_SENT) {
454*b8aa3defSJoshua M. Clulow 		/*
455*b8aa3defSJoshua M. Clulow 		 *
456*b8aa3defSJoshua M. Clulow 		 * The controller was reset while we were trying to discover
457*b8aa3defSJoshua M. Clulow 		 * logical volumes.  Report failure.
458*b8aa3defSJoshua M. Clulow 		 */
459*b8aa3defSJoshua M. Clulow 		r = EIO;
460*b8aa3defSJoshua M. Clulow 		goto out;
461*b8aa3defSJoshua M. Clulow 	}
462*b8aa3defSJoshua M. Clulow 
463*b8aa3defSJoshua M. Clulow 	if (smcm->smcm_status & SMRT_CMD_STATUS_ERROR) {
464*b8aa3defSJoshua M. Clulow 		ErrorInfo_t *ei = smcm->smcm_va_err;
465*b8aa3defSJoshua M. Clulow 
466*b8aa3defSJoshua M. Clulow 		if (ei->CommandStatus != CISS_CMD_DATA_UNDERRUN) {
467*b8aa3defSJoshua M. Clulow 			dev_err(smrt->smrt_dip, CE_WARN, "physical target "
468*b8aa3defSJoshua M. Clulow 			    "discovery error: status 0x%x", ei->CommandStatus);
469*b8aa3defSJoshua M. Clulow 			r = EIO;
470*b8aa3defSJoshua M. Clulow 			goto out;
471*b8aa3defSJoshua M. Clulow 		}
472*b8aa3defSJoshua M. Clulow 	}
473*b8aa3defSJoshua M. Clulow 
474*b8aa3defSJoshua M. Clulow 	/*
475*b8aa3defSJoshua M. Clulow 	 * If the controller doesn't support extended physical reporting, it
476*b8aa3defSJoshua M. Clulow 	 * likely doesn't even support physical devices that we'd care about
477*b8aa3defSJoshua M. Clulow 	 * exposing.  As such, we treat this as an OK case.
478*b8aa3defSJoshua M. Clulow 	 */
479*b8aa3defSJoshua M. Clulow 	if ((smrpl->smrpl_extflag & SMRT_REPORT_PHYSICAL_LUN_EXT_MASK) !=
480*b8aa3defSJoshua M. Clulow 	    SMRT_REPORT_PHYSICAL_LUN_EXT_OPDI) {
481*b8aa3defSJoshua M. Clulow 		r = 0;
482*b8aa3defSJoshua M. Clulow 		goto out;
483*b8aa3defSJoshua M. Clulow 	}
484*b8aa3defSJoshua M. Clulow 
485*b8aa3defSJoshua M. Clulow 	if (!ddi_in_panic() &&
486*b8aa3defSJoshua M. Clulow 	    scsi_hba_tgtmap_set_begin(smrt->smrt_phys_tgtmap) != DDI_SUCCESS) {
487*b8aa3defSJoshua M. Clulow 		dev_err(smrt->smrt_dip, CE_WARN, "failed to begin target map "
488*b8aa3defSJoshua M. Clulow 		    "observation on %s", SMRT_IPORT_PHYS);
489*b8aa3defSJoshua M. Clulow 		r = EIO;
490*b8aa3defSJoshua M. Clulow 		goto out;
491*b8aa3defSJoshua M. Clulow 	}
492*b8aa3defSJoshua M. Clulow 
493*b8aa3defSJoshua M. Clulow 	r = smrt_read_phys_ext(smrt, smrpl, timeout, gen);
494*b8aa3defSJoshua M. Clulow 
495*b8aa3defSJoshua M. Clulow 	if (r == 0 && !ddi_in_panic()) {
496*b8aa3defSJoshua M. Clulow 		if (scsi_hba_tgtmap_set_end(smrt->smrt_phys_tgtmap, 0) !=
497*b8aa3defSJoshua M. Clulow 		    DDI_SUCCESS) {
498*b8aa3defSJoshua M. Clulow 			dev_err(smrt->smrt_dip, CE_WARN, "failed to end target "
499*b8aa3defSJoshua M. Clulow 			    "map observation on %s", SMRT_IPORT_PHYS);
500*b8aa3defSJoshua M. Clulow 			r = EIO;
501*b8aa3defSJoshua M. Clulow 		}
502*b8aa3defSJoshua M. Clulow 	} else if (r != 0 && !ddi_in_panic()) {
503*b8aa3defSJoshua M. Clulow 		if (scsi_hba_tgtmap_set_flush(smrt->smrt_phys_tgtmap) !=
504*b8aa3defSJoshua M. Clulow 		    DDI_SUCCESS) {
505*b8aa3defSJoshua M. Clulow 			dev_err(smrt->smrt_dip, CE_WARN, "failed to end target "
506*b8aa3defSJoshua M. Clulow 			    "map observation on %s", SMRT_IPORT_PHYS);
507*b8aa3defSJoshua M. Clulow 			r = EIO;
508*b8aa3defSJoshua M. Clulow 		}
509*b8aa3defSJoshua M. Clulow 	}
510*b8aa3defSJoshua M. Clulow 
511*b8aa3defSJoshua M. Clulow 	if (r == 0) {
512*b8aa3defSJoshua M. Clulow 		smrt_physical_t *smpt, *next;
513*b8aa3defSJoshua M. Clulow 
514*b8aa3defSJoshua M. Clulow 		/*
515*b8aa3defSJoshua M. Clulow 		 * Prune physical devices that do not match the current
516*b8aa3defSJoshua M. Clulow 		 * generation and are not marked as visible devices.  Visible
517*b8aa3defSJoshua M. Clulow 		 * devices will be dealt with as part of the target map work.
518*b8aa3defSJoshua M. Clulow 		 */
519*b8aa3defSJoshua M. Clulow 		for (smpt = list_head(&smrt->smrt_physicals), next = NULL;
520*b8aa3defSJoshua M. Clulow 		    smpt != NULL; smpt = next) {
521*b8aa3defSJoshua M. Clulow 			next = list_next(&smrt->smrt_physicals, smpt);
522*b8aa3defSJoshua M. Clulow 			if (smpt->smpt_visible || smpt->smpt_gen == gen)
523*b8aa3defSJoshua M. Clulow 				continue;
524*b8aa3defSJoshua M. Clulow 			list_remove(&smrt->smrt_physicals, smpt);
525*b8aa3defSJoshua M. Clulow 			smrt_physical_free(smpt);
526*b8aa3defSJoshua M. Clulow 		}
527*b8aa3defSJoshua M. Clulow 
528*b8aa3defSJoshua M. Clulow 		/*
529*b8aa3defSJoshua M. Clulow 		 * Update the time of the last successful Physical Volume
530*b8aa3defSJoshua M. Clulow 		 * discovery:
531*b8aa3defSJoshua M. Clulow 		 */
532*b8aa3defSJoshua M. Clulow 		smrt->smrt_last_phys_discovery = gethrtime();
533*b8aa3defSJoshua M. Clulow 
534*b8aa3defSJoshua M. Clulow 		/*
535*b8aa3defSJoshua M. Clulow 		 * Now, for each unsupported device that we haven't warned about
536*b8aa3defSJoshua M. Clulow 		 * encountering, try and give the administrator some hope of
537*b8aa3defSJoshua M. Clulow 		 * knowing about this.
538*b8aa3defSJoshua M. Clulow 		 */
539*b8aa3defSJoshua M. Clulow 		for (smpt = list_head(&smrt->smrt_physicals), next = NULL;
540*b8aa3defSJoshua M. Clulow 		    smpt != NULL; smpt = next) {
541*b8aa3defSJoshua M. Clulow 			if (smpt->smpt_supported || smpt->smpt_unsup_warn)
542*b8aa3defSJoshua M. Clulow 				continue;
543*b8aa3defSJoshua M. Clulow 			smpt->smpt_unsup_warn = B_TRUE;
544*b8aa3defSJoshua M. Clulow 			dev_err(smrt->smrt_dip, CE_WARN, "encountered "
545*b8aa3defSJoshua M. Clulow 			    "unsupported device with device type %d",
546*b8aa3defSJoshua M. Clulow 			    smpt->smpt_dtype);
547*b8aa3defSJoshua M. Clulow 		}
548*b8aa3defSJoshua M. Clulow 	}
549*b8aa3defSJoshua M. Clulow 
550*b8aa3defSJoshua M. Clulow out:
551*b8aa3defSJoshua M. Clulow 	mutex_exit(&smrt->smrt_mutex);
552*b8aa3defSJoshua M. Clulow 
553*b8aa3defSJoshua M. Clulow 	if (smcm != NULL) {
554*b8aa3defSJoshua M. Clulow 		smrt_command_free(smcm);
555*b8aa3defSJoshua M. Clulow 	}
556*b8aa3defSJoshua M. Clulow 	return (r);
557*b8aa3defSJoshua M. Clulow }
558*b8aa3defSJoshua M. Clulow 
559*b8aa3defSJoshua M. Clulow void
smrt_phys_tgtmap_activate(void * arg,char * addr,scsi_tgtmap_tgt_type_t type,void ** privpp)560*b8aa3defSJoshua M. Clulow smrt_phys_tgtmap_activate(void *arg, char *addr, scsi_tgtmap_tgt_type_t type,
561*b8aa3defSJoshua M. Clulow     void **privpp)
562*b8aa3defSJoshua M. Clulow {
563*b8aa3defSJoshua M. Clulow 	smrt_t *smrt = arg;
564*b8aa3defSJoshua M. Clulow 	smrt_physical_t *smpt;
565*b8aa3defSJoshua M. Clulow 
566*b8aa3defSJoshua M. Clulow 	VERIFY3S(type, ==, SCSI_TGT_SCSI_DEVICE);
567*b8aa3defSJoshua M. Clulow 	mutex_enter(&smrt->smrt_mutex);
568*b8aa3defSJoshua M. Clulow 	smpt = smrt_phys_lookup_by_ua(smrt, addr);
569*b8aa3defSJoshua M. Clulow 	VERIFY(smpt != NULL);
570*b8aa3defSJoshua M. Clulow 	VERIFY(smpt->smpt_supported);
571*b8aa3defSJoshua M. Clulow 	VERIFY(smpt->smpt_visible);
572*b8aa3defSJoshua M. Clulow 	*privpp = NULL;
573*b8aa3defSJoshua M. Clulow 	mutex_exit(&smrt->smrt_mutex);
574*b8aa3defSJoshua M. Clulow }
575*b8aa3defSJoshua M. Clulow 
576*b8aa3defSJoshua M. Clulow boolean_t
smrt_phys_tgtmap_deactivate(void * arg,char * addr,scsi_tgtmap_tgt_type_t type,void * priv,scsi_tgtmap_deact_rsn_t reason)577*b8aa3defSJoshua M. Clulow smrt_phys_tgtmap_deactivate(void *arg, char *addr, scsi_tgtmap_tgt_type_t type,
578*b8aa3defSJoshua M. Clulow     void *priv, scsi_tgtmap_deact_rsn_t reason)
579*b8aa3defSJoshua M. Clulow {
580*b8aa3defSJoshua M. Clulow 	smrt_t *smrt = arg;
581*b8aa3defSJoshua M. Clulow 	smrt_physical_t *smpt;
582*b8aa3defSJoshua M. Clulow 
583*b8aa3defSJoshua M. Clulow 	VERIFY3S(type, ==, SCSI_TGT_SCSI_DEVICE);
584*b8aa3defSJoshua M. Clulow 	VERIFY3P(priv, ==, NULL);
585*b8aa3defSJoshua M. Clulow 
586*b8aa3defSJoshua M. Clulow 	mutex_enter(&smrt->smrt_mutex);
587*b8aa3defSJoshua M. Clulow 	smpt = smrt_phys_lookup_by_ua(smrt, addr);
588*b8aa3defSJoshua M. Clulow 
589*b8aa3defSJoshua M. Clulow 	/*
590*b8aa3defSJoshua M. Clulow 	 * If the device disappeared or became invisible, then it may have
591*b8aa3defSJoshua M. Clulow 	 * already been removed.
592*b8aa3defSJoshua M. Clulow 	 */
593*b8aa3defSJoshua M. Clulow 	if (smpt == NULL || !smpt->smpt_visible) {
594*b8aa3defSJoshua M. Clulow 		mutex_exit(&smrt->smrt_mutex);
595*b8aa3defSJoshua M. Clulow 		return (B_FALSE);
596*b8aa3defSJoshua M. Clulow 	}
597*b8aa3defSJoshua M. Clulow 
598*b8aa3defSJoshua M. Clulow 	list_remove(&smrt->smrt_physicals, smpt);
599*b8aa3defSJoshua M. Clulow 	smrt_physical_free(smpt);
600*b8aa3defSJoshua M. Clulow 	mutex_exit(&smrt->smrt_mutex);
601*b8aa3defSJoshua M. Clulow 	return (B_FALSE);
602*b8aa3defSJoshua M. Clulow }
603*b8aa3defSJoshua M. Clulow 
604*b8aa3defSJoshua M. Clulow void
smrt_phys_teardown(smrt_t * smrt)605*b8aa3defSJoshua M. Clulow smrt_phys_teardown(smrt_t *smrt)
606*b8aa3defSJoshua M. Clulow {
607*b8aa3defSJoshua M. Clulow 	smrt_physical_t *smpt;
608*b8aa3defSJoshua M. Clulow 
609*b8aa3defSJoshua M. Clulow 	while ((smpt = list_remove_head(&smrt->smrt_physicals)) != NULL) {
610*b8aa3defSJoshua M. Clulow 		smrt_physical_free(smpt);
611*b8aa3defSJoshua M. Clulow 	}
612*b8aa3defSJoshua M. Clulow }
613