1*80c94ecdSKeith M Wesolowski /*
2*80c94ecdSKeith M Wesolowski * This file and its contents are supplied under the terms of the
3*80c94ecdSKeith M Wesolowski * Common Development and Distribution License ("CDDL"), version 1.0.
4*80c94ecdSKeith M Wesolowski * You may only use this file in accordance with the terms of version
5*80c94ecdSKeith M Wesolowski * 1.0 of the CDDL.
6*80c94ecdSKeith M Wesolowski *
7*80c94ecdSKeith M Wesolowski * A full copy of the text of the CDDL should have accompanied this
8*80c94ecdSKeith M Wesolowski * source. A copy of the CDDL is also available via the Internet at
9*80c94ecdSKeith M Wesolowski * http://www.illumos.org/license/CDDL.
10*80c94ecdSKeith M Wesolowski */
11*80c94ecdSKeith M Wesolowski
12*80c94ecdSKeith M Wesolowski /*
13*80c94ecdSKeith M Wesolowski * Copyright (C) 2013 Hewlett-Packard Development Company, L.P.
14*80c94ecdSKeith M Wesolowski */
15*80c94ecdSKeith M Wesolowski
16*80c94ecdSKeith M Wesolowski /*
17*80c94ecdSKeith M Wesolowski * Supported IOCTLs :
18*80c94ecdSKeith M Wesolowski * CPQARY3_IOCTL_DRIVER_INFO - to get driver details
19*80c94ecdSKeith M Wesolowski * CPQARY3_IOCTL_CTLR_INFO - to get controller details
20*80c94ecdSKeith M Wesolowski * CPQARY3_IOCTL_BMIC_PASS - to pass BMIC commands
21*80c94ecdSKeith M Wesolowski * CPQARY3_IOCTL_SCSI_PASS - to pass SCSI commands
22*80c94ecdSKeith M Wesolowski */
23*80c94ecdSKeith M Wesolowski
24*80c94ecdSKeith M Wesolowski #include "cpqary3.h"
25*80c94ecdSKeith M Wesolowski
26*80c94ecdSKeith M Wesolowski /*
27*80c94ecdSKeith M Wesolowski * Local Functions Declaration
28*80c94ecdSKeith M Wesolowski */
29*80c94ecdSKeith M Wesolowski
30*80c94ecdSKeith M Wesolowski static int32_t cpqary3_ioctl_send_bmiccmd(cpqary3_t *, cpqary3_bmic_pass_t *,
31*80c94ecdSKeith M Wesolowski int);
32*80c94ecdSKeith M Wesolowski static void cpqary3_ioctl_fil_bmic(CommandList_t *, cpqary3_bmic_pass_t *);
33*80c94ecdSKeith M Wesolowski static void cpqary3_ioctl_fil_bmic_sas(CommandList_t *, cpqary3_bmic_pass_t *);
34*80c94ecdSKeith M Wesolowski static int32_t cpqary3_ioctl_send_scsicmd(cpqary3_t *, cpqary3_scsi_pass_t *,
35*80c94ecdSKeith M Wesolowski int);
36*80c94ecdSKeith M Wesolowski static void cpqary3_ioctl_fil_scsi(CommandList_t *, cpqary3_scsi_pass_t *);
37*80c94ecdSKeith M Wesolowski
38*80c94ecdSKeith M Wesolowski /*
39*80c94ecdSKeith M Wesolowski * Global Variables Definitions
40*80c94ecdSKeith M Wesolowski */
41*80c94ecdSKeith M Wesolowski
42*80c94ecdSKeith M Wesolowski cpqary3_driver_info_t gdriver_info = {0};
43*80c94ecdSKeith M Wesolowski
44*80c94ecdSKeith M Wesolowski /* Function Definitions */
45*80c94ecdSKeith M Wesolowski
46*80c94ecdSKeith M Wesolowski /*
47*80c94ecdSKeith M Wesolowski * Function : cpqary3_ioctl_driver_info
48*80c94ecdSKeith M Wesolowski * Description : This routine will get major/ minor versions, Number of
49*80c94ecdSKeith M Wesolowski * controllers detected & MAX Number of controllers
50*80c94ecdSKeith M Wesolowski * supported
51*80c94ecdSKeith M Wesolowski * Called By : cpqary3_ioctl
52*80c94ecdSKeith M Wesolowski * Parameters : ioctl_reqp - address of the parameter sent from
53*80c94ecdSKeith M Wesolowski * the application
54*80c94ecdSKeith M Wesolowski * cpqary3p - address of the PerController structure
55*80c94ecdSKeith M Wesolowski * mode - mode which comes from application
56*80c94ecdSKeith M Wesolowski * Return Values: EFAULT on Failure, 0 on SUCCESS
57*80c94ecdSKeith M Wesolowski */
58*80c94ecdSKeith M Wesolowski int32_t
cpqary3_ioctl_driver_info(uintptr_t ioctl_reqp,int mode)59*80c94ecdSKeith M Wesolowski cpqary3_ioctl_driver_info(uintptr_t ioctl_reqp, int mode)
60*80c94ecdSKeith M Wesolowski {
61*80c94ecdSKeith M Wesolowski cpqary3_ioctl_request_t *request;
62*80c94ecdSKeith M Wesolowski
63*80c94ecdSKeith M Wesolowski request = (cpqary3_ioctl_request_t *)
64*80c94ecdSKeith M Wesolowski MEM_ZALLOC(sizeof (cpqary3_ioctl_request_t));
65*80c94ecdSKeith M Wesolowski
66*80c94ecdSKeith M Wesolowski if (NULL == request)
67*80c94ecdSKeith M Wesolowski return (FAILURE);
68*80c94ecdSKeith M Wesolowski
69*80c94ecdSKeith M Wesolowski /*
70*80c94ecdSKeith M Wesolowski * First let us copyin the ioctl_reqp user buffer to request(kernel)
71*80c94ecdSKeith M Wesolowski * memory. This is very much recomended before we access any of the
72*80c94ecdSKeith M Wesolowski * fields.
73*80c94ecdSKeith M Wesolowski */
74*80c94ecdSKeith M Wesolowski if (ddi_copyin((void *)ioctl_reqp, (void *)request,
75*80c94ecdSKeith M Wesolowski sizeof (cpqary3_ioctl_request_t), mode)) {
76*80c94ecdSKeith M Wesolowski MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t));
77*80c94ecdSKeith M Wesolowski return (EFAULT);
78*80c94ecdSKeith M Wesolowski }
79*80c94ecdSKeith M Wesolowski
80*80c94ecdSKeith M Wesolowski /*
81*80c94ecdSKeith M Wesolowski * Fill up the global structure "gdriver_info" memory.
82*80c94ecdSKeith M Wesolowski * Fill this structure with available info, which will be copied
83*80c94ecdSKeith M Wesolowski * back later
84*80c94ecdSKeith M Wesolowski */
85*80c94ecdSKeith M Wesolowski
86*80c94ecdSKeith M Wesolowski (void) strcpy(gdriver_info.name, "cpqary3");
87*80c94ecdSKeith M Wesolowski gdriver_info.version.minor = CPQARY3_MINOR_REV_NO;
88*80c94ecdSKeith M Wesolowski gdriver_info.version.major = CPQARY3_MAJOR_REV_NO;
89*80c94ecdSKeith M Wesolowski gdriver_info.version.dd = CPQARY3_REV_MONTH;
90*80c94ecdSKeith M Wesolowski gdriver_info.version.mm = CPQARY3_REV_DATE;
91*80c94ecdSKeith M Wesolowski gdriver_info.version.yyyy = CPQARY3_REV_YEAR;
92*80c94ecdSKeith M Wesolowski gdriver_info.max_num_ctlr = MAX_CTLRS;
93*80c94ecdSKeith M Wesolowski
94*80c94ecdSKeith M Wesolowski /*
95*80c94ecdSKeith M Wesolowski * First Copy out the driver_info structure
96*80c94ecdSKeith M Wesolowski */
97*80c94ecdSKeith M Wesolowski
98*80c94ecdSKeith M Wesolowski if (ddi_copyout((void *)&gdriver_info, (void *)(uintptr_t)request->argp,
99*80c94ecdSKeith M Wesolowski sizeof (cpqary3_driver_info_t), mode)) {
100*80c94ecdSKeith M Wesolowski MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t));
101*80c94ecdSKeith M Wesolowski return (EFAULT);
102*80c94ecdSKeith M Wesolowski }
103*80c94ecdSKeith M Wesolowski
104*80c94ecdSKeith M Wesolowski /*
105*80c94ecdSKeith M Wesolowski * Copy out the request structure back
106*80c94ecdSKeith M Wesolowski */
107*80c94ecdSKeith M Wesolowski
108*80c94ecdSKeith M Wesolowski if (ddi_copyout((void *)request, (void *)ioctl_reqp,
109*80c94ecdSKeith M Wesolowski sizeof (cpqary3_ioctl_request_t), mode)) {
110*80c94ecdSKeith M Wesolowski MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t));
111*80c94ecdSKeith M Wesolowski return (EFAULT);
112*80c94ecdSKeith M Wesolowski }
113*80c94ecdSKeith M Wesolowski
114*80c94ecdSKeith M Wesolowski MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t));
115*80c94ecdSKeith M Wesolowski
116*80c94ecdSKeith M Wesolowski /*
117*80c94ecdSKeith M Wesolowski * Everything looks fine. So return SUCCESS
118*80c94ecdSKeith M Wesolowski */
119*80c94ecdSKeith M Wesolowski
120*80c94ecdSKeith M Wesolowski return (SUCCESS);
121*80c94ecdSKeith M Wesolowski }
122*80c94ecdSKeith M Wesolowski
123*80c94ecdSKeith M Wesolowski /*
124*80c94ecdSKeith M Wesolowski * Function : cpqary3_ioctl_ctlr_info
125*80c94ecdSKeith M Wesolowski * Description : This routine will get the controller related info, like
126*80c94ecdSKeith M Wesolowski * board-id, subsystem-id, num of logical drives,
127*80c94ecdSKeith M Wesolowski * slot number
128*80c94ecdSKeith M Wesolowski * Called By : cpqary3_ioctl
129*80c94ecdSKeith M Wesolowski * Parameters : ioctl_reqp - address of the parameter sent form the
130*80c94ecdSKeith M Wesolowski * application
131*80c94ecdSKeith M Wesolowski * cpqary3p - address of the PerController structure
132*80c94ecdSKeith M Wesolowski * mode - mode which comes from application
133*80c94ecdSKeith M Wesolowski * Return Values: EFAULT on Failure, 0 on SUCCESS
134*80c94ecdSKeith M Wesolowski */
135*80c94ecdSKeith M Wesolowski int32_t
cpqary3_ioctl_ctlr_info(uintptr_t ioctl_reqp,cpqary3_t * cpqary3p,int mode)136*80c94ecdSKeith M Wesolowski cpqary3_ioctl_ctlr_info(uintptr_t ioctl_reqp, cpqary3_t *cpqary3p, int mode)
137*80c94ecdSKeith M Wesolowski {
138*80c94ecdSKeith M Wesolowski cpqary3_ioctl_request_t *request;
139*80c94ecdSKeith M Wesolowski cpqary3_ctlr_info_t *ctlr_info;
140*80c94ecdSKeith M Wesolowski
141*80c94ecdSKeith M Wesolowski request = (cpqary3_ioctl_request_t *)
142*80c94ecdSKeith M Wesolowski MEM_ZALLOC(sizeof (cpqary3_ioctl_request_t));
143*80c94ecdSKeith M Wesolowski
144*80c94ecdSKeith M Wesolowski if (NULL == request)
145*80c94ecdSKeith M Wesolowski return (FAILURE);
146*80c94ecdSKeith M Wesolowski
147*80c94ecdSKeith M Wesolowski /*
148*80c94ecdSKeith M Wesolowski * First let us copyin the buffer to kernel memory. This is very much
149*80c94ecdSKeith M Wesolowski * recomended before we access any of the fields.
150*80c94ecdSKeith M Wesolowski */
151*80c94ecdSKeith M Wesolowski
152*80c94ecdSKeith M Wesolowski if (ddi_copyin((void *) ioctl_reqp, (void *)request,
153*80c94ecdSKeith M Wesolowski sizeof (cpqary3_ioctl_request_t), mode)) {
154*80c94ecdSKeith M Wesolowski MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t));
155*80c94ecdSKeith M Wesolowski return (EFAULT);
156*80c94ecdSKeith M Wesolowski }
157*80c94ecdSKeith M Wesolowski
158*80c94ecdSKeith M Wesolowski ctlr_info = (cpqary3_ctlr_info_t *)
159*80c94ecdSKeith M Wesolowski MEM_ZALLOC(sizeof (cpqary3_ctlr_info_t));
160*80c94ecdSKeith M Wesolowski
161*80c94ecdSKeith M Wesolowski if (NULL == ctlr_info) {
162*80c94ecdSKeith M Wesolowski MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t));
163*80c94ecdSKeith M Wesolowski return (FAILURE);
164*80c94ecdSKeith M Wesolowski }
165*80c94ecdSKeith M Wesolowski
166*80c94ecdSKeith M Wesolowski /*
167*80c94ecdSKeith M Wesolowski * in the driver, board_id is actually subsystem_id
168*80c94ecdSKeith M Wesolowski */
169*80c94ecdSKeith M Wesolowski
170*80c94ecdSKeith M Wesolowski ctlr_info->subsystem_id = cpqary3p->board_id;
171*80c94ecdSKeith M Wesolowski ctlr_info->bus = cpqary3p->bus;
172*80c94ecdSKeith M Wesolowski ctlr_info->dev = cpqary3p->dev;
173*80c94ecdSKeith M Wesolowski ctlr_info->fun = cpqary3p->fun;
174*80c94ecdSKeith M Wesolowski ctlr_info->num_of_tgts = cpqary3p->num_of_targets;
175*80c94ecdSKeith M Wesolowski ctlr_info->controller_instance = cpqary3p->instance;
176*80c94ecdSKeith M Wesolowski
177*80c94ecdSKeith M Wesolowski /*
178*80c94ecdSKeith M Wesolowski * TODO: ctlr_info.slot_num has to be implemented
179*80c94ecdSKeith M Wesolowski * state & board_id fields are kept for future implementation i
180*80c94ecdSKeith M Wesolowski * if required!
181*80c94ecdSKeith M Wesolowski */
182*80c94ecdSKeith M Wesolowski
183*80c94ecdSKeith M Wesolowski /*
184*80c94ecdSKeith M Wesolowski * First Copy out the ctlr_info structure
185*80c94ecdSKeith M Wesolowski */
186*80c94ecdSKeith M Wesolowski
187*80c94ecdSKeith M Wesolowski if (ddi_copyout((void *)ctlr_info, (void *)(uintptr_t)request->argp,
188*80c94ecdSKeith M Wesolowski sizeof (cpqary3_ctlr_info_t), mode)) {
189*80c94ecdSKeith M Wesolowski MEM_SFREE(ctlr_info, sizeof (cpqary3_ctlr_info_t));
190*80c94ecdSKeith M Wesolowski MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t));
191*80c94ecdSKeith M Wesolowski return (EFAULT);
192*80c94ecdSKeith M Wesolowski }
193*80c94ecdSKeith M Wesolowski
194*80c94ecdSKeith M Wesolowski /*
195*80c94ecdSKeith M Wesolowski * Copy out the request structure back
196*80c94ecdSKeith M Wesolowski */
197*80c94ecdSKeith M Wesolowski
198*80c94ecdSKeith M Wesolowski if (ddi_copyout((void *)request, (void *)ioctl_reqp,
199*80c94ecdSKeith M Wesolowski sizeof (cpqary3_ioctl_request_t), mode)) {
200*80c94ecdSKeith M Wesolowski MEM_SFREE(ctlr_info, sizeof (cpqary3_ctlr_info_t));
201*80c94ecdSKeith M Wesolowski MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t));
202*80c94ecdSKeith M Wesolowski return (EFAULT);
203*80c94ecdSKeith M Wesolowski }
204*80c94ecdSKeith M Wesolowski
205*80c94ecdSKeith M Wesolowski MEM_SFREE(ctlr_info, sizeof (cpqary3_ctlr_info_t));
206*80c94ecdSKeith M Wesolowski MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t));
207*80c94ecdSKeith M Wesolowski
208*80c94ecdSKeith M Wesolowski /*
209*80c94ecdSKeith M Wesolowski * Everything looks fine. So return SUCCESS
210*80c94ecdSKeith M Wesolowski */
211*80c94ecdSKeith M Wesolowski
212*80c94ecdSKeith M Wesolowski return (SUCCESS);
213*80c94ecdSKeith M Wesolowski }
214*80c94ecdSKeith M Wesolowski
215*80c94ecdSKeith M Wesolowski /*
216*80c94ecdSKeith M Wesolowski * Function : cpqary3_ioctl_bmic_pass
217*80c94ecdSKeith M Wesolowski * Description : This routine will pass the BMIC commands to controller
218*80c94ecdSKeith M Wesolowski * Called By : cpqary3_ioctl
219*80c94ecdSKeith M Wesolowski * Parameters : ioctl_reqp - address of the parameter sent from the
220*80c94ecdSKeith M Wesolowski * application
221*80c94ecdSKeith M Wesolowski * cpqary3p - address of the PerController structure
222*80c94ecdSKeith M Wesolowski * mode - mode which comes directly from application
223*80c94ecdSKeith M Wesolowski * Return Values: EFAULT on Failure, 0 on SUCCESS
224*80c94ecdSKeith M Wesolowski */
225*80c94ecdSKeith M Wesolowski int32_t
cpqary3_ioctl_bmic_pass(uintptr_t ioctl_reqp,cpqary3_t * cpqary3p,int mode)226*80c94ecdSKeith M Wesolowski cpqary3_ioctl_bmic_pass(uintptr_t ioctl_reqp, cpqary3_t *cpqary3p, int mode)
227*80c94ecdSKeith M Wesolowski {
228*80c94ecdSKeith M Wesolowski cpqary3_ioctl_request_t *request;
229*80c94ecdSKeith M Wesolowski cpqary3_bmic_pass_t *bmic_pass;
230*80c94ecdSKeith M Wesolowski int32_t retval = SUCCESS;
231*80c94ecdSKeith M Wesolowski
232*80c94ecdSKeith M Wesolowski request = (cpqary3_ioctl_request_t *)
233*80c94ecdSKeith M Wesolowski MEM_ZALLOC(sizeof (cpqary3_ioctl_request_t));
234*80c94ecdSKeith M Wesolowski
235*80c94ecdSKeith M Wesolowski if (NULL == request)
236*80c94ecdSKeith M Wesolowski return (FAILURE);
237*80c94ecdSKeith M Wesolowski
238*80c94ecdSKeith M Wesolowski /*
239*80c94ecdSKeith M Wesolowski * First let us copyin the ioctl_reqp(user) buffer to request(kernel)
240*80c94ecdSKeith M Wesolowski * memory. This is very much recommended before we access any of the
241*80c94ecdSKeith M Wesolowski * fields.
242*80c94ecdSKeith M Wesolowski */
243*80c94ecdSKeith M Wesolowski
244*80c94ecdSKeith M Wesolowski if (ddi_copyin((void *)ioctl_reqp, (void *)request,
245*80c94ecdSKeith M Wesolowski sizeof (cpqary3_ioctl_request_t), mode)) {
246*80c94ecdSKeith M Wesolowski MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t));
247*80c94ecdSKeith M Wesolowski return (EFAULT);
248*80c94ecdSKeith M Wesolowski }
249*80c94ecdSKeith M Wesolowski
250*80c94ecdSKeith M Wesolowski bmic_pass = (cpqary3_bmic_pass_t *)
251*80c94ecdSKeith M Wesolowski MEM_ZALLOC(sizeof (cpqary3_bmic_pass_t));
252*80c94ecdSKeith M Wesolowski
253*80c94ecdSKeith M Wesolowski if (NULL == bmic_pass) {
254*80c94ecdSKeith M Wesolowski MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t));
255*80c94ecdSKeith M Wesolowski return (FAILURE);
256*80c94ecdSKeith M Wesolowski }
257*80c94ecdSKeith M Wesolowski
258*80c94ecdSKeith M Wesolowski /*
259*80c94ecdSKeith M Wesolowski * Copy in "cpqary3_bmic_pass_t" structure from argp member
260*80c94ecdSKeith M Wesolowski * of ioctl_reqp.
261*80c94ecdSKeith M Wesolowski */
262*80c94ecdSKeith M Wesolowski
263*80c94ecdSKeith M Wesolowski if (ddi_copyin((void *)(uintptr_t)request->argp, (void *)bmic_pass,
264*80c94ecdSKeith M Wesolowski sizeof (cpqary3_bmic_pass_t), mode)) {
265*80c94ecdSKeith M Wesolowski MEM_SFREE(bmic_pass, sizeof (cpqary3_bmic_pass_t));
266*80c94ecdSKeith M Wesolowski MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t));
267*80c94ecdSKeith M Wesolowski return (EFAULT);
268*80c94ecdSKeith M Wesolowski }
269*80c94ecdSKeith M Wesolowski
270*80c94ecdSKeith M Wesolowski /*
271*80c94ecdSKeith M Wesolowski * Get the free command list, fill in the bmic command and send it
272*80c94ecdSKeith M Wesolowski * to the controller. This will return 0 on success.
273*80c94ecdSKeith M Wesolowski */
274*80c94ecdSKeith M Wesolowski
275*80c94ecdSKeith M Wesolowski retval = cpqary3_ioctl_send_bmiccmd(cpqary3p, bmic_pass, mode);
276*80c94ecdSKeith M Wesolowski
277*80c94ecdSKeith M Wesolowski /*
278*80c94ecdSKeith M Wesolowski * Now copy the bmic_pass (kernel) to the user argp
279*80c94ecdSKeith M Wesolowski */
280*80c94ecdSKeith M Wesolowski
281*80c94ecdSKeith M Wesolowski if (ddi_copyout((void *) bmic_pass, (void *)(uintptr_t)request->argp,
282*80c94ecdSKeith M Wesolowski sizeof (cpqary3_bmic_pass_t), mode)) {
283*80c94ecdSKeith M Wesolowski MEM_SFREE(bmic_pass, sizeof (cpqary3_bmic_pass_t));
284*80c94ecdSKeith M Wesolowski MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t));
285*80c94ecdSKeith M Wesolowski retval = EFAULT; /* copyout failed */
286*80c94ecdSKeith M Wesolowski }
287*80c94ecdSKeith M Wesolowski
288*80c94ecdSKeith M Wesolowski /*
289*80c94ecdSKeith M Wesolowski * Now copy the request(kernel) to ioctl_reqp(user)
290*80c94ecdSKeith M Wesolowski */
291*80c94ecdSKeith M Wesolowski
292*80c94ecdSKeith M Wesolowski if (ddi_copyout((void *) request, (void *)ioctl_reqp,
293*80c94ecdSKeith M Wesolowski sizeof (cpqary3_ioctl_request_t), mode)) {
294*80c94ecdSKeith M Wesolowski MEM_SFREE(bmic_pass, sizeof (cpqary3_bmic_pass_t));
295*80c94ecdSKeith M Wesolowski MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t));
296*80c94ecdSKeith M Wesolowski retval = EFAULT;
297*80c94ecdSKeith M Wesolowski }
298*80c94ecdSKeith M Wesolowski
299*80c94ecdSKeith M Wesolowski MEM_SFREE(bmic_pass, sizeof (cpqary3_bmic_pass_t));
300*80c94ecdSKeith M Wesolowski MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t));
301*80c94ecdSKeith M Wesolowski
302*80c94ecdSKeith M Wesolowski return (retval);
303*80c94ecdSKeith M Wesolowski }
304*80c94ecdSKeith M Wesolowski
305*80c94ecdSKeith M Wesolowski /*
306*80c94ecdSKeith M Wesolowski * Function : cpqary3_ioctl_send_bmiccmd
307*80c94ecdSKeith M Wesolowski * Description : This routine will get the free command,
308*80c94ecdSKeith M Wesolowski * allocate memory and send it to controller.
309*80c94ecdSKeith M Wesolowski * Called By : cpqary3_ioctl_bmic_pass
310*80c94ecdSKeith M Wesolowski * Parameters : cpqary3_t - PerController structure
311*80c94ecdSKeith M Wesolowski * cpqary3_bmic_pass_t - bmic structure
312*80c94ecdSKeith M Wesolowski * mode - mode value sent from application
313*80c94ecdSKeith M Wesolowski * Return Values: 0 on success
314*80c94ecdSKeith M Wesolowski * FAILURE, EFAULT, ETIMEOUT based on the failure
315*80c94ecdSKeith M Wesolowski */
316*80c94ecdSKeith M Wesolowski
317*80c94ecdSKeith M Wesolowski uint32_t cpqary3_ioctl_wait_ms = 30000;
318*80c94ecdSKeith M Wesolowski
319*80c94ecdSKeith M Wesolowski static int32_t
cpqary3_ioctl_send_bmiccmd(cpqary3_t * cpqary3p,cpqary3_bmic_pass_t * bmic_pass,int mode)320*80c94ecdSKeith M Wesolowski cpqary3_ioctl_send_bmiccmd(cpqary3_t *cpqary3p,
321*80c94ecdSKeith M Wesolowski cpqary3_bmic_pass_t *bmic_pass, int mode)
322*80c94ecdSKeith M Wesolowski {
323*80c94ecdSKeith M Wesolowski cpqary3_cmdpvt_t *memp = NULL;
324*80c94ecdSKeith M Wesolowski CommandList_t *cmdlist = NULL;
325*80c94ecdSKeith M Wesolowski int8_t *databuf = NULL;
326*80c94ecdSKeith M Wesolowski uint8_t retval = 0;
327*80c94ecdSKeith M Wesolowski
328*80c94ecdSKeith M Wesolowski /* allocate a command with a dma buffer */
329*80c94ecdSKeith M Wesolowski memp = cpqary3_synccmd_alloc(cpqary3p, bmic_pass->buf_len);
330*80c94ecdSKeith M Wesolowski if (memp == NULL)
331*80c94ecdSKeith M Wesolowski return (FAILURE);
332*80c94ecdSKeith M Wesolowski
333*80c94ecdSKeith M Wesolowski /* Get the databuf when buf_len is greater than zero */
334*80c94ecdSKeith M Wesolowski if (bmic_pass->buf_len > 0) {
335*80c94ecdSKeith M Wesolowski databuf = memp->driverdata->sg;
336*80c94ecdSKeith M Wesolowski }
337*80c94ecdSKeith M Wesolowski
338*80c94ecdSKeith M Wesolowski cmdlist = memp->cmdlist_memaddr;
339*80c94ecdSKeith M Wesolowski
340*80c94ecdSKeith M Wesolowski /*
341*80c94ecdSKeith M Wesolowski * If io_direction is CPQARY3_SCSI_OUT, we have to copy user buffer
342*80c94ecdSKeith M Wesolowski * to databuf
343*80c94ecdSKeith M Wesolowski */
344*80c94ecdSKeith M Wesolowski
345*80c94ecdSKeith M Wesolowski if (bmic_pass->io_direction == CPQARY3_SCSI_OUT) {
346*80c94ecdSKeith M Wesolowski /* Do a copyin when buf_len is greater than zero */
347*80c94ecdSKeith M Wesolowski if (bmic_pass->buf_len > 0) {
348*80c94ecdSKeith M Wesolowski if (ddi_copyin((void*)(uintptr_t)(bmic_pass->buf),
349*80c94ecdSKeith M Wesolowski (void*)databuf, bmic_pass->buf_len, mode)) {
350*80c94ecdSKeith M Wesolowski cpqary3_synccmd_free(cpqary3p, memp);
351*80c94ecdSKeith M Wesolowski return (EFAULT);
352*80c94ecdSKeith M Wesolowski }
353*80c94ecdSKeith M Wesolowski }
354*80c94ecdSKeith M Wesolowski }
355*80c94ecdSKeith M Wesolowski
356*80c94ecdSKeith M Wesolowski /*
357*80c94ecdSKeith M Wesolowski * Now fill the command as per the BMIC
358*80c94ecdSKeith M Wesolowski */
359*80c94ecdSKeith M Wesolowski if (cpqary3p->bddef->bd_flags & SA_BD_SAS) {
360*80c94ecdSKeith M Wesolowski cpqary3_ioctl_fil_bmic_sas(cmdlist, bmic_pass);
361*80c94ecdSKeith M Wesolowski } else {
362*80c94ecdSKeith M Wesolowski cpqary3_ioctl_fil_bmic(cmdlist, bmic_pass);
363*80c94ecdSKeith M Wesolowski }
364*80c94ecdSKeith M Wesolowski
365*80c94ecdSKeith M Wesolowski
366*80c94ecdSKeith M Wesolowski /* PERF */
367*80c94ecdSKeith M Wesolowski
368*80c94ecdSKeith M Wesolowski memp->complete = cpqary3_synccmd_complete;
369*80c94ecdSKeith M Wesolowski
370*80c94ecdSKeith M Wesolowski /* PERF */
371*80c94ecdSKeith M Wesolowski
372*80c94ecdSKeith M Wesolowski /* send command to controller and wait for a reply */
373*80c94ecdSKeith M Wesolowski if (cpqary3_synccmd_send(cpqary3p, memp, cpqary3_ioctl_wait_ms,
374*80c94ecdSKeith M Wesolowski CPQARY3_SYNCCMD_SEND_WAITSIG) != 0) {
375*80c94ecdSKeith M Wesolowski cpqary3_synccmd_free(cpqary3p, memp);
376*80c94ecdSKeith M Wesolowski return (ETIMEDOUT);
377*80c94ecdSKeith M Wesolowski }
378*80c94ecdSKeith M Wesolowski
379*80c94ecdSKeith M Wesolowski /*
380*80c94ecdSKeith M Wesolowski * Now the command is completed and copy the buffers back
381*80c94ecdSKeith M Wesolowski * First copy the buffer databuf to bmic_pass.buf
382*80c94ecdSKeith M Wesolowski * which is used as a buffer before passing the command to the
383*80c94ecdSKeith M Wesolowski * controller.
384*80c94ecdSKeith M Wesolowski */
385*80c94ecdSKeith M Wesolowski
386*80c94ecdSKeith M Wesolowski if (bmic_pass->io_direction == CPQARY3_SCSI_IN) {
387*80c94ecdSKeith M Wesolowski /* Do a copyout when buf_len is greater than zero */
388*80c94ecdSKeith M Wesolowski if (bmic_pass->buf_len > 0) {
389*80c94ecdSKeith M Wesolowski if (ddi_copyout((void *)databuf,
390*80c94ecdSKeith M Wesolowski (void *)(uintptr_t)bmic_pass->buf,
391*80c94ecdSKeith M Wesolowski bmic_pass->buf_len, mode)) {
392*80c94ecdSKeith M Wesolowski retval = EFAULT;
393*80c94ecdSKeith M Wesolowski }
394*80c94ecdSKeith M Wesolowski }
395*80c94ecdSKeith M Wesolowski }
396*80c94ecdSKeith M Wesolowski
397*80c94ecdSKeith M Wesolowski /*
398*80c94ecdSKeith M Wesolowski * This is case where the command completes with error,
399*80c94ecdSKeith M Wesolowski * Then tag would have set its 1st(10) bit.
400*80c94ecdSKeith M Wesolowski */
401*80c94ecdSKeith M Wesolowski
402*80c94ecdSKeith M Wesolowski if (cmdlist->Header.Tag.drvinfo_n_err == CPQARY3_SYNCCMD_FAILURE) {
403*80c94ecdSKeith M Wesolowski bmic_pass->err_status = 1;
404*80c94ecdSKeith M Wesolowski bcopy((caddr_t)memp->errorinfop, &bmic_pass->err_info,
405*80c94ecdSKeith M Wesolowski sizeof (ErrorInfo_t));
406*80c94ecdSKeith M Wesolowski switch (memp->errorinfop->CommandStatus) {
407*80c94ecdSKeith M Wesolowski case CISS_CMD_DATA_OVERRUN :
408*80c94ecdSKeith M Wesolowski case CISS_CMD_DATA_UNDERRUN :
409*80c94ecdSKeith M Wesolowski case CISS_CMD_SUCCESS :
410*80c94ecdSKeith M Wesolowski case CISS_CMD_TARGET_STATUS :
411*80c94ecdSKeith M Wesolowski retval = SUCCESS;
412*80c94ecdSKeith M Wesolowski break;
413*80c94ecdSKeith M Wesolowski default :
414*80c94ecdSKeith M Wesolowski retval = EIO;
415*80c94ecdSKeith M Wesolowski break;
416*80c94ecdSKeith M Wesolowski }
417*80c94ecdSKeith M Wesolowski }
418*80c94ecdSKeith M Wesolowski
419*80c94ecdSKeith M Wesolowski cpqary3_synccmd_free(cpqary3p, memp);
420*80c94ecdSKeith M Wesolowski
421*80c94ecdSKeith M Wesolowski return (retval);
422*80c94ecdSKeith M Wesolowski }
423*80c94ecdSKeith M Wesolowski
424*80c94ecdSKeith M Wesolowski /*
425*80c94ecdSKeith M Wesolowski * Function : cpqary3_ioctl_fil_bmic
426*80c94ecdSKeith M Wesolowski * Description : This routine will fill the cmdlist with BMIC details
427*80c94ecdSKeith M Wesolowski * Called By : cpqary3_ioctl_send_bmiccmd
428*80c94ecdSKeith M Wesolowski * Parameters : cmdlist - command packet
429*80c94ecdSKeith M Wesolowski * bmic_pass - bmic structure
430*80c94ecdSKeith M Wesolowski * Return Values: void
431*80c94ecdSKeith M Wesolowski */
432*80c94ecdSKeith M Wesolowski static void
cpqary3_ioctl_fil_bmic(CommandList_t * cmdlist,cpqary3_bmic_pass_t * bmic_pass)433*80c94ecdSKeith M Wesolowski cpqary3_ioctl_fil_bmic(CommandList_t *cmdlist,
434*80c94ecdSKeith M Wesolowski cpqary3_bmic_pass_t *bmic_pass)
435*80c94ecdSKeith M Wesolowski {
436*80c94ecdSKeith M Wesolowski cmdlist->Header.SGTotal = 1;
437*80c94ecdSKeith M Wesolowski cmdlist->Header.SGList = 1;
438*80c94ecdSKeith M Wesolowski cmdlist->Request.CDBLen = bmic_pass->cmd_len;
439*80c94ecdSKeith M Wesolowski cmdlist->Request.Timeout = bmic_pass->timeout;
440*80c94ecdSKeith M Wesolowski cmdlist->Request.Type.Type = CISS_TYPE_CMD;
441*80c94ecdSKeith M Wesolowski cmdlist->Request.Type.Attribute = CISS_ATTR_HEADOFQUEUE;
442*80c94ecdSKeith M Wesolowski
443*80c94ecdSKeith M Wesolowski switch (bmic_pass->io_direction) {
444*80c94ecdSKeith M Wesolowski case CPQARY3_SCSI_OUT:
445*80c94ecdSKeith M Wesolowski cmdlist->Request.Type.Direction = CISS_XFER_WRITE;
446*80c94ecdSKeith M Wesolowski break;
447*80c94ecdSKeith M Wesolowski case CPQARY3_SCSI_IN:
448*80c94ecdSKeith M Wesolowski cmdlist->Request.Type.Direction = CISS_XFER_READ;
449*80c94ecdSKeith M Wesolowski break;
450*80c94ecdSKeith M Wesolowski case CPQARY3_NODATA_XFER:
451*80c94ecdSKeith M Wesolowski cmdlist->Request.Type.Direction = CISS_XFER_NONE;
452*80c94ecdSKeith M Wesolowski break;
453*80c94ecdSKeith M Wesolowski default:
454*80c94ecdSKeith M Wesolowski cmdlist->Request.Type.Direction = CISS_XFER_RSVD;
455*80c94ecdSKeith M Wesolowski break;
456*80c94ecdSKeith M Wesolowski }
457*80c94ecdSKeith M Wesolowski
458*80c94ecdSKeith M Wesolowski cmdlist ->Request.CDB[0] =
459*80c94ecdSKeith M Wesolowski (bmic_pass->io_direction == CPQARY3_SCSI_IN) ? 0x26: 0x27;
460*80c94ecdSKeith M Wesolowski cmdlist ->Request.CDB[1] = bmic_pass->unit_number; /* Unit Number */
461*80c94ecdSKeith M Wesolowski
462*80c94ecdSKeith M Wesolowski /*
463*80c94ecdSKeith M Wesolowski * BMIC Detail - bytes 2[MSB] to 5[LSB]
464*80c94ecdSKeith M Wesolowski */
465*80c94ecdSKeith M Wesolowski
466*80c94ecdSKeith M Wesolowski cmdlist->Request.CDB[2] = (bmic_pass->blk_number >> 24) & 0xff;
467*80c94ecdSKeith M Wesolowski cmdlist->Request.CDB[3] = (bmic_pass->blk_number >> 16) & 0xff;
468*80c94ecdSKeith M Wesolowski cmdlist->Request.CDB[4] = (bmic_pass->blk_number >> 8) & 0xff;
469*80c94ecdSKeith M Wesolowski cmdlist->Request.CDB[5] = bmic_pass->blk_number;
470*80c94ecdSKeith M Wesolowski
471*80c94ecdSKeith M Wesolowski cmdlist->Request.CDB[6] = bmic_pass->cmd; /* BMIC Command */
472*80c94ecdSKeith M Wesolowski
473*80c94ecdSKeith M Wesolowski /* Transfer Length - bytes 7[MSB] to 8[LSB] */
474*80c94ecdSKeith M Wesolowski
475*80c94ecdSKeith M Wesolowski cmdlist->Request.CDB[7] = (bmic_pass->buf_len >> 8) & 0xff;
476*80c94ecdSKeith M Wesolowski cmdlist->Request.CDB[8] = bmic_pass->buf_len & 0xff;
477*80c94ecdSKeith M Wesolowski cmdlist->Request.CDB[9] = 0x00; /* Reserved */
478*80c94ecdSKeith M Wesolowski
479*80c94ecdSKeith M Wesolowski /*
480*80c94ecdSKeith M Wesolowski * Copy the Lun address from the request
481*80c94ecdSKeith M Wesolowski */
482*80c94ecdSKeith M Wesolowski
483*80c94ecdSKeith M Wesolowski bcopy(&bmic_pass->lun_addr[0], &(cmdlist->Header.LUN),
484*80c94ecdSKeith M Wesolowski sizeof (LUNAddr_t));
485*80c94ecdSKeith M Wesolowski cmdlist->SG[0].Len = bmic_pass->buf_len;
486*80c94ecdSKeith M Wesolowski }
487*80c94ecdSKeith M Wesolowski
488*80c94ecdSKeith M Wesolowski /*
489*80c94ecdSKeith M Wesolowski * Function : cpqary3_ioctl_scsi_pass
490*80c94ecdSKeith M Wesolowski * Description : This routine will pass the SCSI commands to controller
491*80c94ecdSKeith M Wesolowski * Called By : cpqary3_ioctl
492*80c94ecdSKeith M Wesolowski * Parameters : ioctl_reqp - address of the parameter sent
493*80c94ecdSKeith M Wesolowski * from the application
494*80c94ecdSKeith M Wesolowski * cpqary3p - Addess of the percontroller stucture
495*80c94ecdSKeith M Wesolowski * mode - mode which comes directly from application
496*80c94ecdSKeith M Wesolowski * Return Values: EFAULT on Failure, 0 on SUCCESS
497*80c94ecdSKeith M Wesolowski */
498*80c94ecdSKeith M Wesolowski int32_t
cpqary3_ioctl_scsi_pass(uintptr_t ioctl_reqp,cpqary3_t * cpqary3p,int mode)499*80c94ecdSKeith M Wesolowski cpqary3_ioctl_scsi_pass(uintptr_t ioctl_reqp, cpqary3_t *cpqary3p, int mode)
500*80c94ecdSKeith M Wesolowski {
501*80c94ecdSKeith M Wesolowski cpqary3_ioctl_request_t *request;
502*80c94ecdSKeith M Wesolowski cpqary3_scsi_pass_t *scsi_pass;
503*80c94ecdSKeith M Wesolowski int32_t retval = SUCCESS;
504*80c94ecdSKeith M Wesolowski
505*80c94ecdSKeith M Wesolowski request = (cpqary3_ioctl_request_t *)
506*80c94ecdSKeith M Wesolowski MEM_ZALLOC(sizeof (cpqary3_ioctl_request_t));
507*80c94ecdSKeith M Wesolowski
508*80c94ecdSKeith M Wesolowski if (NULL == request)
509*80c94ecdSKeith M Wesolowski return (FAILURE);
510*80c94ecdSKeith M Wesolowski
511*80c94ecdSKeith M Wesolowski /*
512*80c94ecdSKeith M Wesolowski * First let us copyin the ioctl_reqp(user) buffer to request(kernel)
513*80c94ecdSKeith M Wesolowski * memory. * This is very much recommended before we access any of
514*80c94ecdSKeith M Wesolowski * the fields.
515*80c94ecdSKeith M Wesolowski */
516*80c94ecdSKeith M Wesolowski
517*80c94ecdSKeith M Wesolowski if (ddi_copyin((void *)ioctl_reqp, (void *)request,
518*80c94ecdSKeith M Wesolowski sizeof (cpqary3_ioctl_request_t), mode)) {
519*80c94ecdSKeith M Wesolowski MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t));
520*80c94ecdSKeith M Wesolowski return (EFAULT);
521*80c94ecdSKeith M Wesolowski }
522*80c94ecdSKeith M Wesolowski
523*80c94ecdSKeith M Wesolowski scsi_pass = (cpqary3_scsi_pass_t *)
524*80c94ecdSKeith M Wesolowski MEM_ZALLOC(sizeof (cpqary3_scsi_pass_t));
525*80c94ecdSKeith M Wesolowski
526*80c94ecdSKeith M Wesolowski if (NULL == scsi_pass) {
527*80c94ecdSKeith M Wesolowski MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t));
528*80c94ecdSKeith M Wesolowski return (FAILURE);
529*80c94ecdSKeith M Wesolowski }
530*80c94ecdSKeith M Wesolowski
531*80c94ecdSKeith M Wesolowski /*
532*80c94ecdSKeith M Wesolowski * Copy in "cpqary3_scsi_pass_t" structure from argp member
533*80c94ecdSKeith M Wesolowski * of ioctl_reqp.
534*80c94ecdSKeith M Wesolowski */
535*80c94ecdSKeith M Wesolowski
536*80c94ecdSKeith M Wesolowski if (ddi_copyin((void *)(uintptr_t)request->argp, (void *)scsi_pass,
537*80c94ecdSKeith M Wesolowski sizeof (cpqary3_scsi_pass_t), mode)) {
538*80c94ecdSKeith M Wesolowski MEM_SFREE(scsi_pass, sizeof (cpqary3_scsi_pass_t));
539*80c94ecdSKeith M Wesolowski MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t));
540*80c94ecdSKeith M Wesolowski return (EFAULT);
541*80c94ecdSKeith M Wesolowski }
542*80c94ecdSKeith M Wesolowski
543*80c94ecdSKeith M Wesolowski /*
544*80c94ecdSKeith M Wesolowski * Get the free command list, fill in the scsi command and send it
545*80c94ecdSKeith M Wesolowski * to the controller. This will return 0 on success.
546*80c94ecdSKeith M Wesolowski */
547*80c94ecdSKeith M Wesolowski
548*80c94ecdSKeith M Wesolowski retval = cpqary3_ioctl_send_scsicmd(cpqary3p, scsi_pass, mode);
549*80c94ecdSKeith M Wesolowski
550*80c94ecdSKeith M Wesolowski /*
551*80c94ecdSKeith M Wesolowski * Now copy the scsi_pass (kernel) to the user argp
552*80c94ecdSKeith M Wesolowski */
553*80c94ecdSKeith M Wesolowski
554*80c94ecdSKeith M Wesolowski if (ddi_copyout((void *)scsi_pass, (void *)(uintptr_t)request->argp,
555*80c94ecdSKeith M Wesolowski sizeof (cpqary3_scsi_pass_t), mode)) {
556*80c94ecdSKeith M Wesolowski MEM_SFREE(scsi_pass, sizeof (cpqary3_scsi_pass_t));
557*80c94ecdSKeith M Wesolowski MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t));
558*80c94ecdSKeith M Wesolowski retval = EFAULT; /* copyout failed */
559*80c94ecdSKeith M Wesolowski }
560*80c94ecdSKeith M Wesolowski
561*80c94ecdSKeith M Wesolowski /*
562*80c94ecdSKeith M Wesolowski * Now copy the request(kernel) to ioctl_reqp(user)
563*80c94ecdSKeith M Wesolowski */
564*80c94ecdSKeith M Wesolowski
565*80c94ecdSKeith M Wesolowski if (ddi_copyout((void *)request, (void *)ioctl_reqp,
566*80c94ecdSKeith M Wesolowski sizeof (cpqary3_ioctl_request_t), mode)) {
567*80c94ecdSKeith M Wesolowski MEM_SFREE(scsi_pass, sizeof (cpqary3_scsi_pass_t));
568*80c94ecdSKeith M Wesolowski MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t));
569*80c94ecdSKeith M Wesolowski retval = EFAULT;
570*80c94ecdSKeith M Wesolowski }
571*80c94ecdSKeith M Wesolowski
572*80c94ecdSKeith M Wesolowski MEM_SFREE(scsi_pass, sizeof (cpqary3_scsi_pass_t));
573*80c94ecdSKeith M Wesolowski MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t));
574*80c94ecdSKeith M Wesolowski
575*80c94ecdSKeith M Wesolowski return (retval);
576*80c94ecdSKeith M Wesolowski }
577*80c94ecdSKeith M Wesolowski
578*80c94ecdSKeith M Wesolowski /*
579*80c94ecdSKeith M Wesolowski * Function : cpqary3_ioctl_send_scsiccmd
580*80c94ecdSKeith M Wesolowski * Description : This routine will pass the SCSI commands to controller
581*80c94ecdSKeith M Wesolowski * Called By : cpqary3_ioctl_scsi_pass
582*80c94ecdSKeith M Wesolowski * Parameters : cpqary3_t - PerController structure,
583*80c94ecdSKeith M Wesolowski * cpqary3_scsi_pass_t - scsi parameter
584*80c94ecdSKeith M Wesolowski * mode - sent from the application
585*80c94ecdSKeith M Wesolowski * Return Values: 0 on success
586*80c94ecdSKeith M Wesolowski * FAILURE, EFAULT, ETIMEOUT based on the failure
587*80c94ecdSKeith M Wesolowski */
588*80c94ecdSKeith M Wesolowski static int32_t
cpqary3_ioctl_send_scsicmd(cpqary3_t * cpqary3p,cpqary3_scsi_pass_t * scsi_pass,int mode)589*80c94ecdSKeith M Wesolowski cpqary3_ioctl_send_scsicmd(cpqary3_t *cpqary3p,
590*80c94ecdSKeith M Wesolowski cpqary3_scsi_pass_t *scsi_pass, int mode)
591*80c94ecdSKeith M Wesolowski {
592*80c94ecdSKeith M Wesolowski cpqary3_cmdpvt_t *memp = NULL;
593*80c94ecdSKeith M Wesolowski CommandList_t *cmdlist = NULL;
594*80c94ecdSKeith M Wesolowski int8_t *databuf = NULL;
595*80c94ecdSKeith M Wesolowski uint8_t retval = 0;
596*80c94ecdSKeith M Wesolowski NoeBuffer *evt;
597*80c94ecdSKeith M Wesolowski uint16_t drive = 0;
598*80c94ecdSKeith M Wesolowski
599*80c94ecdSKeith M Wesolowski /* allocate a command with a dma buffer */
600*80c94ecdSKeith M Wesolowski memp = cpqary3_synccmd_alloc(cpqary3p, scsi_pass->buf_len);
601*80c94ecdSKeith M Wesolowski if (memp == NULL)
602*80c94ecdSKeith M Wesolowski return (FAILURE);
603*80c94ecdSKeith M Wesolowski
604*80c94ecdSKeith M Wesolowski /* Get the databuf when buf_len is greater than zero */
605*80c94ecdSKeith M Wesolowski if (scsi_pass->buf_len > 0) {
606*80c94ecdSKeith M Wesolowski databuf = memp->driverdata->sg;
607*80c94ecdSKeith M Wesolowski }
608*80c94ecdSKeith M Wesolowski
609*80c94ecdSKeith M Wesolowski cmdlist = memp->cmdlist_memaddr;
610*80c94ecdSKeith M Wesolowski
611*80c94ecdSKeith M Wesolowski if (scsi_pass->io_direction == CPQARY3_SCSI_OUT) {
612*80c94ecdSKeith M Wesolowski /* Do a copyin when buf_len is greater than zero */
613*80c94ecdSKeith M Wesolowski if (scsi_pass->buf_len > 0) {
614*80c94ecdSKeith M Wesolowski if (ddi_copyin((void*)(uintptr_t)(scsi_pass->buf),
615*80c94ecdSKeith M Wesolowski (void*)databuf, scsi_pass->buf_len, mode)) {
616*80c94ecdSKeith M Wesolowski cpqary3_synccmd_free(cpqary3p, memp);
617*80c94ecdSKeith M Wesolowski return (EFAULT);
618*80c94ecdSKeith M Wesolowski }
619*80c94ecdSKeith M Wesolowski }
620*80c94ecdSKeith M Wesolowski }
621*80c94ecdSKeith M Wesolowski
622*80c94ecdSKeith M Wesolowski /*
623*80c94ecdSKeith M Wesolowski * Fill the scsi command
624*80c94ecdSKeith M Wesolowski */
625*80c94ecdSKeith M Wesolowski cpqary3_ioctl_fil_scsi(cmdlist, scsi_pass);
626*80c94ecdSKeith M Wesolowski
627*80c94ecdSKeith M Wesolowski /* PERF */
628*80c94ecdSKeith M Wesolowski memp->complete = cpqary3_synccmd_complete;
629*80c94ecdSKeith M Wesolowski /* PERF */
630*80c94ecdSKeith M Wesolowski
631*80c94ecdSKeith M Wesolowski /* send command to controller and wait for a reply */
632*80c94ecdSKeith M Wesolowski if (cpqary3_synccmd_send(cpqary3p, memp, cpqary3_ioctl_wait_ms,
633*80c94ecdSKeith M Wesolowski CPQARY3_SYNCCMD_SEND_WAITSIG) != 0) {
634*80c94ecdSKeith M Wesolowski cpqary3_synccmd_free(cpqary3p, memp);
635*80c94ecdSKeith M Wesolowski return (ETIMEDOUT);
636*80c94ecdSKeith M Wesolowski }
637*80c94ecdSKeith M Wesolowski
638*80c94ecdSKeith M Wesolowski /*
639*80c94ecdSKeith M Wesolowski * If the command sent is NOE
640*80c94ecdSKeith M Wesolowski * if the event class is CLASS_LOGICAL_DRIVE
641*80c94ecdSKeith M Wesolowski * if the subcalls code is zero and if detail change is zero
642*80c94ecdSKeith M Wesolowski * if the event specific data[3] is either 1 or 2 ie., if
643*80c94ecdSKeith M Wesolowski * if the logical drive is failed set the target type to
644*80c94ecdSKeith M Wesolowski * CPQARY3_TARGET_NONE
645*80c94ecdSKeith M Wesolowski */
646*80c94ecdSKeith M Wesolowski
647*80c94ecdSKeith M Wesolowski /* NOE */
648*80c94ecdSKeith M Wesolowski if (cpqary3p->noe_support == 0 &&
649*80c94ecdSKeith M Wesolowski cmdlist->Request.CDB[0] == 0x26 &&
650*80c94ecdSKeith M Wesolowski cmdlist->Request.CDB[6] == BMIC_NOTIFY_ON_EVENT) {
651*80c94ecdSKeith M Wesolowski
652*80c94ecdSKeith M Wesolowski evt = (NoeBuffer*)MEM2DRVPVT(memp)->sg;
653*80c94ecdSKeith M Wesolowski
654*80c94ecdSKeith M Wesolowski if (evt->event_class_code == CLASS_LOGICAL_DRIVE &&
655*80c94ecdSKeith M Wesolowski evt->event_subclass_code == SUB_CLASS_STATUS &&
656*80c94ecdSKeith M Wesolowski evt->event_detail_code == DETAIL_CHANGE &&
657*80c94ecdSKeith M Wesolowski evt->event_specific_data[3] == 1) {
658*80c94ecdSKeith M Wesolowski /* LINTED: alignment */
659*80c94ecdSKeith M Wesolowski drive = *(uint16_t *)(&evt->event_specific_data[0]);
660*80c94ecdSKeith M Wesolowski drive = ((drive < CTLR_SCSI_ID) ?
661*80c94ecdSKeith M Wesolowski drive : drive + CPQARY3_TGT_ALIGNMENT);
662*80c94ecdSKeith M Wesolowski
663*80c94ecdSKeith M Wesolowski if (cpqary3p && cpqary3p->cpqary3_tgtp[drive]) {
664*80c94ecdSKeith M Wesolowski cpqary3p->cpqary3_tgtp[drive]->type =
665*80c94ecdSKeith M Wesolowski CPQARY3_TARGET_NONE;
666*80c94ecdSKeith M Wesolowski }
667*80c94ecdSKeith M Wesolowski }
668*80c94ecdSKeith M Wesolowski }
669*80c94ecdSKeith M Wesolowski
670*80c94ecdSKeith M Wesolowski /*
671*80c94ecdSKeith M Wesolowski * Now the command is completed and copy the buffers back
672*80c94ecdSKeith M Wesolowski * First copy the buffer databuf to scsi_pass->buf
673*80c94ecdSKeith M Wesolowski * which is used as a buffer before passing the command to the
674*80c94ecdSKeith M Wesolowski * controller.
675*80c94ecdSKeith M Wesolowski */
676*80c94ecdSKeith M Wesolowski
677*80c94ecdSKeith M Wesolowski if (scsi_pass->io_direction == CPQARY3_SCSI_IN) {
678*80c94ecdSKeith M Wesolowski if (scsi_pass->buf_len > 0) {
679*80c94ecdSKeith M Wesolowski if (ddi_copyout((void *)databuf,
680*80c94ecdSKeith M Wesolowski (void *)(uintptr_t)scsi_pass->buf,
681*80c94ecdSKeith M Wesolowski scsi_pass->buf_len, mode)) {
682*80c94ecdSKeith M Wesolowski retval = EFAULT;
683*80c94ecdSKeith M Wesolowski }
684*80c94ecdSKeith M Wesolowski }
685*80c94ecdSKeith M Wesolowski }
686*80c94ecdSKeith M Wesolowski
687*80c94ecdSKeith M Wesolowski /*
688*80c94ecdSKeith M Wesolowski * This is case where the command completes with error,
689*80c94ecdSKeith M Wesolowski * Then tag would have set its 1st(10) bit.
690*80c94ecdSKeith M Wesolowski */
691*80c94ecdSKeith M Wesolowski
692*80c94ecdSKeith M Wesolowski if (cmdlist->Header.Tag.drvinfo_n_err == CPQARY3_SYNCCMD_FAILURE) {
693*80c94ecdSKeith M Wesolowski scsi_pass->err_status = 1;
694*80c94ecdSKeith M Wesolowski bcopy((caddr_t)memp->errorinfop, &scsi_pass->err_info,
695*80c94ecdSKeith M Wesolowski sizeof (ErrorInfo_t));
696*80c94ecdSKeith M Wesolowski switch (memp->errorinfop->CommandStatus) {
697*80c94ecdSKeith M Wesolowski case CISS_CMD_DATA_OVERRUN:
698*80c94ecdSKeith M Wesolowski case CISS_CMD_DATA_UNDERRUN:
699*80c94ecdSKeith M Wesolowski case CISS_CMD_SUCCESS:
700*80c94ecdSKeith M Wesolowski case CISS_CMD_TARGET_STATUS:
701*80c94ecdSKeith M Wesolowski retval = SUCCESS;
702*80c94ecdSKeith M Wesolowski break;
703*80c94ecdSKeith M Wesolowski default:
704*80c94ecdSKeith M Wesolowski retval = EIO;
705*80c94ecdSKeith M Wesolowski break;
706*80c94ecdSKeith M Wesolowski }
707*80c94ecdSKeith M Wesolowski }
708*80c94ecdSKeith M Wesolowski
709*80c94ecdSKeith M Wesolowski cpqary3_synccmd_free(cpqary3p, memp);
710*80c94ecdSKeith M Wesolowski
711*80c94ecdSKeith M Wesolowski return (retval);
712*80c94ecdSKeith M Wesolowski }
713*80c94ecdSKeith M Wesolowski
714*80c94ecdSKeith M Wesolowski /*
715*80c94ecdSKeith M Wesolowski * Function : cpqary3_ioctl_fil_scsi_
716*80c94ecdSKeith M Wesolowski * Description : This routine will fill the cmdlist with SCSI CDB
717*80c94ecdSKeith M Wesolowski * Called By : cpqary3_ioctl_send_scsicmd
718*80c94ecdSKeith M Wesolowski * Parameters : cmdlist - command packet
719*80c94ecdSKeith M Wesolowski * cpqary3_scsi_pass_t - scsi parameter
720*80c94ecdSKeith M Wesolowski * Return Values: void
721*80c94ecdSKeith M Wesolowski */
722*80c94ecdSKeith M Wesolowski static void
cpqary3_ioctl_fil_scsi(CommandList_t * cmdlist,cpqary3_scsi_pass_t * scsi_pass)723*80c94ecdSKeith M Wesolowski cpqary3_ioctl_fil_scsi(CommandList_t *cmdlist,
724*80c94ecdSKeith M Wesolowski cpqary3_scsi_pass_t *scsi_pass)
725*80c94ecdSKeith M Wesolowski {
726*80c94ecdSKeith M Wesolowski cmdlist->Header.SGTotal = 1;
727*80c94ecdSKeith M Wesolowski cmdlist->Header.SGList = 1;
728*80c94ecdSKeith M Wesolowski cmdlist->Request.CDBLen = scsi_pass->cdb_len;
729*80c94ecdSKeith M Wesolowski cmdlist->Request.Timeout = scsi_pass->timeout;
730*80c94ecdSKeith M Wesolowski cmdlist->Request.Type.Type = CISS_TYPE_CMD;
731*80c94ecdSKeith M Wesolowski cmdlist->Request.Type.Attribute = CISS_ATTR_HEADOFQUEUE;
732*80c94ecdSKeith M Wesolowski
733*80c94ecdSKeith M Wesolowski switch (scsi_pass->io_direction) {
734*80c94ecdSKeith M Wesolowski case CPQARY3_SCSI_OUT:
735*80c94ecdSKeith M Wesolowski cmdlist->Request.Type.Direction = CISS_XFER_WRITE;
736*80c94ecdSKeith M Wesolowski break;
737*80c94ecdSKeith M Wesolowski case CPQARY3_SCSI_IN:
738*80c94ecdSKeith M Wesolowski cmdlist->Request.Type.Direction = CISS_XFER_READ;
739*80c94ecdSKeith M Wesolowski break;
740*80c94ecdSKeith M Wesolowski case CPQARY3_NODATA_XFER:
741*80c94ecdSKeith M Wesolowski cmdlist->Request.Type.Direction = CISS_XFER_NONE;
742*80c94ecdSKeith M Wesolowski break;
743*80c94ecdSKeith M Wesolowski default:
744*80c94ecdSKeith M Wesolowski cmdlist->Request.Type.Direction = CISS_XFER_RSVD;
745*80c94ecdSKeith M Wesolowski break;
746*80c94ecdSKeith M Wesolowski }
747*80c94ecdSKeith M Wesolowski
748*80c94ecdSKeith M Wesolowski /*
749*80c94ecdSKeith M Wesolowski * Copy the SCSI CDB as is
750*80c94ecdSKeith M Wesolowski */
751*80c94ecdSKeith M Wesolowski
752*80c94ecdSKeith M Wesolowski bcopy(&scsi_pass->cdb[0], &cmdlist->Request.CDB[0],
753*80c94ecdSKeith M Wesolowski scsi_pass->cdb_len);
754*80c94ecdSKeith M Wesolowski
755*80c94ecdSKeith M Wesolowski /*
756*80c94ecdSKeith M Wesolowski * Copy the Lun address from the request
757*80c94ecdSKeith M Wesolowski */
758*80c94ecdSKeith M Wesolowski
759*80c94ecdSKeith M Wesolowski bcopy(&scsi_pass->lun_addr[0], &(cmdlist->Header.LUN),
760*80c94ecdSKeith M Wesolowski sizeof (LUNAddr_t));
761*80c94ecdSKeith M Wesolowski
762*80c94ecdSKeith M Wesolowski cmdlist->SG[0].Len = scsi_pass->buf_len;
763*80c94ecdSKeith M Wesolowski }
764*80c94ecdSKeith M Wesolowski
765*80c94ecdSKeith M Wesolowski /*
766*80c94ecdSKeith M Wesolowski * Function : cpqary3_ioctl_fil_bmic_sas
767*80c94ecdSKeith M Wesolowski * Description : This routine will fill the cmdlist with BMIC details
768*80c94ecdSKeith M Wesolowski * Called By : cpqary3_ioctl_send_bmiccmd
769*80c94ecdSKeith M Wesolowski * Parameters : cmdlist - command packet
770*80c94ecdSKeith M Wesolowski * bmic_pass - bmic structure
771*80c94ecdSKeith M Wesolowski * Return Values: void
772*80c94ecdSKeith M Wesolowski */
773*80c94ecdSKeith M Wesolowski static void
cpqary3_ioctl_fil_bmic_sas(CommandList_t * cmdlist,cpqary3_bmic_pass_t * bmic_pass)774*80c94ecdSKeith M Wesolowski cpqary3_ioctl_fil_bmic_sas(CommandList_t *cmdlist,
775*80c94ecdSKeith M Wesolowski cpqary3_bmic_pass_t *bmic_pass)
776*80c94ecdSKeith M Wesolowski {
777*80c94ecdSKeith M Wesolowski cmdlist->Header.SGTotal = 1;
778*80c94ecdSKeith M Wesolowski cmdlist->Header.SGList = 1;
779*80c94ecdSKeith M Wesolowski cmdlist->Request.CDBLen = bmic_pass->cmd_len;
780*80c94ecdSKeith M Wesolowski cmdlist->Request.Timeout = bmic_pass->timeout;
781*80c94ecdSKeith M Wesolowski cmdlist->Request.Type.Type = CISS_TYPE_CMD;
782*80c94ecdSKeith M Wesolowski cmdlist->Request.Type.Attribute = CISS_ATTR_HEADOFQUEUE;
783*80c94ecdSKeith M Wesolowski
784*80c94ecdSKeith M Wesolowski switch (bmic_pass->io_direction) {
785*80c94ecdSKeith M Wesolowski case CPQARY3_SCSI_OUT:
786*80c94ecdSKeith M Wesolowski cmdlist->Request.Type.Direction = CISS_XFER_WRITE;
787*80c94ecdSKeith M Wesolowski break;
788*80c94ecdSKeith M Wesolowski case CPQARY3_SCSI_IN:
789*80c94ecdSKeith M Wesolowski cmdlist->Request.Type.Direction = CISS_XFER_READ;
790*80c94ecdSKeith M Wesolowski break;
791*80c94ecdSKeith M Wesolowski case CPQARY3_NODATA_XFER:
792*80c94ecdSKeith M Wesolowski cmdlist->Request.Type.Direction = CISS_XFER_NONE;
793*80c94ecdSKeith M Wesolowski break;
794*80c94ecdSKeith M Wesolowski default:
795*80c94ecdSKeith M Wesolowski cmdlist->Request.Type.Direction = CISS_XFER_RSVD;
796*80c94ecdSKeith M Wesolowski break;
797*80c94ecdSKeith M Wesolowski }
798*80c94ecdSKeith M Wesolowski
799*80c94ecdSKeith M Wesolowski cmdlist->Request.CDB[0] =
800*80c94ecdSKeith M Wesolowski (bmic_pass->io_direction == CPQARY3_SCSI_IN) ? 0x26: 0x27;
801*80c94ecdSKeith M Wesolowski cmdlist->Request.CDB[1] = bmic_pass->unit_number; /* Unit Number */
802*80c94ecdSKeith M Wesolowski
803*80c94ecdSKeith M Wesolowski /*
804*80c94ecdSKeith M Wesolowski * BMIC Detail - bytes 2[MSB] to 5[LSB]
805*80c94ecdSKeith M Wesolowski */
806*80c94ecdSKeith M Wesolowski
807*80c94ecdSKeith M Wesolowski cmdlist->Request.CDB[2] = (bmic_pass->blk_number >> 24) & 0xff;
808*80c94ecdSKeith M Wesolowski cmdlist->Request.CDB[3] = (bmic_pass->blk_number >> 16) & 0xff;
809*80c94ecdSKeith M Wesolowski cmdlist->Request.CDB[4] = (bmic_pass->blk_number >> 8) & 0xff;
810*80c94ecdSKeith M Wesolowski cmdlist->Request.CDB[5] = bmic_pass->blk_number;
811*80c94ecdSKeith M Wesolowski
812*80c94ecdSKeith M Wesolowski cmdlist->Request.CDB[6] = bmic_pass->cmd; /* BMIC Command */
813*80c94ecdSKeith M Wesolowski
814*80c94ecdSKeith M Wesolowski /* Transfer Length - bytes 7[MSB] to 8[LSB] */
815*80c94ecdSKeith M Wesolowski
816*80c94ecdSKeith M Wesolowski cmdlist->Request.CDB[7] = (bmic_pass->buf_len >> 8) & 0xff;
817*80c94ecdSKeith M Wesolowski cmdlist->Request.CDB[8] = bmic_pass->buf_len & 0xff;
818*80c94ecdSKeith M Wesolowski cmdlist->Request.CDB[9] = 0x00; /* Reserved */
819*80c94ecdSKeith M Wesolowski
820*80c94ecdSKeith M Wesolowski /* Update CDB[2] = LSB bmix_index and CDB[9] = MSB bmic_index */
821*80c94ecdSKeith M Wesolowski switch (bmic_pass->cmd) {
822*80c94ecdSKeith M Wesolowski case HPSAS_ID_PHYSICAL_DRIVE:
823*80c94ecdSKeith M Wesolowski case HPSAS_TAPE_INQUIRY:
824*80c94ecdSKeith M Wesolowski case HPSAS_SENSE_MP_STAT:
825*80c94ecdSKeith M Wesolowski case HPSAS_SET_MP_THRESHOLD:
826*80c94ecdSKeith M Wesolowski case HPSAS_MP_PARAM_CONTROL:
827*80c94ecdSKeith M Wesolowski case HPSAS_SENSE_DRV_ERR_LOG:
828*80c94ecdSKeith M Wesolowski case HPSAS_SET_MP_VALUE:
829*80c94ecdSKeith M Wesolowski cmdlist -> Request.CDB[2] = bmic_pass->bmic_index & 0xff;
830*80c94ecdSKeith M Wesolowski cmdlist -> Request.CDB[9] = (bmic_pass->bmic_index >>8) & 0xff;
831*80c94ecdSKeith M Wesolowski break;
832*80c94ecdSKeith M Wesolowski
833*80c94ecdSKeith M Wesolowski case HPSAS_ID_LOG_DRIVE:
834*80c94ecdSKeith M Wesolowski case HPSAS_SENSE_LOG_DRIVE:
835*80c94ecdSKeith M Wesolowski case HPSAS_READ:
836*80c94ecdSKeith M Wesolowski case HPSAS_WRITE:
837*80c94ecdSKeith M Wesolowski case HPSAS_WRITE_THROUGH:
838*80c94ecdSKeith M Wesolowski case HPSAS_SENSE_CONFIG:
839*80c94ecdSKeith M Wesolowski case HPSAS_SET_CONFIG:
840*80c94ecdSKeith M Wesolowski case HPSAS_BYPASS_VOL_STATE:
841*80c94ecdSKeith M Wesolowski case HPSAS_CHANGE_CONFIG:
842*80c94ecdSKeith M Wesolowski case HPSAS_SENSE_ORIG_CONFIG:
843*80c94ecdSKeith M Wesolowski case HPSAS_LABEL_LOG_DRIVE:
844*80c94ecdSKeith M Wesolowski /* Unit Number MSB */
845*80c94ecdSKeith M Wesolowski cmdlist->Request.CDB[9] = (bmic_pass->unit_number >> 8) & 0xff;
846*80c94ecdSKeith M Wesolowski break;
847*80c94ecdSKeith M Wesolowski
848*80c94ecdSKeith M Wesolowski default:
849*80c94ecdSKeith M Wesolowski break;
850*80c94ecdSKeith M Wesolowski }
851*80c94ecdSKeith M Wesolowski
852*80c94ecdSKeith M Wesolowski
853*80c94ecdSKeith M Wesolowski /*
854*80c94ecdSKeith M Wesolowski * Copy the Lun address from the request
855*80c94ecdSKeith M Wesolowski */
856*80c94ecdSKeith M Wesolowski
857*80c94ecdSKeith M Wesolowski bcopy(&bmic_pass->lun_addr[0], &(cmdlist->Header.LUN),
858*80c94ecdSKeith M Wesolowski sizeof (LUNAddr_t));
859*80c94ecdSKeith M Wesolowski
860*80c94ecdSKeith M Wesolowski cmdlist->SG[0].Len = bmic_pass->buf_len;
861*80c94ecdSKeith M Wesolowski }
862