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