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 2019 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 /*
19*b8aa3defSJoshua M. Clulow  * The controller is not allowed to attach.
20*b8aa3defSJoshua M. Clulow  */
21*b8aa3defSJoshua M. Clulow static int
smrt_ctrl_tran_tgt_init(dev_info_t * hba_dip,dev_info_t * tgt_dip,scsi_hba_tran_t * hba_tran,struct scsi_device * sd)22*b8aa3defSJoshua M. Clulow smrt_ctrl_tran_tgt_init(dev_info_t *hba_dip, dev_info_t *tgt_dip,
23*b8aa3defSJoshua M. Clulow     scsi_hba_tran_t *hba_tran, struct scsi_device *sd)
24*b8aa3defSJoshua M. Clulow {
25*b8aa3defSJoshua M. Clulow 	return (DDI_FAILURE);
26*b8aa3defSJoshua M. Clulow }
27*b8aa3defSJoshua M. Clulow 
28*b8aa3defSJoshua M. Clulow /*
29*b8aa3defSJoshua M. Clulow  * The controller is not allowed to send packets.
30*b8aa3defSJoshua M. Clulow  */
31*b8aa3defSJoshua M. Clulow static int
smrt_ctrl_tran_start(struct scsi_address * sa,struct scsi_pkt * pkt)32*b8aa3defSJoshua M. Clulow smrt_ctrl_tran_start(struct scsi_address *sa, struct scsi_pkt *pkt)
33*b8aa3defSJoshua M. Clulow {
34*b8aa3defSJoshua M. Clulow 	return (TRAN_BADPKT);
35*b8aa3defSJoshua M. Clulow }
36*b8aa3defSJoshua M. Clulow 
37*b8aa3defSJoshua M. Clulow static boolean_t
smrt_logvol_parse(const char * ua,uint_t * targp)38*b8aa3defSJoshua M. Clulow smrt_logvol_parse(const char *ua, uint_t *targp)
39*b8aa3defSJoshua M. Clulow {
40*b8aa3defSJoshua M. Clulow 	long targ, lun;
41*b8aa3defSJoshua M. Clulow 	const char *comma;
42*b8aa3defSJoshua M. Clulow 	char *eptr;
43*b8aa3defSJoshua M. Clulow 
44*b8aa3defSJoshua M. Clulow 	comma = strchr(ua, ',');
45*b8aa3defSJoshua M. Clulow 	if (comma == NULL) {
46*b8aa3defSJoshua M. Clulow 		return (B_FALSE);
47*b8aa3defSJoshua M. Clulow 	}
48*b8aa3defSJoshua M. Clulow 
49*b8aa3defSJoshua M. Clulow 	/*
50*b8aa3defSJoshua M. Clulow 	 * We expect the target number for a logical unit number to be zero for
51*b8aa3defSJoshua M. Clulow 	 * a logical volume.
52*b8aa3defSJoshua M. Clulow 	 */
53*b8aa3defSJoshua M. Clulow 	if (ddi_strtol(comma + 1, &eptr, 16, &lun) != 0 || *eptr != '\0' ||
54*b8aa3defSJoshua M. Clulow 	    lun != 0) {
55*b8aa3defSJoshua M. Clulow 		return (B_FALSE);
56*b8aa3defSJoshua M. Clulow 	}
57*b8aa3defSJoshua M. Clulow 
58*b8aa3defSJoshua M. Clulow 	if (ddi_strtol(ua, &eptr, 16, &targ) != 0 || eptr != comma ||
59*b8aa3defSJoshua M. Clulow 	    targ < 0 || targ >= SMRT_MAX_LOGDRV) {
60*b8aa3defSJoshua M. Clulow 		return (B_FALSE);
61*b8aa3defSJoshua M. Clulow 	}
62*b8aa3defSJoshua M. Clulow 
63*b8aa3defSJoshua M. Clulow 	*targp = (uint_t)targ;
64*b8aa3defSJoshua M. Clulow 
65*b8aa3defSJoshua M. Clulow 	return (B_TRUE);
66*b8aa3defSJoshua M. Clulow }
67*b8aa3defSJoshua M. Clulow 
68*b8aa3defSJoshua M. Clulow static int
smrt_logvol_tran_tgt_init(dev_info_t * hba_dip,dev_info_t * tgt_dip,scsi_hba_tran_t * hba_tran,struct scsi_device * sd)69*b8aa3defSJoshua M. Clulow smrt_logvol_tran_tgt_init(dev_info_t *hba_dip, dev_info_t *tgt_dip,
70*b8aa3defSJoshua M. Clulow     scsi_hba_tran_t *hba_tran, struct scsi_device *sd)
71*b8aa3defSJoshua M. Clulow {
72*b8aa3defSJoshua M. Clulow 	_NOTE(ARGUNUSED(hba_dip))
73*b8aa3defSJoshua M. Clulow 
74*b8aa3defSJoshua M. Clulow 	smrt_volume_t *smlv;
75*b8aa3defSJoshua M. Clulow 	smrt_target_t *smtg;
76*b8aa3defSJoshua M. Clulow 	const char *ua;
77*b8aa3defSJoshua M. Clulow 	uint_t targ;
78*b8aa3defSJoshua M. Clulow 
79*b8aa3defSJoshua M. Clulow 	smrt_t *smrt = (smrt_t *)hba_tran->tran_hba_private;
80*b8aa3defSJoshua M. Clulow 	dev_info_t *dip = smrt->smrt_dip;
81*b8aa3defSJoshua M. Clulow 
82*b8aa3defSJoshua M. Clulow 	/*
83*b8aa3defSJoshua M. Clulow 	 * The unit address comes in the form of 'target,lun'.  We expect the
84*b8aa3defSJoshua M. Clulow 	 * lun to be zero.  The target is what we set when we added it to the
85*b8aa3defSJoshua M. Clulow 	 * target map earlier.
86*b8aa3defSJoshua M. Clulow 	 */
87*b8aa3defSJoshua M. Clulow 	ua = scsi_device_unit_address(sd);
88*b8aa3defSJoshua M. Clulow 	if (ua == NULL) {
89*b8aa3defSJoshua M. Clulow 		return (DDI_FAILURE);
90*b8aa3defSJoshua M. Clulow 	}
91*b8aa3defSJoshua M. Clulow 
92*b8aa3defSJoshua M. Clulow 	if (!smrt_logvol_parse(ua, &targ)) {
93*b8aa3defSJoshua M. Clulow 		return (DDI_FAILURE);
94*b8aa3defSJoshua M. Clulow 	}
95*b8aa3defSJoshua M. Clulow 
96*b8aa3defSJoshua M. Clulow 	if ((smtg = kmem_zalloc(sizeof (*smtg), KM_NOSLEEP)) == NULL) {
97*b8aa3defSJoshua M. Clulow 		dev_err(dip, CE_WARN, "could not allocate target object "
98*b8aa3defSJoshua M. Clulow 		    "due to memory exhaustion");
99*b8aa3defSJoshua M. Clulow 		return (DDI_FAILURE);
100*b8aa3defSJoshua M. Clulow 	}
101*b8aa3defSJoshua M. Clulow 
102*b8aa3defSJoshua M. Clulow 	mutex_enter(&smrt->smrt_mutex);
103*b8aa3defSJoshua M. Clulow 
104*b8aa3defSJoshua M. Clulow 	if (smrt->smrt_status & SMRT_CTLR_STATUS_DETACHING) {
105*b8aa3defSJoshua M. Clulow 		/*
106*b8aa3defSJoshua M. Clulow 		 * We are detaching.  Do not accept any more requests to
107*b8aa3defSJoshua M. Clulow 		 * attach targets from the framework.
108*b8aa3defSJoshua M. Clulow 		 */
109*b8aa3defSJoshua M. Clulow 		mutex_exit(&smrt->smrt_mutex);
110*b8aa3defSJoshua M. Clulow 		kmem_free(smtg, sizeof (*smtg));
111*b8aa3defSJoshua M. Clulow 		return (DDI_FAILURE);
112*b8aa3defSJoshua M. Clulow 	}
113*b8aa3defSJoshua M. Clulow 
114*b8aa3defSJoshua M. Clulow 	/*
115*b8aa3defSJoshua M. Clulow 	 * Look for a logical volume for the SCSI unit address of this target.
116*b8aa3defSJoshua M. Clulow 	 */
117*b8aa3defSJoshua M. Clulow 	if ((smlv = smrt_logvol_lookup_by_id(smrt, targ)) == NULL) {
118*b8aa3defSJoshua M. Clulow 		mutex_exit(&smrt->smrt_mutex);
119*b8aa3defSJoshua M. Clulow 		kmem_free(smtg, sizeof (*smtg));
120*b8aa3defSJoshua M. Clulow 		return (DDI_FAILURE);
121*b8aa3defSJoshua M. Clulow 	}
122*b8aa3defSJoshua M. Clulow 
123*b8aa3defSJoshua M. Clulow 	smtg->smtg_lun.smtg_vol = smlv;
124*b8aa3defSJoshua M. Clulow 	smtg->smtg_addr = &smlv->smlv_addr;
125*b8aa3defSJoshua M. Clulow 	smtg->smtg_physical = B_FALSE;
126*b8aa3defSJoshua M. Clulow 	list_insert_tail(&smlv->smlv_targets, smtg);
127*b8aa3defSJoshua M. Clulow 
128*b8aa3defSJoshua M. Clulow 	/*
129*b8aa3defSJoshua M. Clulow 	 * Link this target object to the controller:
130*b8aa3defSJoshua M. Clulow 	 */
131*b8aa3defSJoshua M. Clulow 	smtg->smtg_ctlr = smrt;
132*b8aa3defSJoshua M. Clulow 	list_insert_tail(&smrt->smrt_targets, smtg);
133*b8aa3defSJoshua M. Clulow 
134*b8aa3defSJoshua M. Clulow 	smtg->smtg_scsi_dev = sd;
135*b8aa3defSJoshua M. Clulow 	VERIFY(sd->sd_dev == tgt_dip);
136*b8aa3defSJoshua M. Clulow 
137*b8aa3defSJoshua M. Clulow 	scsi_device_hba_private_set(sd, smtg);
138*b8aa3defSJoshua M. Clulow 
139*b8aa3defSJoshua M. Clulow 	mutex_exit(&smrt->smrt_mutex);
140*b8aa3defSJoshua M. Clulow 	return (DDI_SUCCESS);
141*b8aa3defSJoshua M. Clulow }
142*b8aa3defSJoshua M. Clulow 
143*b8aa3defSJoshua M. Clulow static void
smrt_logvol_tran_tgt_free(dev_info_t * hba_dip,dev_info_t * tgt_dip,scsi_hba_tran_t * hba_tran,struct scsi_device * sd)144*b8aa3defSJoshua M. Clulow smrt_logvol_tran_tgt_free(dev_info_t *hba_dip, dev_info_t *tgt_dip,
145*b8aa3defSJoshua M. Clulow     scsi_hba_tran_t *hba_tran, struct scsi_device *sd)
146*b8aa3defSJoshua M. Clulow {
147*b8aa3defSJoshua M. Clulow 	_NOTE(ARGUNUSED(hba_dip, tgt_dip))
148*b8aa3defSJoshua M. Clulow 
149*b8aa3defSJoshua M. Clulow 	smrt_t *smrt = (smrt_t *)hba_tran->tran_hba_private;
150*b8aa3defSJoshua M. Clulow 	smrt_target_t *smtg = scsi_device_hba_private_get(sd);
151*b8aa3defSJoshua M. Clulow 	smrt_volume_t *smlv = smtg->smtg_lun.smtg_vol;
152*b8aa3defSJoshua M. Clulow 
153*b8aa3defSJoshua M. Clulow 	VERIFY(smtg->smtg_scsi_dev == sd);
154*b8aa3defSJoshua M. Clulow 	VERIFY(smtg->smtg_physical == B_FALSE);
155*b8aa3defSJoshua M. Clulow 
156*b8aa3defSJoshua M. Clulow 	mutex_enter(&smrt->smrt_mutex);
157*b8aa3defSJoshua M. Clulow 	list_remove(&smlv->smlv_targets, smtg);
158*b8aa3defSJoshua M. Clulow 	list_remove(&smrt->smrt_targets, smtg);
159*b8aa3defSJoshua M. Clulow 
160*b8aa3defSJoshua M. Clulow 	scsi_device_hba_private_set(sd, NULL);
161*b8aa3defSJoshua M. Clulow 
162*b8aa3defSJoshua M. Clulow 	mutex_exit(&smrt->smrt_mutex);
163*b8aa3defSJoshua M. Clulow 
164*b8aa3defSJoshua M. Clulow 	kmem_free(smtg, sizeof (*smtg));
165*b8aa3defSJoshua M. Clulow }
166*b8aa3defSJoshua M. Clulow 
167*b8aa3defSJoshua M. Clulow static int
smrt_phys_tran_tgt_init(dev_info_t * hba_dip,dev_info_t * tgt_dip,scsi_hba_tran_t * hba_tran,struct scsi_device * sd)168*b8aa3defSJoshua M. Clulow smrt_phys_tran_tgt_init(dev_info_t *hba_dip, dev_info_t *tgt_dip,
169*b8aa3defSJoshua M. Clulow     scsi_hba_tran_t *hba_tran, struct scsi_device *sd)
170*b8aa3defSJoshua M. Clulow {
171*b8aa3defSJoshua M. Clulow 	_NOTE(ARGUNUSED(hba_dip))
172*b8aa3defSJoshua M. Clulow 
173*b8aa3defSJoshua M. Clulow 	smrt_target_t *smtg;
174*b8aa3defSJoshua M. Clulow 	smrt_physical_t *smpt;
175*b8aa3defSJoshua M. Clulow 	const char *ua, *comma;
176*b8aa3defSJoshua M. Clulow 	char *eptr;
177*b8aa3defSJoshua M. Clulow 	long lun;
178*b8aa3defSJoshua M. Clulow 
179*b8aa3defSJoshua M. Clulow 	smrt_t *smrt = (smrt_t *)hba_tran->tran_hba_private;
180*b8aa3defSJoshua M. Clulow 	dev_info_t *dip = smrt->smrt_dip;
181*b8aa3defSJoshua M. Clulow 
182*b8aa3defSJoshua M. Clulow 	/*
183*b8aa3defSJoshua M. Clulow 	 * The unit address comes in the form of 'target,lun'.  We expect the
184*b8aa3defSJoshua M. Clulow 	 * lun to be zero.  The target is what we set when we added it to the
185*b8aa3defSJoshua M. Clulow 	 * target map earlier.
186*b8aa3defSJoshua M. Clulow 	 */
187*b8aa3defSJoshua M. Clulow 	ua = scsi_device_unit_address(sd);
188*b8aa3defSJoshua M. Clulow 	if (ua == NULL)
189*b8aa3defSJoshua M. Clulow 		return (DDI_FAILURE);
190*b8aa3defSJoshua M. Clulow 
191*b8aa3defSJoshua M. Clulow 	comma = strchr(ua, ',');
192*b8aa3defSJoshua M. Clulow 	if (comma == NULL) {
193*b8aa3defSJoshua M. Clulow 		return (DDI_FAILURE);
194*b8aa3defSJoshua M. Clulow 	}
195*b8aa3defSJoshua M. Clulow 
196*b8aa3defSJoshua M. Clulow 	/*
197*b8aa3defSJoshua M. Clulow 	 * Confirm the LUN is zero.  We may want to instead check the scsi
198*b8aa3defSJoshua M. Clulow 	 * 'lun'/'lun64' property or do so in addition to this logic.
199*b8aa3defSJoshua M. Clulow 	 */
200*b8aa3defSJoshua M. Clulow 	if (ddi_strtol(comma + 1, &eptr, 16, &lun) != 0 || *eptr != '\0' ||
201*b8aa3defSJoshua M. Clulow 	    lun != 0) {
202*b8aa3defSJoshua M. Clulow 		return (DDI_FAILURE);
203*b8aa3defSJoshua M. Clulow 	}
204*b8aa3defSJoshua M. Clulow 
205*b8aa3defSJoshua M. Clulow 	if ((smtg = kmem_zalloc(sizeof (*smtg), KM_NOSLEEP)) == NULL) {
206*b8aa3defSJoshua M. Clulow 		dev_err(dip, CE_WARN, "could not allocate target object "
207*b8aa3defSJoshua M. Clulow 		    "due to memory exhaustion");
208*b8aa3defSJoshua M. Clulow 		return (DDI_FAILURE);
209*b8aa3defSJoshua M. Clulow 	}
210*b8aa3defSJoshua M. Clulow 
211*b8aa3defSJoshua M. Clulow 	mutex_enter(&smrt->smrt_mutex);
212*b8aa3defSJoshua M. Clulow 
213*b8aa3defSJoshua M. Clulow 	if (smrt->smrt_status & SMRT_CTLR_STATUS_DETACHING) {
214*b8aa3defSJoshua M. Clulow 		/*
215*b8aa3defSJoshua M. Clulow 		 * We are detaching.  Do not accept any more requests to
216*b8aa3defSJoshua M. Clulow 		 * attach targets from the framework.
217*b8aa3defSJoshua M. Clulow 		 */
218*b8aa3defSJoshua M. Clulow 		mutex_exit(&smrt->smrt_mutex);
219*b8aa3defSJoshua M. Clulow 		kmem_free(smtg, sizeof (*smtg));
220*b8aa3defSJoshua M. Clulow 		return (DDI_FAILURE);
221*b8aa3defSJoshua M. Clulow 	}
222*b8aa3defSJoshua M. Clulow 
223*b8aa3defSJoshua M. Clulow 
224*b8aa3defSJoshua M. Clulow 	/*
225*b8aa3defSJoshua M. Clulow 	 * Look for a physical target based on the unit address of the target
226*b8aa3defSJoshua M. Clulow 	 * (which will encode its WWN and LUN).
227*b8aa3defSJoshua M. Clulow 	 */
228*b8aa3defSJoshua M. Clulow 	smpt = smrt_phys_lookup_by_ua(smrt, ua);
229*b8aa3defSJoshua M. Clulow 	if (smpt == NULL) {
230*b8aa3defSJoshua M. Clulow 		mutex_exit(&smrt->smrt_mutex);
231*b8aa3defSJoshua M. Clulow 		kmem_free(smtg, sizeof (*smtg));
232*b8aa3defSJoshua M. Clulow 		return (DDI_FAILURE);
233*b8aa3defSJoshua M. Clulow 	}
234*b8aa3defSJoshua M. Clulow 
235*b8aa3defSJoshua M. Clulow 	smtg->smtg_scsi_dev = sd;
236*b8aa3defSJoshua M. Clulow 	smtg->smtg_physical = B_TRUE;
237*b8aa3defSJoshua M. Clulow 	smtg->smtg_lun.smtg_phys = smpt;
238*b8aa3defSJoshua M. Clulow 	list_insert_tail(&smpt->smpt_targets, smtg);
239*b8aa3defSJoshua M. Clulow 	smtg->smtg_addr = &smpt->smpt_addr;
240*b8aa3defSJoshua M. Clulow 
241*b8aa3defSJoshua M. Clulow 	/*
242*b8aa3defSJoshua M. Clulow 	 * Link this target object to the controller:
243*b8aa3defSJoshua M. Clulow 	 */
244*b8aa3defSJoshua M. Clulow 	smtg->smtg_ctlr = smrt;
245*b8aa3defSJoshua M. Clulow 	list_insert_tail(&smrt->smrt_targets, smtg);
246*b8aa3defSJoshua M. Clulow 
247*b8aa3defSJoshua M. Clulow 	VERIFY(sd->sd_dev == tgt_dip);
248*b8aa3defSJoshua M. Clulow 	smtg->smtg_scsi_dev = sd;
249*b8aa3defSJoshua M. Clulow 
250*b8aa3defSJoshua M. Clulow 	scsi_device_hba_private_set(sd, smtg);
251*b8aa3defSJoshua M. Clulow 	mutex_exit(&smrt->smrt_mutex);
252*b8aa3defSJoshua M. Clulow 
253*b8aa3defSJoshua M. Clulow 	return (DDI_SUCCESS);
254*b8aa3defSJoshua M. Clulow }
255*b8aa3defSJoshua M. Clulow 
256*b8aa3defSJoshua M. Clulow static void
smrt_phys_tran_tgt_free(dev_info_t * hba_dip,dev_info_t * tgt_dip,scsi_hba_tran_t * hba_tran,struct scsi_device * sd)257*b8aa3defSJoshua M. Clulow smrt_phys_tran_tgt_free(dev_info_t *hba_dip, dev_info_t *tgt_dip,
258*b8aa3defSJoshua M. Clulow     scsi_hba_tran_t *hba_tran, struct scsi_device *sd)
259*b8aa3defSJoshua M. Clulow {
260*b8aa3defSJoshua M. Clulow 	_NOTE(ARGUNUSED(hba_dip, tgt_dip))
261*b8aa3defSJoshua M. Clulow 
262*b8aa3defSJoshua M. Clulow 	smrt_t *smrt = (smrt_t *)hba_tran->tran_hba_private;
263*b8aa3defSJoshua M. Clulow 	smrt_target_t *smtg = scsi_device_hba_private_get(sd);
264*b8aa3defSJoshua M. Clulow 	smrt_physical_t *smpt = smtg->smtg_lun.smtg_phys;
265*b8aa3defSJoshua M. Clulow 
266*b8aa3defSJoshua M. Clulow 	VERIFY(smtg->smtg_scsi_dev == sd);
267*b8aa3defSJoshua M. Clulow 	VERIFY(smtg->smtg_physical == B_TRUE);
268*b8aa3defSJoshua M. Clulow 
269*b8aa3defSJoshua M. Clulow 	mutex_enter(&smrt->smrt_mutex);
270*b8aa3defSJoshua M. Clulow 	list_remove(&smpt->smpt_targets, smtg);
271*b8aa3defSJoshua M. Clulow 	list_remove(&smrt->smrt_targets, smtg);
272*b8aa3defSJoshua M. Clulow 
273*b8aa3defSJoshua M. Clulow 	scsi_device_hba_private_set(sd, NULL);
274*b8aa3defSJoshua M. Clulow 	mutex_exit(&smrt->smrt_mutex);
275*b8aa3defSJoshua M. Clulow 	kmem_free(smtg, sizeof (*smtg));
276*b8aa3defSJoshua M. Clulow }
277*b8aa3defSJoshua M. Clulow 
278*b8aa3defSJoshua M. Clulow /*
279*b8aa3defSJoshua M. Clulow  * This function is called when the SCSI framework has allocated a packet and
280*b8aa3defSJoshua M. Clulow  * our private per-packet object.
281*b8aa3defSJoshua M. Clulow  *
282*b8aa3defSJoshua M. Clulow  * We choose not to have the framework pre-allocate memory for the CDB.
283*b8aa3defSJoshua M. Clulow  * Instead, we will make available the CDB area in the controller command block
284*b8aa3defSJoshua M. Clulow  * itself.
285*b8aa3defSJoshua M. Clulow  *
286*b8aa3defSJoshua M. Clulow  * Status block memory is allocated by the framework because we passed
287*b8aa3defSJoshua M. Clulow  * SCSI_HBA_TRAN_SCB to scsi_hba_attach_setup(9F).
288*b8aa3defSJoshua M. Clulow  */
289*b8aa3defSJoshua M. Clulow static int
smrt_tran_setup_pkt(struct scsi_pkt * pkt,int (* callback)(caddr_t),caddr_t arg)290*b8aa3defSJoshua M. Clulow smrt_tran_setup_pkt(struct scsi_pkt *pkt, int (*callback)(caddr_t),
291*b8aa3defSJoshua M. Clulow     caddr_t arg)
292*b8aa3defSJoshua M. Clulow {
293*b8aa3defSJoshua M. Clulow 	_NOTE(ARGUNUSED(arg))
294*b8aa3defSJoshua M. Clulow 
295*b8aa3defSJoshua M. Clulow 	struct scsi_device *sd;
296*b8aa3defSJoshua M. Clulow 	smrt_target_t *smtg;
297*b8aa3defSJoshua M. Clulow 	smrt_t *smrt;
298*b8aa3defSJoshua M. Clulow 	smrt_command_t *smcm;
299*b8aa3defSJoshua M. Clulow 	smrt_command_scsa_t *smcms;
300*b8aa3defSJoshua M. Clulow 	int kmflags = callback == SLEEP_FUNC ? KM_SLEEP : KM_NOSLEEP;
301*b8aa3defSJoshua M. Clulow 
302*b8aa3defSJoshua M. Clulow 	sd = scsi_address_device(&pkt->pkt_address);
303*b8aa3defSJoshua M. Clulow 	VERIFY(sd != NULL);
304*b8aa3defSJoshua M. Clulow 	smtg = scsi_device_hba_private_get(sd);
305*b8aa3defSJoshua M. Clulow 	VERIFY(smtg != NULL);
306*b8aa3defSJoshua M. Clulow 	smrt = smtg->smtg_ctlr;
307*b8aa3defSJoshua M. Clulow 	VERIFY(smrt != NULL);
308*b8aa3defSJoshua M. Clulow 	smcms = (smrt_command_scsa_t *)pkt->pkt_ha_private;
309*b8aa3defSJoshua M. Clulow 
310*b8aa3defSJoshua M. Clulow 	/*
311*b8aa3defSJoshua M. Clulow 	 * Check that we have enough space in the command object for the
312*b8aa3defSJoshua M. Clulow 	 * request from the target driver:
313*b8aa3defSJoshua M. Clulow 	 */
314*b8aa3defSJoshua M. Clulow 	if (pkt->pkt_cdblen > CISS_CDBLEN) {
315*b8aa3defSJoshua M. Clulow 		/*
316*b8aa3defSJoshua M. Clulow 		 * The CDB member of the Request Block of a controller
317*b8aa3defSJoshua M. Clulow 		 * command is fixed at 16 bytes.
318*b8aa3defSJoshua M. Clulow 		 */
319*b8aa3defSJoshua M. Clulow 		dev_err(smrt->smrt_dip, CE_WARN, "oversize CDB: had %u, "
320*b8aa3defSJoshua M. Clulow 		    "needed %u", CISS_CDBLEN, pkt->pkt_cdblen);
321*b8aa3defSJoshua M. Clulow 		return (-1);
322*b8aa3defSJoshua M. Clulow 	}
323*b8aa3defSJoshua M. Clulow 
324*b8aa3defSJoshua M. Clulow 	/*
325*b8aa3defSJoshua M. Clulow 	 * Allocate our command block:
326*b8aa3defSJoshua M. Clulow 	 */
327*b8aa3defSJoshua M. Clulow 	if ((smcm = smrt_command_alloc(smrt, SMRT_CMDTYPE_SCSA,
328*b8aa3defSJoshua M. Clulow 	    kmflags)) == NULL) {
329*b8aa3defSJoshua M. Clulow 		return (-1);
330*b8aa3defSJoshua M. Clulow 	}
331*b8aa3defSJoshua M. Clulow 	smcm->smcm_scsa = smcms;
332*b8aa3defSJoshua M. Clulow 	smcms->smcms_command = smcm;
333*b8aa3defSJoshua M. Clulow 	smcms->smcms_pkt = pkt;
334*b8aa3defSJoshua M. Clulow 
335*b8aa3defSJoshua M. Clulow 	pkt->pkt_cdbp = &smcm->smcm_va_cmd->Request.CDB[0];
336*b8aa3defSJoshua M. Clulow 	smcm->smcm_va_cmd->Request.CDBLen = pkt->pkt_cdblen;
337*b8aa3defSJoshua M. Clulow 
338*b8aa3defSJoshua M. Clulow 	smcm->smcm_target = smtg;
339*b8aa3defSJoshua M. Clulow 
340*b8aa3defSJoshua M. Clulow 	return (0);
341*b8aa3defSJoshua M. Clulow }
342*b8aa3defSJoshua M. Clulow 
343*b8aa3defSJoshua M. Clulow static void
smrt_tran_teardown_pkt(struct scsi_pkt * pkt)344*b8aa3defSJoshua M. Clulow smrt_tran_teardown_pkt(struct scsi_pkt *pkt)
345*b8aa3defSJoshua M. Clulow {
346*b8aa3defSJoshua M. Clulow 	smrt_command_scsa_t *smcms = (smrt_command_scsa_t *)
347*b8aa3defSJoshua M. Clulow 	    pkt->pkt_ha_private;
348*b8aa3defSJoshua M. Clulow 	smrt_command_t *smcm = smcms->smcms_command;
349*b8aa3defSJoshua M. Clulow 
350*b8aa3defSJoshua M. Clulow 	smrt_command_free(smcm);
351*b8aa3defSJoshua M. Clulow 
352*b8aa3defSJoshua M. Clulow 	pkt->pkt_cdbp = NULL;
353*b8aa3defSJoshua M. Clulow }
354*b8aa3defSJoshua M. Clulow 
355*b8aa3defSJoshua M. Clulow static void
smrt_set_arq_data(struct scsi_pkt * pkt,uchar_t key)356*b8aa3defSJoshua M. Clulow smrt_set_arq_data(struct scsi_pkt *pkt, uchar_t key)
357*b8aa3defSJoshua M. Clulow {
358*b8aa3defSJoshua M. Clulow 	struct scsi_arq_status *sts;
359*b8aa3defSJoshua M. Clulow 
360*b8aa3defSJoshua M. Clulow 	VERIFY3U(pkt->pkt_scblen, >=, sizeof (struct scsi_arq_status));
361*b8aa3defSJoshua M. Clulow 
362*b8aa3defSJoshua M. Clulow 	/* LINTED: E_BAD_PTR_CAST_ALIGN */
363*b8aa3defSJoshua M. Clulow 	sts = (struct scsi_arq_status *)(pkt->pkt_scbp);
364*b8aa3defSJoshua M. Clulow 	bzero(sts, sizeof (*sts));
365*b8aa3defSJoshua M. Clulow 
366*b8aa3defSJoshua M. Clulow 	/*
367*b8aa3defSJoshua M. Clulow 	 * Mock up a CHECK CONDITION SCSI status for the original command:
368*b8aa3defSJoshua M. Clulow 	 */
369*b8aa3defSJoshua M. Clulow 	sts->sts_status.sts_chk = 1;
370*b8aa3defSJoshua M. Clulow 
371*b8aa3defSJoshua M. Clulow 	/*
372*b8aa3defSJoshua M. Clulow 	 * Pretend that we successfully performed REQUEST SENSE:
373*b8aa3defSJoshua M. Clulow 	 */
374*b8aa3defSJoshua M. Clulow 	sts->sts_rqpkt_reason = CMD_CMPLT;
375*b8aa3defSJoshua M. Clulow 	sts->sts_rqpkt_resid = 0;
376*b8aa3defSJoshua M. Clulow 	sts->sts_rqpkt_state = STATE_GOT_BUS | STATE_GOT_TARGET |
377*b8aa3defSJoshua M. Clulow 	    STATE_SENT_CMD | STATE_XFERRED_DATA;
378*b8aa3defSJoshua M. Clulow 	sts->sts_rqpkt_statistics = 0;
379*b8aa3defSJoshua M. Clulow 
380*b8aa3defSJoshua M. Clulow 	/*
381*b8aa3defSJoshua M. Clulow 	 * Return the key value we were provided in the fake sense data:
382*b8aa3defSJoshua M. Clulow 	 */
383*b8aa3defSJoshua M. Clulow 	sts->sts_sensedata.es_valid = 1;
384*b8aa3defSJoshua M. Clulow 	sts->sts_sensedata.es_class = CLASS_EXTENDED_SENSE;
385*b8aa3defSJoshua M. Clulow 	sts->sts_sensedata.es_key = key;
386*b8aa3defSJoshua M. Clulow 
387*b8aa3defSJoshua M. Clulow 	pkt->pkt_state |= STATE_ARQ_DONE;
388*b8aa3defSJoshua M. Clulow }
389*b8aa3defSJoshua M. Clulow 
390*b8aa3defSJoshua M. Clulow /*
391*b8aa3defSJoshua M. Clulow  * When faking up a REPORT LUNS data structure, we simply report one LUN, LUN 0.
392*b8aa3defSJoshua M. Clulow  * We need 16 bytes for this, 4 for the size, 4 reserved bytes, and the 8 for
393*b8aa3defSJoshua M. Clulow  * the actual LUN.
394*b8aa3defSJoshua M. Clulow  */
395*b8aa3defSJoshua M. Clulow static void
smrt_fake_report_lun(smrt_command_t * smcm,struct scsi_pkt * pkt)396*b8aa3defSJoshua M. Clulow smrt_fake_report_lun(smrt_command_t *smcm, struct scsi_pkt *pkt)
397*b8aa3defSJoshua M. Clulow {
398*b8aa3defSJoshua M. Clulow 	size_t sz;
399*b8aa3defSJoshua M. Clulow 	char resp[16];
400*b8aa3defSJoshua M. Clulow 	struct buf *bp;
401*b8aa3defSJoshua M. Clulow 
402*b8aa3defSJoshua M. Clulow 	pkt->pkt_reason = CMD_CMPLT;
403*b8aa3defSJoshua M. Clulow 	pkt->pkt_state |= STATE_GOT_BUS | STATE_GOT_TARGET | STATE_SENT_CMD |
404*b8aa3defSJoshua M. Clulow 	    STATE_GOT_STATUS;
405*b8aa3defSJoshua M. Clulow 
406*b8aa3defSJoshua M. Clulow 	/*
407*b8aa3defSJoshua M. Clulow 	 * Check to make sure this is valid.  If reserved bits are set or if the
408*b8aa3defSJoshua M. Clulow 	 * mode is one other than 0x00, 0x01, 0x02, then it's an illegal
409*b8aa3defSJoshua M. Clulow 	 * request.
410*b8aa3defSJoshua M. Clulow 	 */
411*b8aa3defSJoshua M. Clulow 	if (pkt->pkt_cdbp[1] != 0 || pkt->pkt_cdbp[3] != 0 ||
412*b8aa3defSJoshua M. Clulow 	    pkt->pkt_cdbp[4] != 0 || pkt->pkt_cdbp[5] != 0 ||
413*b8aa3defSJoshua M. Clulow 	    pkt->pkt_cdbp[10] != 0 || pkt->pkt_cdbp[11] != 0 ||
414*b8aa3defSJoshua M. Clulow 	    pkt->pkt_cdbp[2] > 0x2) {
415*b8aa3defSJoshua M. Clulow 		smrt_set_arq_data(pkt, KEY_ILLEGAL_REQUEST);
416*b8aa3defSJoshua M. Clulow 		return;
417*b8aa3defSJoshua M. Clulow 	}
418*b8aa3defSJoshua M. Clulow 
419*b8aa3defSJoshua M. Clulow 	/*
420*b8aa3defSJoshua M. Clulow 	 * Construct the actual REPORT LUNS reply.  We need to indicate a single
421*b8aa3defSJoshua M. Clulow 	 * LUN of all zeros.  This means that the length needs to be 8 bytes,
422*b8aa3defSJoshua M. Clulow 	 * the size of the lun.  Otherwise, the rest of this structure can be
423*b8aa3defSJoshua M. Clulow 	 * zeros.
424*b8aa3defSJoshua M. Clulow 	 */
425*b8aa3defSJoshua M. Clulow 	bzero(resp, sizeof (resp));
426*b8aa3defSJoshua M. Clulow 	resp[3] = sizeof (scsi_lun_t);
427*b8aa3defSJoshua M. Clulow 
428*b8aa3defSJoshua M. Clulow 	bp = scsi_pkt2bp(pkt);
429*b8aa3defSJoshua M. Clulow 	sz = MIN(sizeof (resp), bp->b_bcount);
430*b8aa3defSJoshua M. Clulow 
431*b8aa3defSJoshua M. Clulow 	bp_mapin(bp);
432*b8aa3defSJoshua M. Clulow 	bcopy(resp, bp->b_un.b_addr, sz);
433*b8aa3defSJoshua M. Clulow 	bp_mapout(bp);
434*b8aa3defSJoshua M. Clulow 	pkt->pkt_state |= STATE_XFERRED_DATA;
435*b8aa3defSJoshua M. Clulow 	pkt->pkt_resid = bp->b_bcount - sz;
436*b8aa3defSJoshua M. Clulow 	if (pkt->pkt_scblen >= 1) {
437*b8aa3defSJoshua M. Clulow 		pkt->pkt_scbp[0] = STATUS_GOOD;
438*b8aa3defSJoshua M. Clulow 	}
439*b8aa3defSJoshua M. Clulow }
440*b8aa3defSJoshua M. Clulow 
441*b8aa3defSJoshua M. Clulow static int
smrt_tran_start(struct scsi_address * sa,struct scsi_pkt * pkt)442*b8aa3defSJoshua M. Clulow smrt_tran_start(struct scsi_address *sa, struct scsi_pkt *pkt)
443*b8aa3defSJoshua M. Clulow {
444*b8aa3defSJoshua M. Clulow 	_NOTE(ARGUNUSED(sa))
445*b8aa3defSJoshua M. Clulow 
446*b8aa3defSJoshua M. Clulow 	struct scsi_device *sd;
447*b8aa3defSJoshua M. Clulow 	smrt_target_t *smtg;
448*b8aa3defSJoshua M. Clulow 	smrt_t *smrt;
449*b8aa3defSJoshua M. Clulow 	smrt_command_scsa_t *smcms;
450*b8aa3defSJoshua M. Clulow 	smrt_command_t *smcm;
451*b8aa3defSJoshua M. Clulow 	int r;
452*b8aa3defSJoshua M. Clulow 
453*b8aa3defSJoshua M. Clulow 	sd = scsi_address_device(&pkt->pkt_address);
454*b8aa3defSJoshua M. Clulow 	VERIFY(sd != NULL);
455*b8aa3defSJoshua M. Clulow 	smtg = scsi_device_hba_private_get(sd);
456*b8aa3defSJoshua M. Clulow 	VERIFY(smtg != NULL);
457*b8aa3defSJoshua M. Clulow 	smrt = smtg->smtg_ctlr;
458*b8aa3defSJoshua M. Clulow 	VERIFY(smrt != NULL);
459*b8aa3defSJoshua M. Clulow 	smcms = (smrt_command_scsa_t *)pkt->pkt_ha_private;
460*b8aa3defSJoshua M. Clulow 	VERIFY(smcms != NULL);
461*b8aa3defSJoshua M. Clulow 	smcm = smcms->smcms_command;
462*b8aa3defSJoshua M. Clulow 	VERIFY(smcm != NULL);
463*b8aa3defSJoshua M. Clulow 
464*b8aa3defSJoshua M. Clulow 	if (smcm->smcm_status & SMRT_CMD_STATUS_TRAN_START) {
465*b8aa3defSJoshua M. Clulow 		/*
466*b8aa3defSJoshua M. Clulow 		 * This is a retry of a command that has already been
467*b8aa3defSJoshua M. Clulow 		 * used once.  Assign it a new tag number.
468*b8aa3defSJoshua M. Clulow 		 */
469*b8aa3defSJoshua M. Clulow 		smrt_command_reuse(smcm);
470*b8aa3defSJoshua M. Clulow 	}
471*b8aa3defSJoshua M. Clulow 	smcm->smcm_status |= SMRT_CMD_STATUS_TRAN_START;
472*b8aa3defSJoshua M. Clulow 
473*b8aa3defSJoshua M. Clulow 	/*
474*b8aa3defSJoshua M. Clulow 	 * The sophisticated firmware in this controller cannot possibly bear
475*b8aa3defSJoshua M. Clulow 	 * the following SCSI commands.  It appears to return a response with
476*b8aa3defSJoshua M. Clulow 	 * the status STATUS_ACA_ACTIVE (0x30), which is not something we
477*b8aa3defSJoshua M. Clulow 	 * expect.  Instead, fake up a failure response.
478*b8aa3defSJoshua M. Clulow 	 */
479*b8aa3defSJoshua M. Clulow 	switch (pkt->pkt_cdbp[0]) {
480*b8aa3defSJoshua M. Clulow 	case SCMD_FORMAT:
481*b8aa3defSJoshua M. Clulow 	case SCMD_LOG_SENSE_G1:
482*b8aa3defSJoshua M. Clulow 	case SCMD_MODE_SELECT:
483*b8aa3defSJoshua M. Clulow 	case SCMD_PERSISTENT_RESERVE_IN:
484*b8aa3defSJoshua M. Clulow 		if (smtg->smtg_physical) {
485*b8aa3defSJoshua M. Clulow 			break;
486*b8aa3defSJoshua M. Clulow 		}
487*b8aa3defSJoshua M. Clulow 
488*b8aa3defSJoshua M. Clulow 		smrt->smrt_stats.smrts_ignored_scsi_cmds++;
489*b8aa3defSJoshua M. Clulow 		smcm->smcm_status |= SMRT_CMD_STATUS_TRAN_IGNORED;
490*b8aa3defSJoshua M. Clulow 
491*b8aa3defSJoshua M. Clulow 		/*
492*b8aa3defSJoshua M. Clulow 		 * Mark the command as completed to the point where we
493*b8aa3defSJoshua M. Clulow 		 * received a SCSI status code:
494*b8aa3defSJoshua M. Clulow 		 */
495*b8aa3defSJoshua M. Clulow 		pkt->pkt_reason = CMD_CMPLT;
496*b8aa3defSJoshua M. Clulow 		pkt->pkt_state |= STATE_GOT_BUS | STATE_GOT_TARGET |
497*b8aa3defSJoshua M. Clulow 		    STATE_SENT_CMD | STATE_GOT_STATUS;
498*b8aa3defSJoshua M. Clulow 
499*b8aa3defSJoshua M. Clulow 		/*
500*b8aa3defSJoshua M. Clulow 		 * Mock up sense data for an illegal request:
501*b8aa3defSJoshua M. Clulow 		 */
502*b8aa3defSJoshua M. Clulow 		smrt_set_arq_data(pkt, KEY_ILLEGAL_REQUEST);
503*b8aa3defSJoshua M. Clulow 
504*b8aa3defSJoshua M. Clulow 		scsi_hba_pkt_comp(pkt);
505*b8aa3defSJoshua M. Clulow 		return (TRAN_ACCEPT);
506*b8aa3defSJoshua M. Clulow 	case SCMD_REPORT_LUNS:
507*b8aa3defSJoshua M. Clulow 		/*
508*b8aa3defSJoshua M. Clulow 		 * The SMRT controller does not accept a REPORT LUNS command for
509*b8aa3defSJoshua M. Clulow 		 * logical volumes.  As such, we need to fake up a REPORT LUNS
510*b8aa3defSJoshua M. Clulow 		 * response that has a single LUN, LUN 0.
511*b8aa3defSJoshua M. Clulow 		 */
512*b8aa3defSJoshua M. Clulow 		if (smtg->smtg_physical) {
513*b8aa3defSJoshua M. Clulow 			break;
514*b8aa3defSJoshua M. Clulow 		}
515*b8aa3defSJoshua M. Clulow 
516*b8aa3defSJoshua M. Clulow 		smrt_fake_report_lun(smcm, pkt);
517*b8aa3defSJoshua M. Clulow 
518*b8aa3defSJoshua M. Clulow 		scsi_hba_pkt_comp(pkt);
519*b8aa3defSJoshua M. Clulow 		return (TRAN_ACCEPT);
520*b8aa3defSJoshua M. Clulow 	default:
521*b8aa3defSJoshua M. Clulow 		break;
522*b8aa3defSJoshua M. Clulow 	}
523*b8aa3defSJoshua M. Clulow 
524*b8aa3defSJoshua M. Clulow 	if (pkt->pkt_flags & FLAG_NOINTR) {
525*b8aa3defSJoshua M. Clulow 		/*
526*b8aa3defSJoshua M. Clulow 		 * We must sleep and wait for the completion of this command.
527*b8aa3defSJoshua M. Clulow 		 */
528*b8aa3defSJoshua M. Clulow 		smcm->smcm_status |= SMRT_CMD_STATUS_POLLED;
529*b8aa3defSJoshua M. Clulow 	}
530*b8aa3defSJoshua M. Clulow 
531*b8aa3defSJoshua M. Clulow 	/*
532*b8aa3defSJoshua M. Clulow 	 * Because we provide a tran_setup_pkt(9E) entrypoint, we must now
533*b8aa3defSJoshua M. Clulow 	 * set up the Scatter/Gather List in the Command to reflect any
534*b8aa3defSJoshua M. Clulow 	 * DMA resources passed to us by the framework.
535*b8aa3defSJoshua M. Clulow 	 */
536*b8aa3defSJoshua M. Clulow 	if (pkt->pkt_numcookies > smrt->smrt_sg_cnt) {
537*b8aa3defSJoshua M. Clulow 		/*
538*b8aa3defSJoshua M. Clulow 		 * More DMA cookies than we are prepared to handle.
539*b8aa3defSJoshua M. Clulow 		 */
540*b8aa3defSJoshua M. Clulow 		dev_err(smrt->smrt_dip, CE_WARN, "too many DMA cookies (got %u;"
541*b8aa3defSJoshua M. Clulow 		    " expected %u)", pkt->pkt_numcookies, smrt->smrt_sg_cnt);
542*b8aa3defSJoshua M. Clulow 		return (TRAN_BADPKT);
543*b8aa3defSJoshua M. Clulow 	}
544*b8aa3defSJoshua M. Clulow 	smcm->smcm_va_cmd->Header.SGList = pkt->pkt_numcookies;
545*b8aa3defSJoshua M. Clulow 	smcm->smcm_va_cmd->Header.SGTotal = pkt->pkt_numcookies;
546*b8aa3defSJoshua M. Clulow 	for (unsigned i = 0; i < pkt->pkt_numcookies; i++) {
547*b8aa3defSJoshua M. Clulow 		smcm->smcm_va_cmd->SG[i].Addr =
548*b8aa3defSJoshua M. Clulow 		    LE_64(pkt->pkt_cookies[i].dmac_laddress);
549*b8aa3defSJoshua M. Clulow 		smcm->smcm_va_cmd->SG[i].Len =
550*b8aa3defSJoshua M. Clulow 		    LE_32(pkt->pkt_cookies[i].dmac_size);
551*b8aa3defSJoshua M. Clulow 	}
552*b8aa3defSJoshua M. Clulow 
553*b8aa3defSJoshua M. Clulow 	/*
554*b8aa3defSJoshua M. Clulow 	 * Copy logical volume address from the target object:
555*b8aa3defSJoshua M. Clulow 	 */
556*b8aa3defSJoshua M. Clulow 	smcm->smcm_va_cmd->Header.LUN = *smcm->smcm_target->smtg_addr;
557*b8aa3defSJoshua M. Clulow 
558*b8aa3defSJoshua M. Clulow 	/*
559*b8aa3defSJoshua M. Clulow 	 * Initialise the command block.
560*b8aa3defSJoshua M. Clulow 	 */
561*b8aa3defSJoshua M. Clulow 	smcm->smcm_va_cmd->Request.CDBLen = pkt->pkt_cdblen;
562*b8aa3defSJoshua M. Clulow 	smcm->smcm_va_cmd->Request.Type.Type = CISS_TYPE_CMD;
563*b8aa3defSJoshua M. Clulow 	smcm->smcm_va_cmd->Request.Type.Attribute = CISS_ATTR_SIMPLE;
564*b8aa3defSJoshua M. Clulow 	smcm->smcm_va_cmd->Request.Timeout = LE_16(pkt->pkt_time);
565*b8aa3defSJoshua M. Clulow 	if (pkt->pkt_numcookies > 0) {
566*b8aa3defSJoshua M. Clulow 		/*
567*b8aa3defSJoshua M. Clulow 		 * There are DMA resources; set the transfer direction
568*b8aa3defSJoshua M. Clulow 		 * appropriately:
569*b8aa3defSJoshua M. Clulow 		 */
570*b8aa3defSJoshua M. Clulow 		if (pkt->pkt_dma_flags & DDI_DMA_READ) {
571*b8aa3defSJoshua M. Clulow 			smcm->smcm_va_cmd->Request.Type.Direction =
572*b8aa3defSJoshua M. Clulow 			    CISS_XFER_READ;
573*b8aa3defSJoshua M. Clulow 		} else if (pkt->pkt_dma_flags & DDI_DMA_WRITE) {
574*b8aa3defSJoshua M. Clulow 			smcm->smcm_va_cmd->Request.Type.Direction =
575*b8aa3defSJoshua M. Clulow 			    CISS_XFER_WRITE;
576*b8aa3defSJoshua M. Clulow 		} else {
577*b8aa3defSJoshua M. Clulow 			smcm->smcm_va_cmd->Request.Type.Direction =
578*b8aa3defSJoshua M. Clulow 			    CISS_XFER_NONE;
579*b8aa3defSJoshua M. Clulow 		}
580*b8aa3defSJoshua M. Clulow 	} else {
581*b8aa3defSJoshua M. Clulow 		/*
582*b8aa3defSJoshua M. Clulow 		 * No DMA resources means no transfer.
583*b8aa3defSJoshua M. Clulow 		 */
584*b8aa3defSJoshua M. Clulow 		smcm->smcm_va_cmd->Request.Type.Direction = CISS_XFER_NONE;
585*b8aa3defSJoshua M. Clulow 	}
586*b8aa3defSJoshua M. Clulow 
587*b8aa3defSJoshua M. Clulow 	/*
588*b8aa3defSJoshua M. Clulow 	 * Initialise the SCSI packet as described in tran_start(9E).  We will
589*b8aa3defSJoshua M. Clulow 	 * progressively update these fields as the command moves through the
590*b8aa3defSJoshua M. Clulow 	 * submission and completion states.
591*b8aa3defSJoshua M. Clulow 	 */
592*b8aa3defSJoshua M. Clulow 	pkt->pkt_resid = 0;
593*b8aa3defSJoshua M. Clulow 	pkt->pkt_reason = CMD_CMPLT;
594*b8aa3defSJoshua M. Clulow 	pkt->pkt_statistics = 0;
595*b8aa3defSJoshua M. Clulow 	pkt->pkt_state = 0;
596*b8aa3defSJoshua M. Clulow 
597*b8aa3defSJoshua M. Clulow 	/*
598*b8aa3defSJoshua M. Clulow 	 * If this SCSI packet has a timeout, configure an appropriate
599*b8aa3defSJoshua M. Clulow 	 * expiry time:
600*b8aa3defSJoshua M. Clulow 	 */
601*b8aa3defSJoshua M. Clulow 	if (pkt->pkt_time != 0) {
602*b8aa3defSJoshua M. Clulow 		smcm->smcm_expiry = gethrtime() + pkt->pkt_time * NANOSEC;
603*b8aa3defSJoshua M. Clulow 	}
604*b8aa3defSJoshua M. Clulow 
605*b8aa3defSJoshua M. Clulow 	/*
606*b8aa3defSJoshua M. Clulow 	 * Submit the command to the controller.
607*b8aa3defSJoshua M. Clulow 	 */
608*b8aa3defSJoshua M. Clulow 	mutex_enter(&smrt->smrt_mutex);
609*b8aa3defSJoshua M. Clulow 
610*b8aa3defSJoshua M. Clulow 	/*
611*b8aa3defSJoshua M. Clulow 	 * If we're dumping, there's a chance that the target we're talking to
612*b8aa3defSJoshua M. Clulow 	 * could have ended up disappearing during the process of discovery.  If
613*b8aa3defSJoshua M. Clulow 	 * this target is part of the dump device, we check here and return that
614*b8aa3defSJoshua M. Clulow 	 * we hit a fatal error.
615*b8aa3defSJoshua M. Clulow 	 */
616*b8aa3defSJoshua M. Clulow 	if (ddi_in_panic() && smtg->smtg_gone) {
617*b8aa3defSJoshua M. Clulow 		mutex_exit(&smrt->smrt_mutex);
618*b8aa3defSJoshua M. Clulow 
619*b8aa3defSJoshua M. Clulow 		dev_err(smrt->smrt_dip, CE_WARN, "smrt_submit failed: target "
620*b8aa3defSJoshua M. Clulow 		    "%s is gone, it did not come back after post-panic reset "
621*b8aa3defSJoshua M. Clulow 		    "device discovery", scsi_device_unit_address(sd));
622*b8aa3defSJoshua M. Clulow 
623*b8aa3defSJoshua M. Clulow 		return (TRAN_FATAL_ERROR);
624*b8aa3defSJoshua M. Clulow 	}
625*b8aa3defSJoshua M. Clulow 
626*b8aa3defSJoshua M. Clulow 	smrt->smrt_stats.smrts_tran_starts++;
627*b8aa3defSJoshua M. Clulow 	if ((r = smrt_submit(smrt, smcm)) != 0) {
628*b8aa3defSJoshua M. Clulow 		mutex_exit(&smrt->smrt_mutex);
629*b8aa3defSJoshua M. Clulow 
630*b8aa3defSJoshua M. Clulow 		dev_err(smrt->smrt_dip, CE_WARN, "smrt_submit failed %d", r);
631*b8aa3defSJoshua M. Clulow 
632*b8aa3defSJoshua M. Clulow 		/*
633*b8aa3defSJoshua M. Clulow 		 * Inform the SCSI framework that we could not submit
634*b8aa3defSJoshua M. Clulow 		 * the command.
635*b8aa3defSJoshua M. Clulow 		 */
636*b8aa3defSJoshua M. Clulow 		return (r == EAGAIN ? TRAN_BUSY : TRAN_FATAL_ERROR);
637*b8aa3defSJoshua M. Clulow 	}
638*b8aa3defSJoshua M. Clulow 
639*b8aa3defSJoshua M. Clulow 	/*
640*b8aa3defSJoshua M. Clulow 	 * Update the SCSI packet to reflect submission of the command.
641*b8aa3defSJoshua M. Clulow 	 */
642*b8aa3defSJoshua M. Clulow 	pkt->pkt_state |= STATE_GOT_BUS | STATE_GOT_TARGET | STATE_SENT_CMD;
643*b8aa3defSJoshua M. Clulow 
644*b8aa3defSJoshua M. Clulow 	if (pkt->pkt_flags & FLAG_NOINTR) {
645*b8aa3defSJoshua M. Clulow 		/*
646*b8aa3defSJoshua M. Clulow 		 * Poll the controller for completion of the command we
647*b8aa3defSJoshua M. Clulow 		 * submitted.  Once this routine has returned, the completion
648*b8aa3defSJoshua M. Clulow 		 * callback will have been fired with either an active response
649*b8aa3defSJoshua M. Clulow 		 * (success or error) or a timeout.  The command is freed by
650*b8aa3defSJoshua M. Clulow 		 * the completion callback, so it may not be referenced again
651*b8aa3defSJoshua M. Clulow 		 * after this call returns.
652*b8aa3defSJoshua M. Clulow 		 */
653*b8aa3defSJoshua M. Clulow 		(void) smrt_poll_for(smrt, smcm);
654*b8aa3defSJoshua M. Clulow 	}
655*b8aa3defSJoshua M. Clulow 
656*b8aa3defSJoshua M. Clulow 	mutex_exit(&smrt->smrt_mutex);
657*b8aa3defSJoshua M. Clulow 	return (TRAN_ACCEPT);
658*b8aa3defSJoshua M. Clulow }
659*b8aa3defSJoshua M. Clulow 
660*b8aa3defSJoshua M. Clulow static int
smrt_tran_reset(struct scsi_address * sa,int level)661*b8aa3defSJoshua M. Clulow smrt_tran_reset(struct scsi_address *sa, int level)
662*b8aa3defSJoshua M. Clulow {
663*b8aa3defSJoshua M. Clulow 	_NOTE(ARGUNUSED(level))
664*b8aa3defSJoshua M. Clulow 
665*b8aa3defSJoshua M. Clulow 	struct scsi_device *sd;
666*b8aa3defSJoshua M. Clulow 	smrt_target_t *smtg;
667*b8aa3defSJoshua M. Clulow 	smrt_t *smrt;
668*b8aa3defSJoshua M. Clulow 	smrt_command_t *smcm;
669*b8aa3defSJoshua M. Clulow 	int r;
670*b8aa3defSJoshua M. Clulow 
671*b8aa3defSJoshua M. Clulow 	sd = scsi_address_device(sa);
672*b8aa3defSJoshua M. Clulow 	VERIFY(sd != NULL);
673*b8aa3defSJoshua M. Clulow 	smtg = scsi_device_hba_private_get(sd);
674*b8aa3defSJoshua M. Clulow 	VERIFY(smtg != NULL);
675*b8aa3defSJoshua M. Clulow 	smrt = smtg->smtg_ctlr;
676*b8aa3defSJoshua M. Clulow 
677*b8aa3defSJoshua M. Clulow 	/*
678*b8aa3defSJoshua M. Clulow 	 * The framework has requested some kind of SCSI reset.  A
679*b8aa3defSJoshua M. Clulow 	 * controller-level soft reset can take a very long time -- often on
680*b8aa3defSJoshua M. Clulow 	 * the order of 30-60 seconds -- but might well be our only option if
681*b8aa3defSJoshua M. Clulow 	 * the controller is non-responsive.
682*b8aa3defSJoshua M. Clulow 	 *
683*b8aa3defSJoshua M. Clulow 	 * First, check if the controller is responding to pings.
684*b8aa3defSJoshua M. Clulow 	 */
685*b8aa3defSJoshua M. Clulow again:
686*b8aa3defSJoshua M. Clulow 	if ((smcm = smrt_command_alloc(smrt, SMRT_CMDTYPE_INTERNAL,
687*b8aa3defSJoshua M. Clulow 	    KM_NOSLEEP)) == NULL) {
688*b8aa3defSJoshua M. Clulow 		return (0);
689*b8aa3defSJoshua M. Clulow 	}
690*b8aa3defSJoshua M. Clulow 
691*b8aa3defSJoshua M. Clulow 	smrt_write_message_nop(smcm, SMRT_PING_CHECK_TIMEOUT);
692*b8aa3defSJoshua M. Clulow 
693*b8aa3defSJoshua M. Clulow 	mutex_enter(&smrt->smrt_mutex);
694*b8aa3defSJoshua M. Clulow 	smrt->smrt_stats.smrts_tran_resets++;
695*b8aa3defSJoshua M. Clulow 	if (ddi_in_panic()) {
696*b8aa3defSJoshua M. Clulow 		goto skip_check;
697*b8aa3defSJoshua M. Clulow 	}
698*b8aa3defSJoshua M. Clulow 
699*b8aa3defSJoshua M. Clulow 	if (smrt->smrt_status & SMRT_CTLR_STATUS_RESETTING) {
700*b8aa3defSJoshua M. Clulow 		/*
701*b8aa3defSJoshua M. Clulow 		 * The controller is already resetting.  Wait for that
702*b8aa3defSJoshua M. Clulow 		 * to finish.
703*b8aa3defSJoshua M. Clulow 		 */
704*b8aa3defSJoshua M. Clulow 		while (smrt->smrt_status & SMRT_CTLR_STATUS_RESETTING) {
705*b8aa3defSJoshua M. Clulow 			cv_wait(&smrt->smrt_cv_finishq, &smrt->smrt_mutex);
706*b8aa3defSJoshua M. Clulow 		}
707*b8aa3defSJoshua M. Clulow 	}
708*b8aa3defSJoshua M. Clulow 
709*b8aa3defSJoshua M. Clulow skip_check:
710*b8aa3defSJoshua M. Clulow 	/*
711*b8aa3defSJoshua M. Clulow 	 * Submit our ping to the controller.
712*b8aa3defSJoshua M. Clulow 	 */
713*b8aa3defSJoshua M. Clulow 	smcm->smcm_status |= SMRT_CMD_STATUS_POLLED;
714*b8aa3defSJoshua M. Clulow 	smcm->smcm_expiry = gethrtime() + SMRT_PING_CHECK_TIMEOUT * NANOSEC;
715*b8aa3defSJoshua M. Clulow 	if (smrt_submit(smrt, smcm) != 0) {
716*b8aa3defSJoshua M. Clulow 		mutex_exit(&smrt->smrt_mutex);
717*b8aa3defSJoshua M. Clulow 		smrt_command_free(smcm);
718*b8aa3defSJoshua M. Clulow 		return (0);
719*b8aa3defSJoshua M. Clulow 	}
720*b8aa3defSJoshua M. Clulow 
721*b8aa3defSJoshua M. Clulow 	if ((r = smrt_poll_for(smrt, smcm)) != 0) {
722*b8aa3defSJoshua M. Clulow 		VERIFY3S(r, ==, ETIMEDOUT);
723*b8aa3defSJoshua M. Clulow 		VERIFY0(smcm->smcm_status & SMRT_CMD_STATUS_POLL_COMPLETE);
724*b8aa3defSJoshua M. Clulow 
725*b8aa3defSJoshua M. Clulow 		/*
726*b8aa3defSJoshua M. Clulow 		 * The ping command timed out.  Abandon it now.
727*b8aa3defSJoshua M. Clulow 		 */
728*b8aa3defSJoshua M. Clulow 		dev_err(smrt->smrt_dip, CE_WARN, "controller ping timed out");
729*b8aa3defSJoshua M. Clulow 		smcm->smcm_status |= SMRT_CMD_STATUS_ABANDONED;
730*b8aa3defSJoshua M. Clulow 		smcm->smcm_status &= ~SMRT_CMD_STATUS_POLLED;
731*b8aa3defSJoshua M. Clulow 
732*b8aa3defSJoshua M. Clulow 	} else if ((smcm->smcm_status & SMRT_CMD_STATUS_RESET_SENT) ||
733*b8aa3defSJoshua M. Clulow 	    (smcm->smcm_status & SMRT_CMD_STATUS_ERROR)) {
734*b8aa3defSJoshua M. Clulow 		/*
735*b8aa3defSJoshua M. Clulow 		 * The command completed in error, or a controller reset
736*b8aa3defSJoshua M. Clulow 		 * was sent while we were trying to ping.
737*b8aa3defSJoshua M. Clulow 		 */
738*b8aa3defSJoshua M. Clulow 		dev_err(smrt->smrt_dip, CE_WARN, "controller ping error");
739*b8aa3defSJoshua M. Clulow 		mutex_exit(&smrt->smrt_mutex);
740*b8aa3defSJoshua M. Clulow 		smrt_command_free(smcm);
741*b8aa3defSJoshua M. Clulow 		mutex_enter(&smrt->smrt_mutex);
742*b8aa3defSJoshua M. Clulow 
743*b8aa3defSJoshua M. Clulow 	} else {
744*b8aa3defSJoshua M. Clulow 		VERIFY(smcm->smcm_status & SMRT_CMD_STATUS_COMPLETE);
745*b8aa3defSJoshua M. Clulow 
746*b8aa3defSJoshua M. Clulow 		/*
747*b8aa3defSJoshua M. Clulow 		 * The controller is responsive, and a full soft reset would be
748*b8aa3defSJoshua M. Clulow 		 * extremely disruptive to the system.  Given our spotty
749*b8aa3defSJoshua M. Clulow 		 * support for some SCSI commands (which can upset the target
750*b8aa3defSJoshua M. Clulow 		 * drivers) and the historically lax behaviour of the "smrt"
751*b8aa3defSJoshua M. Clulow 		 * driver, we grit our teeth and pretend we were able to
752*b8aa3defSJoshua M. Clulow 		 * perform a reset.
753*b8aa3defSJoshua M. Clulow 		 */
754*b8aa3defSJoshua M. Clulow 		mutex_exit(&smrt->smrt_mutex);
755*b8aa3defSJoshua M. Clulow 		smrt_command_free(smcm);
756*b8aa3defSJoshua M. Clulow 		return (1);
757*b8aa3defSJoshua M. Clulow 	}
758*b8aa3defSJoshua M. Clulow 
759*b8aa3defSJoshua M. Clulow 	/*
760*b8aa3defSJoshua M. Clulow 	 * If a reset has been initiated in the last 90 seconds, try
761*b8aa3defSJoshua M. Clulow 	 * another ping.
762*b8aa3defSJoshua M. Clulow 	 */
763*b8aa3defSJoshua M. Clulow 	if (gethrtime() < smrt->smrt_last_reset_start + 90 * NANOSEC) {
764*b8aa3defSJoshua M. Clulow 		dev_err(smrt->smrt_dip, CE_WARN, "controller ping failed, but "
765*b8aa3defSJoshua M. Clulow 		    "was recently reset; retrying ping");
766*b8aa3defSJoshua M. Clulow 		mutex_exit(&smrt->smrt_mutex);
767*b8aa3defSJoshua M. Clulow 
768*b8aa3defSJoshua M. Clulow 		/*
769*b8aa3defSJoshua M. Clulow 		 * Sleep for a second first.
770*b8aa3defSJoshua M. Clulow 		 */
771*b8aa3defSJoshua M. Clulow 		if (ddi_in_panic()) {
772*b8aa3defSJoshua M. Clulow 			drv_usecwait(1 * MICROSEC);
773*b8aa3defSJoshua M. Clulow 		} else {
774*b8aa3defSJoshua M. Clulow 			delay(drv_usectohz(1 * MICROSEC));
775*b8aa3defSJoshua M. Clulow 		}
776*b8aa3defSJoshua M. Clulow 		goto again;
777*b8aa3defSJoshua M. Clulow 	}
778*b8aa3defSJoshua M. Clulow 
779*b8aa3defSJoshua M. Clulow 	dev_err(smrt->smrt_dip, CE_WARN, "controller ping failed; resetting "
780*b8aa3defSJoshua M. Clulow 	    "controller");
781*b8aa3defSJoshua M. Clulow 	if (smrt_ctlr_reset(smrt) != 0) {
782*b8aa3defSJoshua M. Clulow 		dev_err(smrt->smrt_dip, CE_WARN, "controller reset failure");
783*b8aa3defSJoshua M. Clulow 		mutex_exit(&smrt->smrt_mutex);
784*b8aa3defSJoshua M. Clulow 		return (0);
785*b8aa3defSJoshua M. Clulow 	}
786*b8aa3defSJoshua M. Clulow 
787*b8aa3defSJoshua M. Clulow 	mutex_exit(&smrt->smrt_mutex);
788*b8aa3defSJoshua M. Clulow 	return (1);
789*b8aa3defSJoshua M. Clulow }
790*b8aa3defSJoshua M. Clulow 
791*b8aa3defSJoshua M. Clulow static int
smrt_tran_abort(struct scsi_address * sa,struct scsi_pkt * pkt)792*b8aa3defSJoshua M. Clulow smrt_tran_abort(struct scsi_address *sa, struct scsi_pkt *pkt)
793*b8aa3defSJoshua M. Clulow {
794*b8aa3defSJoshua M. Clulow 	struct scsi_device *sd;
795*b8aa3defSJoshua M. Clulow 	smrt_target_t *smtg;
796*b8aa3defSJoshua M. Clulow 	smrt_t *smrt;
797*b8aa3defSJoshua M. Clulow 	smrt_command_t *smcm = NULL;
798*b8aa3defSJoshua M. Clulow 	smrt_command_t *abort_smcm;
799*b8aa3defSJoshua M. Clulow 
800*b8aa3defSJoshua M. Clulow 	sd = scsi_address_device(sa);
801*b8aa3defSJoshua M. Clulow 	VERIFY(sd != NULL);
802*b8aa3defSJoshua M. Clulow 	smtg = scsi_device_hba_private_get(sd);
803*b8aa3defSJoshua M. Clulow 	VERIFY(smtg != NULL);
804*b8aa3defSJoshua M. Clulow 	smrt = smtg->smtg_ctlr;
805*b8aa3defSJoshua M. Clulow 	VERIFY(smrt != NULL);
806*b8aa3defSJoshua M. Clulow 
807*b8aa3defSJoshua M. Clulow 
808*b8aa3defSJoshua M. Clulow 	if ((abort_smcm = smrt_command_alloc(smrt, SMRT_CMDTYPE_INTERNAL,
809*b8aa3defSJoshua M. Clulow 	    KM_NOSLEEP)) == NULL) {
810*b8aa3defSJoshua M. Clulow 		/*
811*b8aa3defSJoshua M. Clulow 		 * No resources available to send an abort message.
812*b8aa3defSJoshua M. Clulow 		 */
813*b8aa3defSJoshua M. Clulow 		return (0);
814*b8aa3defSJoshua M. Clulow 	}
815*b8aa3defSJoshua M. Clulow 
816*b8aa3defSJoshua M. Clulow 	mutex_enter(&smrt->smrt_mutex);
817*b8aa3defSJoshua M. Clulow 	smrt->smrt_stats.smrts_tran_aborts++;
818*b8aa3defSJoshua M. Clulow 	if (pkt != NULL) {
819*b8aa3defSJoshua M. Clulow 		/*
820*b8aa3defSJoshua M. Clulow 		 * The framework wants us to abort a specific SCSI packet.
821*b8aa3defSJoshua M. Clulow 		 */
822*b8aa3defSJoshua M. Clulow 		smrt_command_scsa_t *smcms = (smrt_command_scsa_t *)
823*b8aa3defSJoshua M. Clulow 		    pkt->pkt_ha_private;
824*b8aa3defSJoshua M. Clulow 		smcm = smcms->smcms_command;
825*b8aa3defSJoshua M. Clulow 
826*b8aa3defSJoshua M. Clulow 		if (!(smcm->smcm_status & SMRT_CMD_STATUS_INFLIGHT)) {
827*b8aa3defSJoshua M. Clulow 			/*
828*b8aa3defSJoshua M. Clulow 			 * This message is not currently in flight, so we
829*b8aa3defSJoshua M. Clulow 			 * cannot abort it.
830*b8aa3defSJoshua M. Clulow 			 */
831*b8aa3defSJoshua M. Clulow 			goto fail;
832*b8aa3defSJoshua M. Clulow 		}
833*b8aa3defSJoshua M. Clulow 
834*b8aa3defSJoshua M. Clulow 		if (smcm->smcm_status & SMRT_CMD_STATUS_ABORT_SENT) {
835*b8aa3defSJoshua M. Clulow 			/*
836*b8aa3defSJoshua M. Clulow 			 * An abort message for this command has already been
837*b8aa3defSJoshua M. Clulow 			 * sent to the controller.  Return failure.
838*b8aa3defSJoshua M. Clulow 			 */
839*b8aa3defSJoshua M. Clulow 			goto fail;
840*b8aa3defSJoshua M. Clulow 		}
841*b8aa3defSJoshua M. Clulow 
842*b8aa3defSJoshua M. Clulow 		smrt_write_message_abort_one(abort_smcm, smcm->smcm_tag);
843*b8aa3defSJoshua M. Clulow 	} else {
844*b8aa3defSJoshua M. Clulow 		/*
845*b8aa3defSJoshua M. Clulow 		 * The framework wants us to abort every in flight command
846*b8aa3defSJoshua M. Clulow 		 * for the target with this address.
847*b8aa3defSJoshua M. Clulow 		 */
848*b8aa3defSJoshua M. Clulow 		smrt_write_message_abort_all(abort_smcm, smtg->smtg_addr);
849*b8aa3defSJoshua M. Clulow 	}
850*b8aa3defSJoshua M. Clulow 
851*b8aa3defSJoshua M. Clulow 	/*
852*b8aa3defSJoshua M. Clulow 	 * Submit the abort message to the controller.
853*b8aa3defSJoshua M. Clulow 	 */
854*b8aa3defSJoshua M. Clulow 	abort_smcm->smcm_status |= SMRT_CMD_STATUS_POLLED;
855*b8aa3defSJoshua M. Clulow 	if (smrt_submit(smrt, abort_smcm) != 0) {
856*b8aa3defSJoshua M. Clulow 		goto fail;
857*b8aa3defSJoshua M. Clulow 	}
858*b8aa3defSJoshua M. Clulow 
859*b8aa3defSJoshua M. Clulow 	if (pkt != NULL) {
860*b8aa3defSJoshua M. Clulow 		/*
861*b8aa3defSJoshua M. Clulow 		 * Record some debugging information about the abort we
862*b8aa3defSJoshua M. Clulow 		 * sent:
863*b8aa3defSJoshua M. Clulow 		 */
864*b8aa3defSJoshua M. Clulow 		smcm->smcm_abort_time = gethrtime();
865*b8aa3defSJoshua M. Clulow 		smcm->smcm_abort_tag = abort_smcm->smcm_tag;
866*b8aa3defSJoshua M. Clulow 
867*b8aa3defSJoshua M. Clulow 		/*
868*b8aa3defSJoshua M. Clulow 		 * Mark the command as aborted so that we do not send
869*b8aa3defSJoshua M. Clulow 		 * a second abort message:
870*b8aa3defSJoshua M. Clulow 		 */
871*b8aa3defSJoshua M. Clulow 		smcm->smcm_status |= SMRT_CMD_STATUS_ABORT_SENT;
872*b8aa3defSJoshua M. Clulow 	}
873*b8aa3defSJoshua M. Clulow 
874*b8aa3defSJoshua M. Clulow 	/*
875*b8aa3defSJoshua M. Clulow 	 * Poll for completion of the abort message.  Note that this function
876*b8aa3defSJoshua M. Clulow 	 * only fails if we set a timeout on the command, which we have not
877*b8aa3defSJoshua M. Clulow 	 * done.
878*b8aa3defSJoshua M. Clulow 	 */
879*b8aa3defSJoshua M. Clulow 	VERIFY0(smrt_poll_for(smrt, abort_smcm));
880*b8aa3defSJoshua M. Clulow 
881*b8aa3defSJoshua M. Clulow 	if ((abort_smcm->smcm_status & SMRT_CMD_STATUS_RESET_SENT) ||
882*b8aa3defSJoshua M. Clulow 	    (abort_smcm->smcm_status & SMRT_CMD_STATUS_ERROR)) {
883*b8aa3defSJoshua M. Clulow 		/*
884*b8aa3defSJoshua M. Clulow 		 * Either the controller was reset or the abort command
885*b8aa3defSJoshua M. Clulow 		 * failed.
886*b8aa3defSJoshua M. Clulow 		 */
887*b8aa3defSJoshua M. Clulow 		goto fail;
888*b8aa3defSJoshua M. Clulow 	}
889*b8aa3defSJoshua M. Clulow 
890*b8aa3defSJoshua M. Clulow 	/*
891*b8aa3defSJoshua M. Clulow 	 * The command was successfully aborted.
892*b8aa3defSJoshua M. Clulow 	 */
893*b8aa3defSJoshua M. Clulow 	mutex_exit(&smrt->smrt_mutex);
894*b8aa3defSJoshua M. Clulow 	smrt_command_free(abort_smcm);
895*b8aa3defSJoshua M. Clulow 	return (1);
896*b8aa3defSJoshua M. Clulow 
897*b8aa3defSJoshua M. Clulow fail:
898*b8aa3defSJoshua M. Clulow 	mutex_exit(&smrt->smrt_mutex);
899*b8aa3defSJoshua M. Clulow 	smrt_command_free(abort_smcm);
900*b8aa3defSJoshua M. Clulow 	return (0);
901*b8aa3defSJoshua M. Clulow }
902*b8aa3defSJoshua M. Clulow 
903*b8aa3defSJoshua M. Clulow static void
smrt_hba_complete_status(smrt_command_t * smcm)904*b8aa3defSJoshua M. Clulow smrt_hba_complete_status(smrt_command_t *smcm)
905*b8aa3defSJoshua M. Clulow {
906*b8aa3defSJoshua M. Clulow 	ErrorInfo_t *ei = smcm->smcm_va_err;
907*b8aa3defSJoshua M. Clulow 	struct scsi_pkt *pkt = smcm->smcm_scsa->smcms_pkt;
908*b8aa3defSJoshua M. Clulow 
909*b8aa3defSJoshua M. Clulow 	bzero(pkt->pkt_scbp, pkt->pkt_scblen);
910*b8aa3defSJoshua M. Clulow 
911*b8aa3defSJoshua M. Clulow 	if (ei->ScsiStatus != STATUS_CHECK) {
912*b8aa3defSJoshua M. Clulow 		/*
913*b8aa3defSJoshua M. Clulow 		 * If the SCSI status is not CHECK CONDITION, we don't want
914*b8aa3defSJoshua M. Clulow 		 * to try and read the sense data buffer.
915*b8aa3defSJoshua M. Clulow 		 */
916*b8aa3defSJoshua M. Clulow 		goto simple_status;
917*b8aa3defSJoshua M. Clulow 	}
918*b8aa3defSJoshua M. Clulow 
919*b8aa3defSJoshua M. Clulow 	if (pkt->pkt_scblen < sizeof (struct scsi_arq_status)) {
920*b8aa3defSJoshua M. Clulow 		/*
921*b8aa3defSJoshua M. Clulow 		 * There is not enough room for a request sense structure.
922*b8aa3defSJoshua M. Clulow 		 * Fall back to reporting just the SCSI status code.
923*b8aa3defSJoshua M. Clulow 		 */
924*b8aa3defSJoshua M. Clulow 		goto simple_status;
925*b8aa3defSJoshua M. Clulow 	}
926*b8aa3defSJoshua M. Clulow 
927*b8aa3defSJoshua M. Clulow 	/* LINTED: E_BAD_PTR_CAST_ALIGN */
928*b8aa3defSJoshua M. Clulow 	struct scsi_arq_status *sts = (struct scsi_arq_status *)pkt->pkt_scbp;
929*b8aa3defSJoshua M. Clulow 
930*b8aa3defSJoshua M. Clulow 	/*
931*b8aa3defSJoshua M. Clulow 	 * Copy in the SCSI status from the original command.
932*b8aa3defSJoshua M. Clulow 	 */
933*b8aa3defSJoshua M. Clulow 	bcopy(&ei->ScsiStatus, &sts->sts_status, sizeof (sts->sts_status));
934*b8aa3defSJoshua M. Clulow 
935*b8aa3defSJoshua M. Clulow 	/*
936*b8aa3defSJoshua M. Clulow 	 * Mock up a successful REQUEST SENSE:
937*b8aa3defSJoshua M. Clulow 	 */
938*b8aa3defSJoshua M. Clulow 	sts->sts_rqpkt_reason = CMD_CMPLT;
939*b8aa3defSJoshua M. Clulow 	sts->sts_rqpkt_resid = 0;
940*b8aa3defSJoshua M. Clulow 	sts->sts_rqpkt_state = STATE_GOT_BUS | STATE_GOT_TARGET |
941*b8aa3defSJoshua M. Clulow 	    STATE_SENT_CMD | STATE_XFERRED_DATA | STATE_GOT_STATUS;
942*b8aa3defSJoshua M. Clulow 	sts->sts_rqpkt_statistics = 0;
943*b8aa3defSJoshua M. Clulow 
944*b8aa3defSJoshua M. Clulow 	/*
945*b8aa3defSJoshua M. Clulow 	 * The sense data from the controller should be copied into place
946*b8aa3defSJoshua M. Clulow 	 * starting at the "sts_sensedata" member of the auto request
947*b8aa3defSJoshua M. Clulow 	 * sense object.
948*b8aa3defSJoshua M. Clulow 	 */
949*b8aa3defSJoshua M. Clulow 	size_t sense_len = pkt->pkt_scblen - offsetof(struct scsi_arq_status,
950*b8aa3defSJoshua M. Clulow 	    sts_sensedata);
951*b8aa3defSJoshua M. Clulow 	if (ei->SenseLen < sense_len) {
952*b8aa3defSJoshua M. Clulow 		/*
953*b8aa3defSJoshua M. Clulow 		 * Only copy sense data bytes that are within the region
954*b8aa3defSJoshua M. Clulow 		 * the controller marked as valid.
955*b8aa3defSJoshua M. Clulow 		 */
956*b8aa3defSJoshua M. Clulow 		sense_len = ei->SenseLen;
957*b8aa3defSJoshua M. Clulow 	}
958*b8aa3defSJoshua M. Clulow 	bcopy(ei->SenseInfo, &sts->sts_sensedata, sense_len);
959*b8aa3defSJoshua M. Clulow 
960*b8aa3defSJoshua M. Clulow 	pkt->pkt_state |= STATE_ARQ_DONE;
961*b8aa3defSJoshua M. Clulow 	return;
962*b8aa3defSJoshua M. Clulow 
963*b8aa3defSJoshua M. Clulow simple_status:
964*b8aa3defSJoshua M. Clulow 	if (pkt->pkt_scblen < sizeof (struct scsi_status)) {
965*b8aa3defSJoshua M. Clulow 		/*
966*b8aa3defSJoshua M. Clulow 		 * There is not even enough room for the SCSI status byte.
967*b8aa3defSJoshua M. Clulow 		 */
968*b8aa3defSJoshua M. Clulow 		return;
969*b8aa3defSJoshua M. Clulow 	}
970*b8aa3defSJoshua M. Clulow 
971*b8aa3defSJoshua M. Clulow 	bcopy(&ei->ScsiStatus, pkt->pkt_scbp, sizeof (struct scsi_status));
972*b8aa3defSJoshua M. Clulow }
973*b8aa3defSJoshua M. Clulow 
974*b8aa3defSJoshua M. Clulow static void
smrt_hba_complete_log_error(smrt_command_t * smcm,const char * name)975*b8aa3defSJoshua M. Clulow smrt_hba_complete_log_error(smrt_command_t *smcm, const char *name)
976*b8aa3defSJoshua M. Clulow {
977*b8aa3defSJoshua M. Clulow 	smrt_t *smrt = smcm->smcm_ctlr;
978*b8aa3defSJoshua M. Clulow 	ErrorInfo_t *ei = smcm->smcm_va_err;
979*b8aa3defSJoshua M. Clulow 
980*b8aa3defSJoshua M. Clulow 	dev_err(smrt->smrt_dip, CE_WARN, "!SCSI command failed: %s: "
981*b8aa3defSJoshua M. Clulow 	    "SCSI op %x, CISS status %x, SCSI status %x", name,
982*b8aa3defSJoshua M. Clulow 	    (unsigned)smcm->smcm_va_cmd->Request.CDB[0],
983*b8aa3defSJoshua M. Clulow 	    (unsigned)ei->CommandStatus, (unsigned)ei->ScsiStatus);
984*b8aa3defSJoshua M. Clulow }
985*b8aa3defSJoshua M. Clulow 
986*b8aa3defSJoshua M. Clulow /*
987*b8aa3defSJoshua M. Clulow  * Completion routine for commands submitted to the controller via the SCSI
988*b8aa3defSJoshua M. Clulow  * framework.
989*b8aa3defSJoshua M. Clulow  */
990*b8aa3defSJoshua M. Clulow void
smrt_hba_complete(smrt_command_t * smcm)991*b8aa3defSJoshua M. Clulow smrt_hba_complete(smrt_command_t *smcm)
992*b8aa3defSJoshua M. Clulow {
993*b8aa3defSJoshua M. Clulow 	smrt_t *smrt = smcm->smcm_ctlr;
994*b8aa3defSJoshua M. Clulow 	ErrorInfo_t *ei = smcm->smcm_va_err;
995*b8aa3defSJoshua M. Clulow 	struct scsi_pkt *pkt = smcm->smcm_scsa->smcms_pkt;
996*b8aa3defSJoshua M. Clulow 
997*b8aa3defSJoshua M. Clulow 	VERIFY(MUTEX_HELD(&smrt->smrt_mutex));
998*b8aa3defSJoshua M. Clulow 
999*b8aa3defSJoshua M. Clulow 	pkt->pkt_resid = ei->ResidualCnt;
1000*b8aa3defSJoshua M. Clulow 
1001*b8aa3defSJoshua M. Clulow 	/*
1002*b8aa3defSJoshua M. Clulow 	 * Check if the controller was reset while this packet was in flight.
1003*b8aa3defSJoshua M. Clulow 	 */
1004*b8aa3defSJoshua M. Clulow 	if (smcm->smcm_status & SMRT_CMD_STATUS_RESET_SENT) {
1005*b8aa3defSJoshua M. Clulow 		if (pkt->pkt_reason != CMD_CMPLT) {
1006*b8aa3defSJoshua M. Clulow 			/*
1007*b8aa3defSJoshua M. Clulow 			 * If another error status has already been written,
1008*b8aa3defSJoshua M. Clulow 			 * do not overwrite it.
1009*b8aa3defSJoshua M. Clulow 			 */
1010*b8aa3defSJoshua M. Clulow 			pkt->pkt_reason = CMD_RESET;
1011*b8aa3defSJoshua M. Clulow 		}
1012*b8aa3defSJoshua M. Clulow 		pkt->pkt_statistics |= STAT_BUS_RESET | STAT_DEV_RESET;
1013*b8aa3defSJoshua M. Clulow 		goto finish;
1014*b8aa3defSJoshua M. Clulow 	}
1015*b8aa3defSJoshua M. Clulow 
1016*b8aa3defSJoshua M. Clulow 	if (!(smcm->smcm_status & SMRT_CMD_STATUS_ERROR)) {
1017*b8aa3defSJoshua M. Clulow 		/*
1018*b8aa3defSJoshua M. Clulow 		 * The command was completed without error by the controller.
1019*b8aa3defSJoshua M. Clulow 		 *
1020*b8aa3defSJoshua M. Clulow 		 * As per the specification, if an error was not signalled
1021*b8aa3defSJoshua M. Clulow 		 * by the controller through the CISS transport method,
1022*b8aa3defSJoshua M. Clulow 		 * the error information (including CommandStatus) has not
1023*b8aa3defSJoshua M. Clulow 		 * been written and should not be checked.
1024*b8aa3defSJoshua M. Clulow 		 */
1025*b8aa3defSJoshua M. Clulow 		pkt->pkt_state |= STATE_XFERRED_DATA | STATE_GOT_STATUS;
1026*b8aa3defSJoshua M. Clulow 		goto finish;
1027*b8aa3defSJoshua M. Clulow 	}
1028*b8aa3defSJoshua M. Clulow 
1029*b8aa3defSJoshua M. Clulow 	/*
1030*b8aa3defSJoshua M. Clulow 	 * Check the completion status to determine what befell this request.
1031*b8aa3defSJoshua M. Clulow 	 */
1032*b8aa3defSJoshua M. Clulow 	switch (ei->CommandStatus) {
1033*b8aa3defSJoshua M. Clulow 	case CISS_CMD_SUCCESS:
1034*b8aa3defSJoshua M. Clulow 		/*
1035*b8aa3defSJoshua M. Clulow 		 * In a certain sense, the specification contradicts itself.
1036*b8aa3defSJoshua M. Clulow 		 * On the one hand, it suggests that a successful command
1037*b8aa3defSJoshua M. Clulow 		 * will not result in a controller write to the error
1038*b8aa3defSJoshua M. Clulow 		 * information block; on the other hand, it makes room
1039*b8aa3defSJoshua M. Clulow 		 * for a status code (0) which denotes a successful
1040*b8aa3defSJoshua M. Clulow 		 * execution.
1041*b8aa3defSJoshua M. Clulow 		 *
1042*b8aa3defSJoshua M. Clulow 		 * To be on the safe side, we check for that condition here.
1043*b8aa3defSJoshua M. Clulow 		 */
1044*b8aa3defSJoshua M. Clulow 		pkt->pkt_state |= STATE_XFERRED_DATA | STATE_GOT_STATUS;
1045*b8aa3defSJoshua M. Clulow 		break;
1046*b8aa3defSJoshua M. Clulow 
1047*b8aa3defSJoshua M. Clulow 	case CISS_CMD_DATA_UNDERRUN:
1048*b8aa3defSJoshua M. Clulow 		/*
1049*b8aa3defSJoshua M. Clulow 		 * A data underrun occurred.  Ideally this will result in
1050*b8aa3defSJoshua M. Clulow 		 * an appropriate SCSI status and sense data.
1051*b8aa3defSJoshua M. Clulow 		 */
1052*b8aa3defSJoshua M. Clulow 		pkt->pkt_state |= STATE_XFERRED_DATA | STATE_GOT_STATUS;
1053*b8aa3defSJoshua M. Clulow 		break;
1054*b8aa3defSJoshua M. Clulow 
1055*b8aa3defSJoshua M. Clulow 	case CISS_CMD_TARGET_STATUS:
1056*b8aa3defSJoshua M. Clulow 		/*
1057*b8aa3defSJoshua M. Clulow 		 * The command completed, but an error occurred.  We need
1058*b8aa3defSJoshua M. Clulow 		 * to provide the sense data to the SCSI framework.
1059*b8aa3defSJoshua M. Clulow 		 */
1060*b8aa3defSJoshua M. Clulow 		pkt->pkt_state |= STATE_XFERRED_DATA | STATE_GOT_STATUS;
1061*b8aa3defSJoshua M. Clulow 		break;
1062*b8aa3defSJoshua M. Clulow 
1063*b8aa3defSJoshua M. Clulow 	case CISS_CMD_DATA_OVERRUN:
1064*b8aa3defSJoshua M. Clulow 		/*
1065*b8aa3defSJoshua M. Clulow 		 * Data overrun has occurred.
1066*b8aa3defSJoshua M. Clulow 		 */
1067*b8aa3defSJoshua M. Clulow 		smrt_hba_complete_log_error(smcm, "data overrun");
1068*b8aa3defSJoshua M. Clulow 		pkt->pkt_reason = CMD_DATA_OVR;
1069*b8aa3defSJoshua M. Clulow 		pkt->pkt_state |= STATE_XFERRED_DATA | STATE_GOT_STATUS;
1070*b8aa3defSJoshua M. Clulow 		break;
1071*b8aa3defSJoshua M. Clulow 
1072*b8aa3defSJoshua M. Clulow 	case CISS_CMD_INVALID:
1073*b8aa3defSJoshua M. Clulow 		/*
1074*b8aa3defSJoshua M. Clulow 		 * One or more fields in the command has invalid data.
1075*b8aa3defSJoshua M. Clulow 		 */
1076*b8aa3defSJoshua M. Clulow 		smrt_hba_complete_log_error(smcm, "invalid command");
1077*b8aa3defSJoshua M. Clulow 		pkt->pkt_reason = CMD_BADMSG;
1078*b8aa3defSJoshua M. Clulow 		pkt->pkt_state |= STATE_GOT_STATUS;
1079*b8aa3defSJoshua M. Clulow 		break;
1080*b8aa3defSJoshua M. Clulow 
1081*b8aa3defSJoshua M. Clulow 	case CISS_CMD_PROTOCOL_ERR:
1082*b8aa3defSJoshua M. Clulow 		/*
1083*b8aa3defSJoshua M. Clulow 		 * An error occurred in communication with the end device.
1084*b8aa3defSJoshua M. Clulow 		 */
1085*b8aa3defSJoshua M. Clulow 		smrt_hba_complete_log_error(smcm, "protocol error");
1086*b8aa3defSJoshua M. Clulow 		pkt->pkt_reason = CMD_BADMSG;
1087*b8aa3defSJoshua M. Clulow 		pkt->pkt_state |= STATE_GOT_STATUS;
1088*b8aa3defSJoshua M. Clulow 		break;
1089*b8aa3defSJoshua M. Clulow 
1090*b8aa3defSJoshua M. Clulow 	case CISS_CMD_HARDWARE_ERR:
1091*b8aa3defSJoshua M. Clulow 		/*
1092*b8aa3defSJoshua M. Clulow 		 * A hardware error occurred.
1093*b8aa3defSJoshua M. Clulow 		 */
1094*b8aa3defSJoshua M. Clulow 		smrt_hba_complete_log_error(smcm, "hardware error");
1095*b8aa3defSJoshua M. Clulow 		pkt->pkt_reason = CMD_INCOMPLETE;
1096*b8aa3defSJoshua M. Clulow 		break;
1097*b8aa3defSJoshua M. Clulow 
1098*b8aa3defSJoshua M. Clulow 	case CISS_CMD_CONNECTION_LOST:
1099*b8aa3defSJoshua M. Clulow 		/*
1100*b8aa3defSJoshua M. Clulow 		 * The connection with the end device cannot be
1101*b8aa3defSJoshua M. Clulow 		 * re-established.
1102*b8aa3defSJoshua M. Clulow 		 */
1103*b8aa3defSJoshua M. Clulow 		smrt_hba_complete_log_error(smcm, "connection lost");
1104*b8aa3defSJoshua M. Clulow 		pkt->pkt_reason = CMD_INCOMPLETE;
1105*b8aa3defSJoshua M. Clulow 		break;
1106*b8aa3defSJoshua M. Clulow 
1107*b8aa3defSJoshua M. Clulow 	case CISS_CMD_ABORTED:
1108*b8aa3defSJoshua M. Clulow 	case CISS_CMD_UNSOLICITED_ABORT:
1109*b8aa3defSJoshua M. Clulow 		if (smcm->smcm_status & SMRT_CMD_STATUS_TIMEOUT) {
1110*b8aa3defSJoshua M. Clulow 			/*
1111*b8aa3defSJoshua M. Clulow 			 * This abort was arranged by the periodic routine
1112*b8aa3defSJoshua M. Clulow 			 * in response to an elapsed timeout.
1113*b8aa3defSJoshua M. Clulow 			 */
1114*b8aa3defSJoshua M. Clulow 			pkt->pkt_reason = CMD_TIMEOUT;
1115*b8aa3defSJoshua M. Clulow 			pkt->pkt_statistics |= STAT_TIMEOUT;
1116*b8aa3defSJoshua M. Clulow 		} else {
1117*b8aa3defSJoshua M. Clulow 			pkt->pkt_reason = CMD_ABORTED;
1118*b8aa3defSJoshua M. Clulow 		}
1119*b8aa3defSJoshua M. Clulow 		pkt->pkt_state |= STATE_XFERRED_DATA | STATE_GOT_STATUS;
1120*b8aa3defSJoshua M. Clulow 		pkt->pkt_statistics |= STAT_ABORTED;
1121*b8aa3defSJoshua M. Clulow 		break;
1122*b8aa3defSJoshua M. Clulow 
1123*b8aa3defSJoshua M. Clulow 	case CISS_CMD_TIMEOUT:
1124*b8aa3defSJoshua M. Clulow 		smrt_hba_complete_log_error(smcm, "timeout");
1125*b8aa3defSJoshua M. Clulow 		pkt->pkt_reason = CMD_TIMEOUT;
1126*b8aa3defSJoshua M. Clulow 		pkt->pkt_statistics |= STAT_TIMEOUT;
1127*b8aa3defSJoshua M. Clulow 		break;
1128*b8aa3defSJoshua M. Clulow 
1129*b8aa3defSJoshua M. Clulow 	default:
1130*b8aa3defSJoshua M. Clulow 		/*
1131*b8aa3defSJoshua M. Clulow 		 * This is an error that we were not prepared to handle.
1132*b8aa3defSJoshua M. Clulow 		 * Signal a generic transport-level error to the framework.
1133*b8aa3defSJoshua M. Clulow 		 */
1134*b8aa3defSJoshua M. Clulow 		smrt_hba_complete_log_error(smcm, "unexpected error");
1135*b8aa3defSJoshua M. Clulow 		pkt->pkt_reason = CMD_TRAN_ERR;
1136*b8aa3defSJoshua M. Clulow 	}
1137*b8aa3defSJoshua M. Clulow 
1138*b8aa3defSJoshua M. Clulow 	/*
1139*b8aa3defSJoshua M. Clulow 	 * Attempt to read a SCSI status code and any automatic
1140*b8aa3defSJoshua M. Clulow 	 * request sense data that may exist:
1141*b8aa3defSJoshua M. Clulow 	 */
1142*b8aa3defSJoshua M. Clulow 	smrt_hba_complete_status(smcm);
1143*b8aa3defSJoshua M. Clulow 
1144*b8aa3defSJoshua M. Clulow finish:
1145*b8aa3defSJoshua M. Clulow 	mutex_exit(&smrt->smrt_mutex);
1146*b8aa3defSJoshua M. Clulow 	scsi_hba_pkt_comp(pkt);
1147*b8aa3defSJoshua M. Clulow 	mutex_enter(&smrt->smrt_mutex);
1148*b8aa3defSJoshua M. Clulow }
1149*b8aa3defSJoshua M. Clulow 
1150*b8aa3defSJoshua M. Clulow static int
smrt_getcap(struct scsi_address * sa,char * cap,int whom)1151*b8aa3defSJoshua M. Clulow smrt_getcap(struct scsi_address *sa, char *cap, int whom)
1152*b8aa3defSJoshua M. Clulow {
1153*b8aa3defSJoshua M. Clulow 	_NOTE(ARGUNUSED(whom))
1154*b8aa3defSJoshua M. Clulow 
1155*b8aa3defSJoshua M. Clulow 	struct scsi_device *sd;
1156*b8aa3defSJoshua M. Clulow 	smrt_target_t *smtg;
1157*b8aa3defSJoshua M. Clulow 	smrt_t *smrt;
1158*b8aa3defSJoshua M. Clulow 	int index;
1159*b8aa3defSJoshua M. Clulow 
1160*b8aa3defSJoshua M. Clulow 	sd = scsi_address_device(sa);
1161*b8aa3defSJoshua M. Clulow 	VERIFY(sd != NULL);
1162*b8aa3defSJoshua M. Clulow 	smtg = scsi_device_hba_private_get(sd);
1163*b8aa3defSJoshua M. Clulow 	VERIFY(smtg != NULL);
1164*b8aa3defSJoshua M. Clulow 	smrt = smtg->smtg_ctlr;
1165*b8aa3defSJoshua M. Clulow 	VERIFY(smrt != NULL);
1166*b8aa3defSJoshua M. Clulow 
1167*b8aa3defSJoshua M. Clulow 	if ((index = scsi_hba_lookup_capstr(cap)) == DDI_FAILURE) {
1168*b8aa3defSJoshua M. Clulow 		/*
1169*b8aa3defSJoshua M. Clulow 		 * This capability string could not be translated to an
1170*b8aa3defSJoshua M. Clulow 		 * ID number, so it must not exist.
1171*b8aa3defSJoshua M. Clulow 		 */
1172*b8aa3defSJoshua M. Clulow 		return (-1);
1173*b8aa3defSJoshua M. Clulow 	}
1174*b8aa3defSJoshua M. Clulow 
1175*b8aa3defSJoshua M. Clulow 	switch (index) {
1176*b8aa3defSJoshua M. Clulow 	case SCSI_CAP_CDB_LEN:
1177*b8aa3defSJoshua M. Clulow 		/*
1178*b8aa3defSJoshua M. Clulow 		 * The CDB field in the CISS request block is fixed at 16
1179*b8aa3defSJoshua M. Clulow 		 * bytes.
1180*b8aa3defSJoshua M. Clulow 		 */
1181*b8aa3defSJoshua M. Clulow 		return (CISS_CDBLEN);
1182*b8aa3defSJoshua M. Clulow 
1183*b8aa3defSJoshua M. Clulow 	case SCSI_CAP_DMA_MAX:
1184*b8aa3defSJoshua M. Clulow 		if (smrt->smrt_dma_attr.dma_attr_maxxfer > INT_MAX) {
1185*b8aa3defSJoshua M. Clulow 			return (INT_MAX);
1186*b8aa3defSJoshua M. Clulow 		}
1187*b8aa3defSJoshua M. Clulow 		return ((int)smrt->smrt_dma_attr.dma_attr_maxxfer);
1188*b8aa3defSJoshua M. Clulow 
1189*b8aa3defSJoshua M. Clulow 	case SCSI_CAP_SECTOR_SIZE:
1190*b8aa3defSJoshua M. Clulow 		if (smrt->smrt_dma_attr.dma_attr_granular > INT_MAX) {
1191*b8aa3defSJoshua M. Clulow 			return (-1);
1192*b8aa3defSJoshua M. Clulow 		}
1193*b8aa3defSJoshua M. Clulow 		return ((int)smrt->smrt_dma_attr.dma_attr_granular);
1194*b8aa3defSJoshua M. Clulow 
1195*b8aa3defSJoshua M. Clulow 	/*
1196*b8aa3defSJoshua M. Clulow 	 * If this target corresponds to a physical device, then we always
1197*b8aa3defSJoshua M. Clulow 	 * indicate that we're on a SAS interconnect.  Otherwise, we default to
1198*b8aa3defSJoshua M. Clulow 	 * saying that we're on a parallel bus.  We can't use SAS for
1199*b8aa3defSJoshua M. Clulow 	 * everything, unfortunately.  When you declare yourself to be a SAS
1200*b8aa3defSJoshua M. Clulow 	 * interconnect, it's expected that you have a full 16-byte WWN as the
1201*b8aa3defSJoshua M. Clulow 	 * target.  If not, devfsadm will not be able to enumerate the device
1202*b8aa3defSJoshua M. Clulow 	 * and create /dev/[r]dsk entries.
1203*b8aa3defSJoshua M. Clulow 	 */
1204*b8aa3defSJoshua M. Clulow 	case SCSI_CAP_INTERCONNECT_TYPE:
1205*b8aa3defSJoshua M. Clulow 		if (smtg->smtg_physical) {
1206*b8aa3defSJoshua M. Clulow 			return (INTERCONNECT_SAS);
1207*b8aa3defSJoshua M. Clulow 		} else {
1208*b8aa3defSJoshua M. Clulow 			return (INTERCONNECT_PARALLEL);
1209*b8aa3defSJoshua M. Clulow 		}
1210*b8aa3defSJoshua M. Clulow 
1211*b8aa3defSJoshua M. Clulow 	case SCSI_CAP_DISCONNECT:
1212*b8aa3defSJoshua M. Clulow 	case SCSI_CAP_SYNCHRONOUS:
1213*b8aa3defSJoshua M. Clulow 	case SCSI_CAP_WIDE_XFER:
1214*b8aa3defSJoshua M. Clulow 	case SCSI_CAP_ARQ:
1215*b8aa3defSJoshua M. Clulow 	case SCSI_CAP_UNTAGGED_QING:
1216*b8aa3defSJoshua M. Clulow 	case SCSI_CAP_TAGGED_QING:
1217*b8aa3defSJoshua M. Clulow 		/*
1218*b8aa3defSJoshua M. Clulow 		 * These capabilities are supported by the driver and the
1219*b8aa3defSJoshua M. Clulow 		 * controller.  See scsi_ifgetcap(9F) for more information.
1220*b8aa3defSJoshua M. Clulow 		 */
1221*b8aa3defSJoshua M. Clulow 		return (1);
1222*b8aa3defSJoshua M. Clulow 
1223*b8aa3defSJoshua M. Clulow 	case SCSI_CAP_INITIATOR_ID:
1224*b8aa3defSJoshua M. Clulow 	case SCSI_CAP_RESET_NOTIFICATION:
1225*b8aa3defSJoshua M. Clulow 		/*
1226*b8aa3defSJoshua M. Clulow 		 * These capabilities are not supported.
1227*b8aa3defSJoshua M. Clulow 		 */
1228*b8aa3defSJoshua M. Clulow 		return (0);
1229*b8aa3defSJoshua M. Clulow 
1230*b8aa3defSJoshua M. Clulow 	default:
1231*b8aa3defSJoshua M. Clulow 		/*
1232*b8aa3defSJoshua M. Clulow 		 * The property in question is not known to this driver.
1233*b8aa3defSJoshua M. Clulow 		 */
1234*b8aa3defSJoshua M. Clulow 		return (-1);
1235*b8aa3defSJoshua M. Clulow 	}
1236*b8aa3defSJoshua M. Clulow }
1237*b8aa3defSJoshua M. Clulow 
1238*b8aa3defSJoshua M. Clulow /* ARGSUSED */
1239*b8aa3defSJoshua M. Clulow static int
smrt_setcap(struct scsi_address * sa,char * cap,int value,int whom)1240*b8aa3defSJoshua M. Clulow smrt_setcap(struct scsi_address *sa, char *cap, int value, int whom)
1241*b8aa3defSJoshua M. Clulow {
1242*b8aa3defSJoshua M. Clulow 	int index;
1243*b8aa3defSJoshua M. Clulow 
1244*b8aa3defSJoshua M. Clulow 	if ((index = scsi_hba_lookup_capstr(cap)) == DDI_FAILURE) {
1245*b8aa3defSJoshua M. Clulow 		/*
1246*b8aa3defSJoshua M. Clulow 		 * This capability string could not be translated to an
1247*b8aa3defSJoshua M. Clulow 		 * ID number, so it must not exist.
1248*b8aa3defSJoshua M. Clulow 		 */
1249*b8aa3defSJoshua M. Clulow 		return (-1);
1250*b8aa3defSJoshua M. Clulow 	}
1251*b8aa3defSJoshua M. Clulow 
1252*b8aa3defSJoshua M. Clulow 	if (whom == 0) {
1253*b8aa3defSJoshua M. Clulow 		/*
1254*b8aa3defSJoshua M. Clulow 		 * When whom is 0, this is a request to set a capability for
1255*b8aa3defSJoshua M. Clulow 		 * all targets.  As per the recommendation in tran_setcap(9E),
1256*b8aa3defSJoshua M. Clulow 		 * we do not support this mode of operation.
1257*b8aa3defSJoshua M. Clulow 		 */
1258*b8aa3defSJoshua M. Clulow 		return (-1);
1259*b8aa3defSJoshua M. Clulow 	}
1260*b8aa3defSJoshua M. Clulow 
1261*b8aa3defSJoshua M. Clulow 	switch (index) {
1262*b8aa3defSJoshua M. Clulow 	case SCSI_CAP_CDB_LEN:
1263*b8aa3defSJoshua M. Clulow 	case SCSI_CAP_DMA_MAX:
1264*b8aa3defSJoshua M. Clulow 	case SCSI_CAP_SECTOR_SIZE:
1265*b8aa3defSJoshua M. Clulow 	case SCSI_CAP_INITIATOR_ID:
1266*b8aa3defSJoshua M. Clulow 	case SCSI_CAP_DISCONNECT:
1267*b8aa3defSJoshua M. Clulow 	case SCSI_CAP_SYNCHRONOUS:
1268*b8aa3defSJoshua M. Clulow 	case SCSI_CAP_WIDE_XFER:
1269*b8aa3defSJoshua M. Clulow 	case SCSI_CAP_ARQ:
1270*b8aa3defSJoshua M. Clulow 	case SCSI_CAP_UNTAGGED_QING:
1271*b8aa3defSJoshua M. Clulow 	case SCSI_CAP_TAGGED_QING:
1272*b8aa3defSJoshua M. Clulow 	case SCSI_CAP_RESET_NOTIFICATION:
1273*b8aa3defSJoshua M. Clulow 	case SCSI_CAP_INTERCONNECT_TYPE:
1274*b8aa3defSJoshua M. Clulow 		/*
1275*b8aa3defSJoshua M. Clulow 		 * We do not support changing any capabilities at this time.
1276*b8aa3defSJoshua M. Clulow 		 */
1277*b8aa3defSJoshua M. Clulow 		return (0);
1278*b8aa3defSJoshua M. Clulow 
1279*b8aa3defSJoshua M. Clulow 	default:
1280*b8aa3defSJoshua M. Clulow 		/*
1281*b8aa3defSJoshua M. Clulow 		 * The capability in question is not known to this driver.
1282*b8aa3defSJoshua M. Clulow 		 */
1283*b8aa3defSJoshua M. Clulow 		return (-1);
1284*b8aa3defSJoshua M. Clulow 	}
1285*b8aa3defSJoshua M. Clulow }
1286*b8aa3defSJoshua M. Clulow 
1287*b8aa3defSJoshua M. Clulow int
smrt_ctrl_hba_setup(smrt_t * smrt)1288*b8aa3defSJoshua M. Clulow smrt_ctrl_hba_setup(smrt_t *smrt)
1289*b8aa3defSJoshua M. Clulow {
1290*b8aa3defSJoshua M. Clulow 	int flags;
1291*b8aa3defSJoshua M. Clulow 	dev_info_t *dip = smrt->smrt_dip;
1292*b8aa3defSJoshua M. Clulow 	scsi_hba_tran_t *tran;
1293*b8aa3defSJoshua M. Clulow 
1294*b8aa3defSJoshua M. Clulow 	if ((tran = scsi_hba_tran_alloc(dip, SCSI_HBA_CANSLEEP)) == NULL) {
1295*b8aa3defSJoshua M. Clulow 		dev_err(dip, CE_WARN, "could not allocate SCSA resources");
1296*b8aa3defSJoshua M. Clulow 		return (DDI_FAILURE);
1297*b8aa3defSJoshua M. Clulow 	}
1298*b8aa3defSJoshua M. Clulow 
1299*b8aa3defSJoshua M. Clulow 	smrt->smrt_hba_tran = tran;
1300*b8aa3defSJoshua M. Clulow 	tran->tran_hba_private = smrt;
1301*b8aa3defSJoshua M. Clulow 
1302*b8aa3defSJoshua M. Clulow 	tran->tran_tgt_init = smrt_ctrl_tran_tgt_init;
1303*b8aa3defSJoshua M. Clulow 	tran->tran_tgt_probe = scsi_hba_probe;
1304*b8aa3defSJoshua M. Clulow 
1305*b8aa3defSJoshua M. Clulow 	tran->tran_start = smrt_ctrl_tran_start;
1306*b8aa3defSJoshua M. Clulow 
1307*b8aa3defSJoshua M. Clulow 	tran->tran_getcap = smrt_getcap;
1308*b8aa3defSJoshua M. Clulow 	tran->tran_setcap = smrt_setcap;
1309*b8aa3defSJoshua M. Clulow 
1310*b8aa3defSJoshua M. Clulow 	tran->tran_setup_pkt = smrt_tran_setup_pkt;
1311*b8aa3defSJoshua M. Clulow 	tran->tran_teardown_pkt = smrt_tran_teardown_pkt;
1312*b8aa3defSJoshua M. Clulow 	tran->tran_hba_len = sizeof (smrt_command_scsa_t);
1313*b8aa3defSJoshua M. Clulow 	tran->tran_interconnect_type = INTERCONNECT_SAS;
1314*b8aa3defSJoshua M. Clulow 
1315*b8aa3defSJoshua M. Clulow 	flags = SCSI_HBA_HBA | SCSI_HBA_TRAN_SCB | SCSI_HBA_ADDR_COMPLEX;
1316*b8aa3defSJoshua M. Clulow 	if (scsi_hba_attach_setup(dip, &smrt->smrt_dma_attr, tran, flags) !=
1317*b8aa3defSJoshua M. Clulow 	    DDI_SUCCESS) {
1318*b8aa3defSJoshua M. Clulow 		dev_err(dip, CE_WARN, "could not attach to SCSA framework");
1319*b8aa3defSJoshua M. Clulow 		scsi_hba_tran_free(tran);
1320*b8aa3defSJoshua M. Clulow 		return (DDI_FAILURE);
1321*b8aa3defSJoshua M. Clulow 	}
1322*b8aa3defSJoshua M. Clulow 
1323*b8aa3defSJoshua M. Clulow 	smrt->smrt_init_level |= SMRT_INITLEVEL_SCSA;
1324*b8aa3defSJoshua M. Clulow 	return (DDI_SUCCESS);
1325*b8aa3defSJoshua M. Clulow }
1326*b8aa3defSJoshua M. Clulow 
1327*b8aa3defSJoshua M. Clulow void
smrt_ctrl_hba_teardown(smrt_t * smrt)1328*b8aa3defSJoshua M. Clulow smrt_ctrl_hba_teardown(smrt_t *smrt)
1329*b8aa3defSJoshua M. Clulow {
1330*b8aa3defSJoshua M. Clulow 	if (smrt->smrt_init_level & SMRT_INITLEVEL_SCSA) {
1331*b8aa3defSJoshua M. Clulow 		VERIFY(scsi_hba_detach(smrt->smrt_dip) != DDI_FAILURE);
1332*b8aa3defSJoshua M. Clulow 		scsi_hba_tran_free(smrt->smrt_hba_tran);
1333*b8aa3defSJoshua M. Clulow 		smrt->smrt_init_level &= ~SMRT_INITLEVEL_SCSA;
1334*b8aa3defSJoshua M. Clulow 	}
1335*b8aa3defSJoshua M. Clulow }
1336*b8aa3defSJoshua M. Clulow 
1337*b8aa3defSJoshua M. Clulow int
smrt_logvol_hba_setup(smrt_t * smrt,dev_info_t * iport)1338*b8aa3defSJoshua M. Clulow smrt_logvol_hba_setup(smrt_t *smrt, dev_info_t *iport)
1339*b8aa3defSJoshua M. Clulow {
1340*b8aa3defSJoshua M. Clulow 	scsi_hba_tran_t *tran;
1341*b8aa3defSJoshua M. Clulow 
1342*b8aa3defSJoshua M. Clulow 	tran = ddi_get_driver_private(iport);
1343*b8aa3defSJoshua M. Clulow 	if (tran == NULL)
1344*b8aa3defSJoshua M. Clulow 		return (DDI_FAILURE);
1345*b8aa3defSJoshua M. Clulow 
1346*b8aa3defSJoshua M. Clulow 	tran->tran_tgt_init = smrt_logvol_tran_tgt_init;
1347*b8aa3defSJoshua M. Clulow 	tran->tran_tgt_free = smrt_logvol_tran_tgt_free;
1348*b8aa3defSJoshua M. Clulow 
1349*b8aa3defSJoshua M. Clulow 	tran->tran_start = smrt_tran_start;
1350*b8aa3defSJoshua M. Clulow 	tran->tran_reset = smrt_tran_reset;
1351*b8aa3defSJoshua M. Clulow 	tran->tran_abort = smrt_tran_abort;
1352*b8aa3defSJoshua M. Clulow 
1353*b8aa3defSJoshua M. Clulow 	tran->tran_hba_private = smrt;
1354*b8aa3defSJoshua M. Clulow 
1355*b8aa3defSJoshua M. Clulow 	mutex_enter(&smrt->smrt_mutex);
1356*b8aa3defSJoshua M. Clulow 	if (scsi_hba_tgtmap_create(iport, SCSI_TM_FULLSET, MICROSEC,
1357*b8aa3defSJoshua M. Clulow 	    2 * MICROSEC, smrt, smrt_logvol_tgtmap_activate,
1358*b8aa3defSJoshua M. Clulow 	    smrt_logvol_tgtmap_deactivate, &smrt->smrt_virt_tgtmap) !=
1359*b8aa3defSJoshua M. Clulow 	    DDI_SUCCESS) {
1360*b8aa3defSJoshua M. Clulow 		return (DDI_FAILURE);
1361*b8aa3defSJoshua M. Clulow 	}
1362*b8aa3defSJoshua M. Clulow 
1363*b8aa3defSJoshua M. Clulow 	smrt_discover_request(smrt);
1364*b8aa3defSJoshua M. Clulow 	mutex_exit(&smrt->smrt_mutex);
1365*b8aa3defSJoshua M. Clulow 
1366*b8aa3defSJoshua M. Clulow 	return (DDI_SUCCESS);
1367*b8aa3defSJoshua M. Clulow }
1368*b8aa3defSJoshua M. Clulow 
1369*b8aa3defSJoshua M. Clulow void
smrt_logvol_hba_teardown(smrt_t * smrt,dev_info_t * iport)1370*b8aa3defSJoshua M. Clulow smrt_logvol_hba_teardown(smrt_t *smrt, dev_info_t *iport)
1371*b8aa3defSJoshua M. Clulow {
1372*b8aa3defSJoshua M. Clulow 	ASSERT(smrt->smrt_virt_iport == iport);
1373*b8aa3defSJoshua M. Clulow 
1374*b8aa3defSJoshua M. Clulow 	mutex_enter(&smrt->smrt_mutex);
1375*b8aa3defSJoshua M. Clulow 
1376*b8aa3defSJoshua M. Clulow 	if (smrt->smrt_virt_tgtmap != NULL) {
1377*b8aa3defSJoshua M. Clulow 		scsi_hba_tgtmap_t *t;
1378*b8aa3defSJoshua M. Clulow 
1379*b8aa3defSJoshua M. Clulow 		/*
1380*b8aa3defSJoshua M. Clulow 		 * Ensure that we can't be racing with discovery.
1381*b8aa3defSJoshua M. Clulow 		 */
1382*b8aa3defSJoshua M. Clulow 		while (smrt->smrt_status & SMRT_CTLR_DISCOVERY_RUNNING) {
1383*b8aa3defSJoshua M. Clulow 			mutex_exit(&smrt->smrt_mutex);
1384*b8aa3defSJoshua M. Clulow 			ddi_taskq_wait(smrt->smrt_discover_taskq);
1385*b8aa3defSJoshua M. Clulow 			mutex_enter(&smrt->smrt_mutex);
1386*b8aa3defSJoshua M. Clulow 		}
1387*b8aa3defSJoshua M. Clulow 
1388*b8aa3defSJoshua M. Clulow 		t = smrt->smrt_virt_tgtmap;
1389*b8aa3defSJoshua M. Clulow 		smrt->smrt_virt_tgtmap = NULL;
1390*b8aa3defSJoshua M. Clulow 		mutex_exit(&smrt->smrt_mutex);
1391*b8aa3defSJoshua M. Clulow 		scsi_hba_tgtmap_destroy(t);
1392*b8aa3defSJoshua M. Clulow 		mutex_enter(&smrt->smrt_mutex);
1393*b8aa3defSJoshua M. Clulow 	}
1394*b8aa3defSJoshua M. Clulow 
1395*b8aa3defSJoshua M. Clulow 	mutex_exit(&smrt->smrt_mutex);
1396*b8aa3defSJoshua M. Clulow }
1397*b8aa3defSJoshua M. Clulow 
1398*b8aa3defSJoshua M. Clulow int
smrt_phys_hba_setup(smrt_t * smrt,dev_info_t * iport)1399*b8aa3defSJoshua M. Clulow smrt_phys_hba_setup(smrt_t *smrt, dev_info_t *iport)
1400*b8aa3defSJoshua M. Clulow {
1401*b8aa3defSJoshua M. Clulow 	scsi_hba_tran_t *tran;
1402*b8aa3defSJoshua M. Clulow 
1403*b8aa3defSJoshua M. Clulow 	tran = ddi_get_driver_private(iport);
1404*b8aa3defSJoshua M. Clulow 	if (tran == NULL)
1405*b8aa3defSJoshua M. Clulow 		return (DDI_FAILURE);
1406*b8aa3defSJoshua M. Clulow 
1407*b8aa3defSJoshua M. Clulow 	tran->tran_tgt_init = smrt_phys_tran_tgt_init;
1408*b8aa3defSJoshua M. Clulow 	tran->tran_tgt_free = smrt_phys_tran_tgt_free;
1409*b8aa3defSJoshua M. Clulow 
1410*b8aa3defSJoshua M. Clulow 	tran->tran_start = smrt_tran_start;
1411*b8aa3defSJoshua M. Clulow 	tran->tran_reset = smrt_tran_reset;
1412*b8aa3defSJoshua M. Clulow 	tran->tran_abort = smrt_tran_abort;
1413*b8aa3defSJoshua M. Clulow 
1414*b8aa3defSJoshua M. Clulow 	tran->tran_hba_private = smrt;
1415*b8aa3defSJoshua M. Clulow 
1416*b8aa3defSJoshua M. Clulow 	mutex_enter(&smrt->smrt_mutex);
1417*b8aa3defSJoshua M. Clulow 	if (scsi_hba_tgtmap_create(iport, SCSI_TM_FULLSET, MICROSEC,
1418*b8aa3defSJoshua M. Clulow 	    2 * MICROSEC, smrt, smrt_phys_tgtmap_activate,
1419*b8aa3defSJoshua M. Clulow 	    smrt_phys_tgtmap_deactivate, &smrt->smrt_phys_tgtmap) !=
1420*b8aa3defSJoshua M. Clulow 	    DDI_SUCCESS) {
1421*b8aa3defSJoshua M. Clulow 		return (DDI_FAILURE);
1422*b8aa3defSJoshua M. Clulow 	}
1423*b8aa3defSJoshua M. Clulow 
1424*b8aa3defSJoshua M. Clulow 	smrt_discover_request(smrt);
1425*b8aa3defSJoshua M. Clulow 	mutex_exit(&smrt->smrt_mutex);
1426*b8aa3defSJoshua M. Clulow 
1427*b8aa3defSJoshua M. Clulow 	return (DDI_SUCCESS);
1428*b8aa3defSJoshua M. Clulow }
1429*b8aa3defSJoshua M. Clulow 
1430*b8aa3defSJoshua M. Clulow void
smrt_phys_hba_teardown(smrt_t * smrt,dev_info_t * iport)1431*b8aa3defSJoshua M. Clulow smrt_phys_hba_teardown(smrt_t *smrt, dev_info_t *iport)
1432*b8aa3defSJoshua M. Clulow {
1433*b8aa3defSJoshua M. Clulow 	ASSERT(smrt->smrt_phys_iport == iport);
1434*b8aa3defSJoshua M. Clulow 
1435*b8aa3defSJoshua M. Clulow 	mutex_enter(&smrt->smrt_mutex);
1436*b8aa3defSJoshua M. Clulow 
1437*b8aa3defSJoshua M. Clulow 	if (smrt->smrt_phys_tgtmap != NULL) {
1438*b8aa3defSJoshua M. Clulow 		scsi_hba_tgtmap_t *t;
1439*b8aa3defSJoshua M. Clulow 
1440*b8aa3defSJoshua M. Clulow 		/*
1441*b8aa3defSJoshua M. Clulow 		 * Ensure that we can't be racing with discovery.
1442*b8aa3defSJoshua M. Clulow 		 */
1443*b8aa3defSJoshua M. Clulow 		while (smrt->smrt_status & SMRT_CTLR_DISCOVERY_RUNNING) {
1444*b8aa3defSJoshua M. Clulow 			mutex_exit(&smrt->smrt_mutex);
1445*b8aa3defSJoshua M. Clulow 			ddi_taskq_wait(smrt->smrt_discover_taskq);
1446*b8aa3defSJoshua M. Clulow 			mutex_enter(&smrt->smrt_mutex);
1447*b8aa3defSJoshua M. Clulow 		}
1448*b8aa3defSJoshua M. Clulow 
1449*b8aa3defSJoshua M. Clulow 		t = smrt->smrt_phys_tgtmap;
1450*b8aa3defSJoshua M. Clulow 		smrt->smrt_phys_tgtmap = NULL;
1451*b8aa3defSJoshua M. Clulow 		mutex_exit(&smrt->smrt_mutex);
1452*b8aa3defSJoshua M. Clulow 		scsi_hba_tgtmap_destroy(t);
1453*b8aa3defSJoshua M. Clulow 		mutex_enter(&smrt->smrt_mutex);
1454*b8aa3defSJoshua M. Clulow 	}
1455*b8aa3defSJoshua M. Clulow 
1456*b8aa3defSJoshua M. Clulow 	mutex_exit(&smrt->smrt_mutex);
1457*b8aa3defSJoshua M. Clulow }
1458