xref: /illumos-gate/usr/src/uts/common/io/scsi/adapters/smrt/smrt_logvol.c (revision b8aa3def2e2531e693fba6d1f00a74339a4a663d)
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_logvol_free(smrt_volume_t * smlv)19*b8aa3defSJoshua M. Clulow smrt_logvol_free(smrt_volume_t *smlv)
20*b8aa3defSJoshua M. Clulow {
21*b8aa3defSJoshua M. Clulow 	/*
22*b8aa3defSJoshua M. Clulow 	 * By this stage of teardown, all of the SCSI target drivers
23*b8aa3defSJoshua M. Clulow 	 * must have been detached from this logical volume.
24*b8aa3defSJoshua M. Clulow 	 */
25*b8aa3defSJoshua M. Clulow 	VERIFY(list_is_empty(&smlv->smlv_targets));
26*b8aa3defSJoshua M. Clulow 	list_destroy(&smlv->smlv_targets);
27*b8aa3defSJoshua M. Clulow 
28*b8aa3defSJoshua M. Clulow 	kmem_free(smlv, sizeof (*smlv));
29*b8aa3defSJoshua M. Clulow }
30*b8aa3defSJoshua M. Clulow 
31*b8aa3defSJoshua M. Clulow smrt_volume_t *
smrt_logvol_lookup_by_id(smrt_t * smrt,unsigned long id)32*b8aa3defSJoshua M. Clulow smrt_logvol_lookup_by_id(smrt_t *smrt, unsigned long id)
33*b8aa3defSJoshua M. Clulow {
34*b8aa3defSJoshua M. Clulow 	VERIFY(MUTEX_HELD(&smrt->smrt_mutex));
35*b8aa3defSJoshua M. Clulow 
36*b8aa3defSJoshua M. Clulow 	for (smrt_volume_t *smlv = list_head(&smrt->smrt_volumes);
37*b8aa3defSJoshua M. Clulow 	    smlv != NULL; smlv = list_next(&smrt->smrt_volumes, smlv)) {
38*b8aa3defSJoshua M. Clulow 		if (smlv->smlv_addr.LogDev.VolId == id) {
39*b8aa3defSJoshua M. Clulow 			return (smlv);
40*b8aa3defSJoshua M. Clulow 		}
41*b8aa3defSJoshua M. Clulow 	}
42*b8aa3defSJoshua M. Clulow 
43*b8aa3defSJoshua M. Clulow 	return (NULL);
44*b8aa3defSJoshua M. Clulow }
45*b8aa3defSJoshua M. Clulow 
46*b8aa3defSJoshua M. Clulow static int
smrt_read_logvols(smrt_t * smrt,smrt_report_logical_lun_t * smrll,uint64_t gen)47*b8aa3defSJoshua M. Clulow smrt_read_logvols(smrt_t *smrt, smrt_report_logical_lun_t *smrll, uint64_t gen)
48*b8aa3defSJoshua M. Clulow {
49*b8aa3defSJoshua M. Clulow 	smrt_report_logical_lun_ent_t *ents = smrll->smrll_data.ents;
50*b8aa3defSJoshua M. Clulow 	uint32_t count = BE_32(smrll->smrll_datasize) /
51*b8aa3defSJoshua M. Clulow 	    sizeof (smrt_report_logical_lun_ent_t);
52*b8aa3defSJoshua M. Clulow 
53*b8aa3defSJoshua M. Clulow 	VERIFY(MUTEX_HELD(&smrt->smrt_mutex));
54*b8aa3defSJoshua M. Clulow 
55*b8aa3defSJoshua M. Clulow 	if (count > SMRT_MAX_LOGDRV) {
56*b8aa3defSJoshua M. Clulow 		count = SMRT_MAX_LOGDRV;
57*b8aa3defSJoshua M. Clulow 	}
58*b8aa3defSJoshua M. Clulow 
59*b8aa3defSJoshua M. Clulow 	for (unsigned i = 0; i < count; i++) {
60*b8aa3defSJoshua M. Clulow 		smrt_volume_t *smlv;
61*b8aa3defSJoshua M. Clulow 		char id[SCSI_MAXNAMELEN];
62*b8aa3defSJoshua M. Clulow 
63*b8aa3defSJoshua M. Clulow 		DTRACE_PROBE2(read_logvol, unsigned, i,
64*b8aa3defSJoshua M. Clulow 		    smrt_report_logical_lun_ent_t *, &ents[i]);
65*b8aa3defSJoshua M. Clulow 
66*b8aa3defSJoshua M. Clulow 		if ((smlv = smrt_logvol_lookup_by_id(smrt,
67*b8aa3defSJoshua M. Clulow 		    ents[i].smrle_addr.VolId)) == NULL) {
68*b8aa3defSJoshua M. Clulow 
69*b8aa3defSJoshua M. Clulow 			/*
70*b8aa3defSJoshua M. Clulow 			 * This is a new Logical Volume, so add it the the list.
71*b8aa3defSJoshua M. Clulow 			 */
72*b8aa3defSJoshua M. Clulow 			if ((smlv = kmem_zalloc(sizeof (*smlv), KM_NOSLEEP)) ==
73*b8aa3defSJoshua M. Clulow 			    NULL) {
74*b8aa3defSJoshua M. Clulow 				return (ENOMEM);
75*b8aa3defSJoshua M. Clulow 			}
76*b8aa3defSJoshua M. Clulow 
77*b8aa3defSJoshua M. Clulow 			list_create(&smlv->smlv_targets,
78*b8aa3defSJoshua M. Clulow 			    sizeof (smrt_target_t),
79*b8aa3defSJoshua M. Clulow 			    offsetof(smrt_target_t, smtg_link_lun));
80*b8aa3defSJoshua M. Clulow 
81*b8aa3defSJoshua M. Clulow 			smlv->smlv_ctlr = smrt;
82*b8aa3defSJoshua M. Clulow 			list_insert_tail(&smrt->smrt_volumes, smlv);
83*b8aa3defSJoshua M. Clulow 		}
84*b8aa3defSJoshua M. Clulow 
85*b8aa3defSJoshua M. Clulow 		/*
86*b8aa3defSJoshua M. Clulow 		 * Always make sure that the address and the generation are up
87*b8aa3defSJoshua M. Clulow 		 * to date, regardless of where this came from.
88*b8aa3defSJoshua M. Clulow 		 */
89*b8aa3defSJoshua M. Clulow 		smlv->smlv_addr.LogDev = ents[i].smrle_addr;
90*b8aa3defSJoshua M. Clulow 		smlv->smlv_gen = gen;
91*b8aa3defSJoshua M. Clulow 		(void) snprintf(id, sizeof (id), "%x",
92*b8aa3defSJoshua M. Clulow 		    smlv->smlv_addr.LogDev.VolId);
93*b8aa3defSJoshua M. Clulow 		if (!ddi_in_panic() &&
94*b8aa3defSJoshua M. Clulow 		    scsi_hba_tgtmap_set_add(smrt->smrt_virt_tgtmap,
95*b8aa3defSJoshua M. Clulow 		    SCSI_TGT_SCSI_DEVICE, id, NULL) != DDI_SUCCESS) {
96*b8aa3defSJoshua M. Clulow 			return (EIO);
97*b8aa3defSJoshua M. Clulow 		}
98*b8aa3defSJoshua M. Clulow 	}
99*b8aa3defSJoshua M. Clulow 
100*b8aa3defSJoshua M. Clulow 	return (0);
101*b8aa3defSJoshua M. Clulow }
102*b8aa3defSJoshua M. Clulow 
103*b8aa3defSJoshua M. Clulow static int
smrt_read_logvols_ext(smrt_t * smrt,smrt_report_logical_lun_t * smrll,uint64_t gen)104*b8aa3defSJoshua M. Clulow smrt_read_logvols_ext(smrt_t *smrt, smrt_report_logical_lun_t *smrll,
105*b8aa3defSJoshua M. Clulow     uint64_t gen)
106*b8aa3defSJoshua M. Clulow {
107*b8aa3defSJoshua M. Clulow 	smrt_report_logical_lun_extent_t *extents =
108*b8aa3defSJoshua M. Clulow 	    smrll->smrll_data.extents;
109*b8aa3defSJoshua M. Clulow 	uint32_t count = BE_32(smrll->smrll_datasize) /
110*b8aa3defSJoshua M. Clulow 	    sizeof (smrt_report_logical_lun_extent_t);
111*b8aa3defSJoshua M. Clulow 
112*b8aa3defSJoshua M. Clulow 	VERIFY(MUTEX_HELD(&smrt->smrt_mutex));
113*b8aa3defSJoshua M. Clulow 
114*b8aa3defSJoshua M. Clulow 	if (count > SMRT_MAX_LOGDRV) {
115*b8aa3defSJoshua M. Clulow 		count = SMRT_MAX_LOGDRV;
116*b8aa3defSJoshua M. Clulow 	}
117*b8aa3defSJoshua M. Clulow 
118*b8aa3defSJoshua M. Clulow 	for (unsigned i = 0; i < count; i++) {
119*b8aa3defSJoshua M. Clulow 		smrt_volume_t *smlv;
120*b8aa3defSJoshua M. Clulow 		char id[SCSI_MAXNAMELEN];
121*b8aa3defSJoshua M. Clulow 
122*b8aa3defSJoshua M. Clulow 		DTRACE_PROBE2(read_logvol_ext, unsigned, i,
123*b8aa3defSJoshua M. Clulow 		    smrt_report_logical_lun_extent_t *, &extents[i]);
124*b8aa3defSJoshua M. Clulow 
125*b8aa3defSJoshua M. Clulow 		if ((smlv = smrt_logvol_lookup_by_id(smrt,
126*b8aa3defSJoshua M. Clulow 		    extents[i].smrle_addr.VolId)) != NULL) {
127*b8aa3defSJoshua M. Clulow 			if ((smlv->smlv_flags & SMRT_VOL_FLAG_WWN) &&
128*b8aa3defSJoshua M. Clulow 			    bcmp(extents[i].smrle_wwn, smlv->smlv_wwn,
129*b8aa3defSJoshua M. Clulow 			    16) != 0) {
130*b8aa3defSJoshua M. Clulow 				dev_err(smrt->smrt_dip, CE_PANIC, "logical "
131*b8aa3defSJoshua M. Clulow 				    "volume %u WWN changed unexpectedly", i);
132*b8aa3defSJoshua M. Clulow 			}
133*b8aa3defSJoshua M. Clulow 		} else {
134*b8aa3defSJoshua M. Clulow 			/*
135*b8aa3defSJoshua M. Clulow 			 * This is a new Logical Volume, so add it the the list.
136*b8aa3defSJoshua M. Clulow 			 */
137*b8aa3defSJoshua M. Clulow 			if ((smlv = kmem_zalloc(sizeof (*smlv), KM_NOSLEEP)) ==
138*b8aa3defSJoshua M. Clulow 			    NULL) {
139*b8aa3defSJoshua M. Clulow 				return (ENOMEM);
140*b8aa3defSJoshua M. Clulow 			}
141*b8aa3defSJoshua M. Clulow 
142*b8aa3defSJoshua M. Clulow 			bcopy(extents[i].smrle_wwn, smlv->smlv_wwn, 16);
143*b8aa3defSJoshua M. Clulow 			smlv->smlv_flags |= SMRT_VOL_FLAG_WWN;
144*b8aa3defSJoshua M. Clulow 
145*b8aa3defSJoshua M. Clulow 			list_create(&smlv->smlv_targets,
146*b8aa3defSJoshua M. Clulow 			    sizeof (smrt_target_t),
147*b8aa3defSJoshua M. Clulow 			    offsetof(smrt_target_t, smtg_link_lun));
148*b8aa3defSJoshua M. Clulow 
149*b8aa3defSJoshua M. Clulow 			smlv->smlv_ctlr = smrt;
150*b8aa3defSJoshua M. Clulow 			list_insert_tail(&smrt->smrt_volumes, smlv);
151*b8aa3defSJoshua M. Clulow 		}
152*b8aa3defSJoshua M. Clulow 
153*b8aa3defSJoshua M. Clulow 		/*
154*b8aa3defSJoshua M. Clulow 		 * Always make sure that the address and the generation are up
155*b8aa3defSJoshua M. Clulow 		 * to date.  The address may have changed on a reset.
156*b8aa3defSJoshua M. Clulow 		 */
157*b8aa3defSJoshua M. Clulow 		smlv->smlv_addr.LogDev = extents[i].smrle_addr;
158*b8aa3defSJoshua M. Clulow 		smlv->smlv_gen = gen;
159*b8aa3defSJoshua M. Clulow 		(void) snprintf(id, sizeof (id), "%x",
160*b8aa3defSJoshua M. Clulow 		    smlv->smlv_addr.LogDev.VolId);
161*b8aa3defSJoshua M. Clulow 		if (!ddi_in_panic() &&
162*b8aa3defSJoshua M. Clulow 		    scsi_hba_tgtmap_set_add(smrt->smrt_virt_tgtmap,
163*b8aa3defSJoshua M. Clulow 		    SCSI_TGT_SCSI_DEVICE, id, NULL) != DDI_SUCCESS) {
164*b8aa3defSJoshua M. Clulow 			return (EIO);
165*b8aa3defSJoshua M. Clulow 		}
166*b8aa3defSJoshua M. Clulow 	}
167*b8aa3defSJoshua M. Clulow 
168*b8aa3defSJoshua M. Clulow 	return (0);
169*b8aa3defSJoshua M. Clulow }
170*b8aa3defSJoshua M. Clulow 
171*b8aa3defSJoshua M. Clulow /*
172*b8aa3defSJoshua M. Clulow  * Discover the currently visible set of Logical Volumes exposed by the
173*b8aa3defSJoshua M. Clulow  * controller.
174*b8aa3defSJoshua M. Clulow  */
175*b8aa3defSJoshua M. Clulow int
smrt_logvol_discover(smrt_t * smrt,uint16_t timeout,uint64_t gen)176*b8aa3defSJoshua M. Clulow smrt_logvol_discover(smrt_t *smrt, uint16_t timeout, uint64_t gen)
177*b8aa3defSJoshua M. Clulow {
178*b8aa3defSJoshua M. Clulow 	smrt_command_t *smcm;
179*b8aa3defSJoshua M. Clulow 	smrt_report_logical_lun_t *smrll;
180*b8aa3defSJoshua M. Clulow 	smrt_report_logical_lun_req_t smrllr = { 0 };
181*b8aa3defSJoshua M. Clulow 	int r;
182*b8aa3defSJoshua M. Clulow 
183*b8aa3defSJoshua M. Clulow 	/*
184*b8aa3defSJoshua M. Clulow 	 * Allocate the command to send to the device, including buffer space
185*b8aa3defSJoshua M. Clulow 	 * for the returned list of Logical Volumes.
186*b8aa3defSJoshua M. Clulow 	 */
187*b8aa3defSJoshua M. Clulow 	if ((smcm = smrt_command_alloc(smrt, SMRT_CMDTYPE_INTERNAL,
188*b8aa3defSJoshua M. Clulow 	    KM_NOSLEEP)) == NULL || smrt_command_attach_internal(smrt, smcm,
189*b8aa3defSJoshua M. Clulow 	    sizeof (smrt_report_logical_lun_t), KM_NOSLEEP) != 0) {
190*b8aa3defSJoshua M. Clulow 		r = ENOMEM;
191*b8aa3defSJoshua M. Clulow 		mutex_enter(&smrt->smrt_mutex);
192*b8aa3defSJoshua M. Clulow 		goto out;
193*b8aa3defSJoshua M. Clulow 	}
194*b8aa3defSJoshua M. Clulow 
195*b8aa3defSJoshua M. Clulow 	smrll = smcm->smcm_internal->smcmi_va;
196*b8aa3defSJoshua M. Clulow 
197*b8aa3defSJoshua M. Clulow 	smrt_write_controller_lun_addr(&smcm->smcm_va_cmd->Header.LUN);
198*b8aa3defSJoshua M. Clulow 
199*b8aa3defSJoshua M. Clulow 	smcm->smcm_va_cmd->Request.CDBLen = sizeof (smrllr);
200*b8aa3defSJoshua M. Clulow 	smcm->smcm_va_cmd->Request.Timeout = LE_16(timeout);
201*b8aa3defSJoshua M. Clulow 	smcm->smcm_va_cmd->Request.Type.Type = CISS_TYPE_CMD;
202*b8aa3defSJoshua M. Clulow 	smcm->smcm_va_cmd->Request.Type.Attribute = CISS_ATTR_SIMPLE;
203*b8aa3defSJoshua M. Clulow 	smcm->smcm_va_cmd->Request.Type.Direction = CISS_XFER_READ;
204*b8aa3defSJoshua M. Clulow 
205*b8aa3defSJoshua M. Clulow 	/*
206*b8aa3defSJoshua M. Clulow 	 * The Report Logical LUNs command is essentially a vendor-specific
207*b8aa3defSJoshua M. Clulow 	 * SCSI command, which we assemble into the CDB region of the command
208*b8aa3defSJoshua M. Clulow 	 * block.
209*b8aa3defSJoshua M. Clulow 	 */
210*b8aa3defSJoshua M. Clulow 	bzero(&smrllr, sizeof (smrllr));
211*b8aa3defSJoshua M. Clulow 	smrllr.smrllr_opcode = CISS_SCMD_REPORT_LOGICAL_LUNS;
212*b8aa3defSJoshua M. Clulow 	smrllr.smrllr_extflag = 1;
213*b8aa3defSJoshua M. Clulow 	smrllr.smrllr_datasize = htonl(sizeof (smrt_report_logical_lun_t));
214*b8aa3defSJoshua M. Clulow 	bcopy(&smrllr, &smcm->smcm_va_cmd->Request.CDB[0],
215*b8aa3defSJoshua M. Clulow 	    MIN(CISS_CDBLEN, sizeof (smrllr)));
216*b8aa3defSJoshua M. Clulow 
217*b8aa3defSJoshua M. Clulow 	mutex_enter(&smrt->smrt_mutex);
218*b8aa3defSJoshua M. Clulow 
219*b8aa3defSJoshua M. Clulow 	/*
220*b8aa3defSJoshua M. Clulow 	 * Send the command to the device.
221*b8aa3defSJoshua M. Clulow 	 */
222*b8aa3defSJoshua M. Clulow 	smcm->smcm_status |= SMRT_CMD_STATUS_POLLED;
223*b8aa3defSJoshua M. Clulow 	if ((r = smrt_submit(smrt, smcm)) != 0) {
224*b8aa3defSJoshua M. Clulow 		goto out;
225*b8aa3defSJoshua M. Clulow 	}
226*b8aa3defSJoshua M. Clulow 
227*b8aa3defSJoshua M. Clulow 	/*
228*b8aa3defSJoshua M. Clulow 	 * Poll for completion.
229*b8aa3defSJoshua M. Clulow 	 */
230*b8aa3defSJoshua M. Clulow 	smcm->smcm_expiry = gethrtime() + timeout * NANOSEC;
231*b8aa3defSJoshua M. Clulow 	if ((r = smrt_poll_for(smrt, smcm)) != 0) {
232*b8aa3defSJoshua M. Clulow 		VERIFY3S(r, ==, ETIMEDOUT);
233*b8aa3defSJoshua M. Clulow 		VERIFY0(smcm->smcm_status & SMRT_CMD_STATUS_POLL_COMPLETE);
234*b8aa3defSJoshua M. Clulow 
235*b8aa3defSJoshua M. Clulow 		/*
236*b8aa3defSJoshua M. Clulow 		 * The command timed out; abandon it now.  Remove the POLLED
237*b8aa3defSJoshua M. Clulow 		 * flag so that the periodic routine will send an abort to
238*b8aa3defSJoshua M. Clulow 		 * clean it up next time around.
239*b8aa3defSJoshua M. Clulow 		 */
240*b8aa3defSJoshua M. Clulow 		smcm->smcm_status |= SMRT_CMD_STATUS_ABANDONED;
241*b8aa3defSJoshua M. Clulow 		smcm->smcm_status &= ~SMRT_CMD_STATUS_POLLED;
242*b8aa3defSJoshua M. Clulow 		smcm = NULL;
243*b8aa3defSJoshua M. Clulow 		goto out;
244*b8aa3defSJoshua M. Clulow 	}
245*b8aa3defSJoshua M. Clulow 
246*b8aa3defSJoshua M. Clulow 	if (smcm->smcm_status & SMRT_CMD_STATUS_RESET_SENT) {
247*b8aa3defSJoshua M. Clulow 		/*
248*b8aa3defSJoshua M. Clulow 		 * The controller was reset while we were trying to discover
249*b8aa3defSJoshua M. Clulow 		 * logical volumes.  Report failure.
250*b8aa3defSJoshua M. Clulow 		 */
251*b8aa3defSJoshua M. Clulow 		r = EIO;
252*b8aa3defSJoshua M. Clulow 		goto out;
253*b8aa3defSJoshua M. Clulow 	}
254*b8aa3defSJoshua M. Clulow 
255*b8aa3defSJoshua M. Clulow 	if (smcm->smcm_status & SMRT_CMD_STATUS_ERROR) {
256*b8aa3defSJoshua M. Clulow 		ErrorInfo_t *ei = smcm->smcm_va_err;
257*b8aa3defSJoshua M. Clulow 
258*b8aa3defSJoshua M. Clulow 		if (ei->CommandStatus != CISS_CMD_DATA_UNDERRUN) {
259*b8aa3defSJoshua M. Clulow 			dev_err(smrt->smrt_dip, CE_WARN, "logical volume "
260*b8aa3defSJoshua M. Clulow 			    "discovery error: status 0x%x", ei->CommandStatus);
261*b8aa3defSJoshua M. Clulow 			r = EIO;
262*b8aa3defSJoshua M. Clulow 			goto out;
263*b8aa3defSJoshua M. Clulow 		}
264*b8aa3defSJoshua M. Clulow 	}
265*b8aa3defSJoshua M. Clulow 
266*b8aa3defSJoshua M. Clulow 	if (!ddi_in_panic() &&
267*b8aa3defSJoshua M. Clulow 	    scsi_hba_tgtmap_set_begin(smrt->smrt_virt_tgtmap) != DDI_SUCCESS) {
268*b8aa3defSJoshua M. Clulow 		dev_err(smrt->smrt_dip, CE_WARN, "failed to begin target map "
269*b8aa3defSJoshua M. Clulow 		    "observation on %s", SMRT_IPORT_VIRT);
270*b8aa3defSJoshua M. Clulow 		r = EIO;
271*b8aa3defSJoshua M. Clulow 		goto out;
272*b8aa3defSJoshua M. Clulow 	}
273*b8aa3defSJoshua M. Clulow 
274*b8aa3defSJoshua M. Clulow 	if ((smrll->smrll_extflag & 0x1) != 0) {
275*b8aa3defSJoshua M. Clulow 		r = smrt_read_logvols_ext(smrt, smrll, gen);
276*b8aa3defSJoshua M. Clulow 	} else {
277*b8aa3defSJoshua M. Clulow 		r = smrt_read_logvols(smrt, smrll, gen);
278*b8aa3defSJoshua M. Clulow 	}
279*b8aa3defSJoshua M. Clulow 
280*b8aa3defSJoshua M. Clulow 	if (r == 0 && !ddi_in_panic()) {
281*b8aa3defSJoshua M. Clulow 		if (scsi_hba_tgtmap_set_end(smrt->smrt_virt_tgtmap, 0) !=
282*b8aa3defSJoshua M. Clulow 		    DDI_SUCCESS) {
283*b8aa3defSJoshua M. Clulow 			dev_err(smrt->smrt_dip, CE_WARN, "failed to end target "
284*b8aa3defSJoshua M. Clulow 			    "map observation on %s", SMRT_IPORT_VIRT);
285*b8aa3defSJoshua M. Clulow 			r = EIO;
286*b8aa3defSJoshua M. Clulow 		}
287*b8aa3defSJoshua M. Clulow 	} else if (r != 0 && !ddi_in_panic()) {
288*b8aa3defSJoshua M. Clulow 		if (scsi_hba_tgtmap_set_flush(smrt->smrt_virt_tgtmap) !=
289*b8aa3defSJoshua M. Clulow 		    DDI_SUCCESS) {
290*b8aa3defSJoshua M. Clulow 			dev_err(smrt->smrt_dip, CE_WARN, "failed to end target "
291*b8aa3defSJoshua M. Clulow 			    "map observation on %s", SMRT_IPORT_VIRT);
292*b8aa3defSJoshua M. Clulow 			r = EIO;
293*b8aa3defSJoshua M. Clulow 		}
294*b8aa3defSJoshua M. Clulow 	}
295*b8aa3defSJoshua M. Clulow 
296*b8aa3defSJoshua M. Clulow 	if (r == 0) {
297*b8aa3defSJoshua M. Clulow 		/*
298*b8aa3defSJoshua M. Clulow 		 * Update the time of the last successful Logical Volume
299*b8aa3defSJoshua M. Clulow 		 * discovery:
300*b8aa3defSJoshua M. Clulow 		 */
301*b8aa3defSJoshua M. Clulow 		smrt->smrt_last_log_discovery = gethrtime();
302*b8aa3defSJoshua M. Clulow 	}
303*b8aa3defSJoshua M. Clulow 
304*b8aa3defSJoshua M. Clulow out:
305*b8aa3defSJoshua M. Clulow 	mutex_exit(&smrt->smrt_mutex);
306*b8aa3defSJoshua M. Clulow 
307*b8aa3defSJoshua M. Clulow 	if (smcm != NULL) {
308*b8aa3defSJoshua M. Clulow 		smrt_command_free(smcm);
309*b8aa3defSJoshua M. Clulow 	}
310*b8aa3defSJoshua M. Clulow 	return (r);
311*b8aa3defSJoshua M. Clulow }
312*b8aa3defSJoshua M. Clulow 
313*b8aa3defSJoshua M. Clulow void
smrt_logvol_tgtmap_activate(void * arg,char * addr,scsi_tgtmap_tgt_type_t type,void ** privpp)314*b8aa3defSJoshua M. Clulow smrt_logvol_tgtmap_activate(void *arg, char *addr, scsi_tgtmap_tgt_type_t type,
315*b8aa3defSJoshua M. Clulow     void **privpp)
316*b8aa3defSJoshua M. Clulow {
317*b8aa3defSJoshua M. Clulow 	smrt_t *smrt = arg;
318*b8aa3defSJoshua M. Clulow 	unsigned long volume;
319*b8aa3defSJoshua M. Clulow 	char *eptr;
320*b8aa3defSJoshua M. Clulow 
321*b8aa3defSJoshua M. Clulow 	VERIFY(type == SCSI_TGT_SCSI_DEVICE);
322*b8aa3defSJoshua M. Clulow 	VERIFY0(ddi_strtoul(addr, &eptr, 16, &volume));
323*b8aa3defSJoshua M. Clulow 	VERIFY3S(*eptr, ==, '\0');
324*b8aa3defSJoshua M. Clulow 	VERIFY3S(volume, >=, 0);
325*b8aa3defSJoshua M. Clulow 	VERIFY3S(volume, <, SMRT_MAX_LOGDRV);
326*b8aa3defSJoshua M. Clulow 	mutex_enter(&smrt->smrt_mutex);
327*b8aa3defSJoshua M. Clulow 	VERIFY(smrt_logvol_lookup_by_id(smrt, volume) != NULL);
328*b8aa3defSJoshua M. Clulow 	mutex_exit(&smrt->smrt_mutex);
329*b8aa3defSJoshua M. Clulow 	*privpp = NULL;
330*b8aa3defSJoshua M. Clulow }
331*b8aa3defSJoshua M. Clulow 
332*b8aa3defSJoshua M. Clulow boolean_t
smrt_logvol_tgtmap_deactivate(void * arg,char * addr,scsi_tgtmap_tgt_type_t type,void * priv,scsi_tgtmap_deact_rsn_t reason)333*b8aa3defSJoshua M. Clulow smrt_logvol_tgtmap_deactivate(void *arg, char *addr,
334*b8aa3defSJoshua M. Clulow     scsi_tgtmap_tgt_type_t type, void *priv, scsi_tgtmap_deact_rsn_t reason)
335*b8aa3defSJoshua M. Clulow {
336*b8aa3defSJoshua M. Clulow 	smrt_t *smrt = arg;
337*b8aa3defSJoshua M. Clulow 	smrt_volume_t *smlv;
338*b8aa3defSJoshua M. Clulow 	unsigned long volume;
339*b8aa3defSJoshua M. Clulow 	char *eptr;
340*b8aa3defSJoshua M. Clulow 
341*b8aa3defSJoshua M. Clulow 	VERIFY(type == SCSI_TGT_SCSI_DEVICE);
342*b8aa3defSJoshua M. Clulow 	VERIFY(priv == NULL);
343*b8aa3defSJoshua M. Clulow 	VERIFY0(ddi_strtoul(addr, &eptr, 16, &volume));
344*b8aa3defSJoshua M. Clulow 	VERIFY3S(*eptr, ==, '\0');
345*b8aa3defSJoshua M. Clulow 	VERIFY3S(volume, >=, 0);
346*b8aa3defSJoshua M. Clulow 	VERIFY3S(volume, <, SMRT_MAX_LOGDRV);
347*b8aa3defSJoshua M. Clulow 
348*b8aa3defSJoshua M. Clulow 	mutex_enter(&smrt->smrt_mutex);
349*b8aa3defSJoshua M. Clulow 	smlv = smrt_logvol_lookup_by_id(smrt, volume);
350*b8aa3defSJoshua M. Clulow 	VERIFY(smlv != NULL);
351*b8aa3defSJoshua M. Clulow 
352*b8aa3defSJoshua M. Clulow 	list_remove(&smrt->smrt_volumes, smlv);
353*b8aa3defSJoshua M. Clulow 	smrt_logvol_free(smlv);
354*b8aa3defSJoshua M. Clulow 	mutex_exit(&smrt->smrt_mutex);
355*b8aa3defSJoshua M. Clulow 
356*b8aa3defSJoshua M. Clulow 	return (B_FALSE);
357*b8aa3defSJoshua M. Clulow }
358*b8aa3defSJoshua M. Clulow 
359*b8aa3defSJoshua M. Clulow void
smrt_logvol_teardown(smrt_t * smrt)360*b8aa3defSJoshua M. Clulow smrt_logvol_teardown(smrt_t *smrt)
361*b8aa3defSJoshua M. Clulow {
362*b8aa3defSJoshua M. Clulow 	smrt_volume_t *smlv;
363*b8aa3defSJoshua M. Clulow 
364*b8aa3defSJoshua M. Clulow 	while ((smlv = list_remove_head(&smrt->smrt_volumes)) != NULL) {
365*b8aa3defSJoshua M. Clulow 		smrt_logvol_free(smlv);
366*b8aa3defSJoshua M. Clulow 	}
367*b8aa3defSJoshua M. Clulow }
368