1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /* Copyright 2010 QLogic Corporation */
23
24 /*
25 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
26 */
27
28 #pragma ident "Copyright 2010 QLogic Corporation; ql_xioctl.c"
29
30 /*
31 * ISP2xxx Solaris Fibre Channel Adapter (FCA) driver source file.
32 *
33 * ***********************************************************************
34 * * **
35 * * NOTICE **
36 * * COPYRIGHT (C) 1996-2010 QLOGIC CORPORATION **
37 * * ALL RIGHTS RESERVED **
38 * * **
39 * ***********************************************************************
40 *
41 */
42
43 #include <ql_apps.h>
44 #include <ql_api.h>
45 #include <ql_debug.h>
46 #include <ql_init.h>
47 #include <ql_iocb.h>
48 #include <ql_ioctl.h>
49 #include <ql_mbx.h>
50 #include <ql_xioctl.h>
51
52 /*
53 * Local data
54 */
55
56 /*
57 * Local prototypes
58 */
59 static int ql_sdm_ioctl(ql_adapter_state_t *, int, void *, int);
60 static int ql_sdm_setup(ql_adapter_state_t *, EXT_IOCTL **, void *, int,
61 boolean_t (*)(EXT_IOCTL *));
62 static boolean_t ql_validate_signature(EXT_IOCTL *);
63 static int ql_sdm_return(ql_adapter_state_t *, EXT_IOCTL *, void *, int);
64 static void ql_query(ql_adapter_state_t *, EXT_IOCTL *, int);
65 static void ql_qry_hba_node(ql_adapter_state_t *, EXT_IOCTL *, int);
66 static void ql_qry_hba_port(ql_adapter_state_t *, EXT_IOCTL *, int);
67 static void ql_qry_disc_port(ql_adapter_state_t *, EXT_IOCTL *, int);
68 static void ql_qry_disc_tgt(ql_adapter_state_t *, EXT_IOCTL *, int);
69 static void ql_qry_fw(ql_adapter_state_t *, EXT_IOCTL *, int);
70 static void ql_qry_chip(ql_adapter_state_t *, EXT_IOCTL *, int);
71 static void ql_qry_driver(ql_adapter_state_t *, EXT_IOCTL *, int);
72 static void ql_fcct(ql_adapter_state_t *, EXT_IOCTL *, int);
73 static void ql_aen_reg(ql_adapter_state_t *, EXT_IOCTL *, int);
74 static void ql_aen_get(ql_adapter_state_t *, EXT_IOCTL *, int);
75 static void ql_scsi_passthru(ql_adapter_state_t *, EXT_IOCTL *, int);
76 static void ql_wwpn_to_scsiaddr(ql_adapter_state_t *, EXT_IOCTL *, int);
77 static void ql_host_idx(ql_adapter_state_t *, EXT_IOCTL *, int);
78 static void ql_host_drvname(ql_adapter_state_t *, EXT_IOCTL *, int);
79 static void ql_read_nvram(ql_adapter_state_t *, EXT_IOCTL *, int);
80 static void ql_write_nvram(ql_adapter_state_t *, EXT_IOCTL *, int);
81 static void ql_read_flash(ql_adapter_state_t *, EXT_IOCTL *, int);
82 static void ql_write_flash(ql_adapter_state_t *, EXT_IOCTL *, int);
83 static void ql_write_vpd(ql_adapter_state_t *, EXT_IOCTL *, int);
84 static void ql_read_vpd(ql_adapter_state_t *, EXT_IOCTL *, int);
85 static void ql_diagnostic_loopback(ql_adapter_state_t *, EXT_IOCTL *, int);
86 static void ql_send_els_rnid(ql_adapter_state_t *, EXT_IOCTL *, int);
87 static void ql_set_host_data(ql_adapter_state_t *, EXT_IOCTL *, int);
88 static void ql_get_host_data(ql_adapter_state_t *, EXT_IOCTL *, int);
89 static void ql_qry_cna_port(ql_adapter_state_t *, EXT_IOCTL *, int);
90
91 static int ql_lun_count(ql_adapter_state_t *, ql_tgt_t *);
92 static int ql_report_lun(ql_adapter_state_t *, ql_tgt_t *);
93 static int ql_inq_scan(ql_adapter_state_t *, ql_tgt_t *, int);
94 static int ql_inq(ql_adapter_state_t *, ql_tgt_t *, int, ql_mbx_iocb_t *,
95 uint8_t);
96 static uint32_t ql_get_buffer_data(caddr_t, caddr_t, uint32_t, int);
97 static uint32_t ql_send_buffer_data(caddr_t, caddr_t, uint32_t, int);
98 static int ql_24xx_flash_desc(ql_adapter_state_t *);
99 static int ql_setup_flash(ql_adapter_state_t *);
100 static ql_tgt_t *ql_find_port(ql_adapter_state_t *, uint8_t *, uint16_t);
101 static int ql_flash_fcode_load(ql_adapter_state_t *, void *, uint32_t, int);
102 static int ql_flash_fcode_dump(ql_adapter_state_t *, void *, uint32_t,
103 uint32_t, int);
104 static int ql_program_flash_address(ql_adapter_state_t *, uint32_t,
105 uint8_t);
106 static void ql_set_rnid_parameters(ql_adapter_state_t *, EXT_IOCTL *, int);
107 static void ql_get_rnid_parameters(ql_adapter_state_t *, EXT_IOCTL *, int);
108 static int ql_reset_statistics(ql_adapter_state_t *, EXT_IOCTL *);
109 static void ql_get_statistics(ql_adapter_state_t *, EXT_IOCTL *, int);
110 static void ql_get_statistics_fc(ql_adapter_state_t *, EXT_IOCTL *, int);
111 static void ql_get_statistics_fc4(ql_adapter_state_t *, EXT_IOCTL *, int);
112 static void ql_set_led_state(ql_adapter_state_t *, EXT_IOCTL *, int);
113 static void ql_get_led_state(ql_adapter_state_t *, EXT_IOCTL *, int);
114 static void ql_drive_led(ql_adapter_state_t *, uint32_t);
115 static uint32_t ql_setup_led(ql_adapter_state_t *);
116 static uint32_t ql_wrapup_led(ql_adapter_state_t *);
117 static void ql_get_port_summary(ql_adapter_state_t *, EXT_IOCTL *, int);
118 static void ql_get_target_id(ql_adapter_state_t *, EXT_IOCTL *, int);
119 static void ql_get_sfp(ql_adapter_state_t *, EXT_IOCTL *, int);
120 static int ql_dump_sfp(ql_adapter_state_t *, void *, int);
121 static ql_fcache_t *ql_setup_fnode(ql_adapter_state_t *);
122 static void ql_get_fcache(ql_adapter_state_t *, EXT_IOCTL *, int);
123 static void ql_get_fcache_ex(ql_adapter_state_t *, EXT_IOCTL *, int);
124 void ql_update_fcache(ql_adapter_state_t *, uint8_t *, uint32_t);
125 static int ql_check_pci(ql_adapter_state_t *, ql_fcache_t *, uint32_t *);
126 static void ql_flash_layout_table(ql_adapter_state_t *, uint32_t);
127 static void ql_process_flt(ql_adapter_state_t *, uint32_t);
128 static void ql_flash_nvram_defaults(ql_adapter_state_t *);
129 static void ql_port_param(ql_adapter_state_t *, EXT_IOCTL *, int);
130 static int ql_check_pci(ql_adapter_state_t *, ql_fcache_t *, uint32_t *);
131 static void ql_get_pci_data(ql_adapter_state_t *, EXT_IOCTL *, int);
132 static void ql_get_fwfcetrace(ql_adapter_state_t *, EXT_IOCTL *, int);
133 static void ql_get_fwexttrace(ql_adapter_state_t *, EXT_IOCTL *, int);
134 static void ql_menlo_reset(ql_adapter_state_t *, EXT_IOCTL *, int);
135 static void ql_menlo_get_fw_version(ql_adapter_state_t *, EXT_IOCTL *, int);
136 static void ql_menlo_update_fw(ql_adapter_state_t *, EXT_IOCTL *, int);
137 static void ql_menlo_manage_info(ql_adapter_state_t *, EXT_IOCTL *, int);
138 static int ql_suspend_hba(ql_adapter_state_t *, uint32_t);
139 static void ql_restart_hba(ql_adapter_state_t *);
140 static void ql_get_vp_cnt_id(ql_adapter_state_t *, EXT_IOCTL *, int);
141 static void ql_vp_ioctl(ql_adapter_state_t *, EXT_IOCTL *, int);
142 static void ql_qry_vport(ql_adapter_state_t *, EXT_IOCTL *, int);
143 static void ql_access_flash(ql_adapter_state_t *, EXT_IOCTL *, int);
144 static void ql_reset_cmd(ql_adapter_state_t *, EXT_IOCTL *);
145 static void ql_update_flash_caches(ql_adapter_state_t *);
146 static void ql_get_dcbx_parameters(ql_adapter_state_t *, EXT_IOCTL *, int);
147 static void ql_get_xgmac_statistics(ql_adapter_state_t *, EXT_IOCTL *, int);
148 static void ql_get_fcf_list(ql_adapter_state_t *, EXT_IOCTL *, int);
149 static void ql_get_resource_counts(ql_adapter_state_t *, EXT_IOCTL *, int);
150 static void ql_qry_adapter_versions(ql_adapter_state_t *, EXT_IOCTL *, int);
151 static int ql_set_loop_point(ql_adapter_state_t *, uint16_t);
152
153 /* ******************************************************************** */
154 /* External IOCTL support. */
155 /* ******************************************************************** */
156
157 /*
158 * ql_alloc_xioctl_resource
159 * Allocates resources needed by module code.
160 *
161 * Input:
162 * ha: adapter state pointer.
163 *
164 * Returns:
165 * SYS_ERRNO
166 *
167 * Context:
168 * Kernel context.
169 */
170 int
ql_alloc_xioctl_resource(ql_adapter_state_t * ha)171 ql_alloc_xioctl_resource(ql_adapter_state_t *ha)
172 {
173 ql_xioctl_t *xp;
174
175 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
176
177 if (ha->xioctl != NULL) {
178 QL_PRINT_9(CE_CONT, "(%d): already allocated done\n",
179 ha->instance);
180 return (0);
181 }
182
183 xp = kmem_zalloc(sizeof (ql_xioctl_t), KM_SLEEP);
184 if (xp == NULL) {
185 EL(ha, "failed, kmem_zalloc\n");
186 return (ENOMEM);
187 }
188 ha->xioctl = xp;
189
190 /* Allocate AEN tracking buffer */
191 xp->aen_tracking_queue = kmem_zalloc(EXT_DEF_MAX_AEN_QUEUE *
192 sizeof (EXT_ASYNC_EVENT), KM_SLEEP);
193 if (xp->aen_tracking_queue == NULL) {
194 EL(ha, "failed, kmem_zalloc-2\n");
195 ql_free_xioctl_resource(ha);
196 return (ENOMEM);
197 }
198
199 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
200
201 return (0);
202 }
203
204 /*
205 * ql_free_xioctl_resource
206 * Frees resources used by module code.
207 *
208 * Input:
209 * ha: adapter state pointer.
210 *
211 * Context:
212 * Kernel context.
213 */
214 void
ql_free_xioctl_resource(ql_adapter_state_t * ha)215 ql_free_xioctl_resource(ql_adapter_state_t *ha)
216 {
217 ql_xioctl_t *xp = ha->xioctl;
218
219 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
220
221 if (xp == NULL) {
222 QL_PRINT_9(CE_CONT, "(%d): already freed\n", ha->instance);
223 return;
224 }
225
226 if (xp->aen_tracking_queue != NULL) {
227 kmem_free(xp->aen_tracking_queue, EXT_DEF_MAX_AEN_QUEUE *
228 sizeof (EXT_ASYNC_EVENT));
229 xp->aen_tracking_queue = NULL;
230 }
231
232 kmem_free(xp, sizeof (ql_xioctl_t));
233 ha->xioctl = NULL;
234
235 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
236 }
237
238 /*
239 * ql_xioctl
240 * External IOCTL processing.
241 *
242 * Input:
243 * ha: adapter state pointer.
244 * cmd: function to perform
245 * arg: data type varies with request
246 * mode: flags
247 * cred_p: credentials pointer
248 * rval_p: pointer to result value
249 *
250 * Returns:
251 * 0: success
252 * ENXIO: No such device or address
253 * ENOPROTOOPT: Protocol not available
254 *
255 * Context:
256 * Kernel context.
257 */
258 /* ARGSUSED */
259 int
ql_xioctl(ql_adapter_state_t * ha,int cmd,intptr_t arg,int mode,cred_t * cred_p,int * rval_p)260 ql_xioctl(ql_adapter_state_t *ha, int cmd, intptr_t arg, int mode,
261 cred_t *cred_p, int *rval_p)
262 {
263 int rval;
264
265 QL_PRINT_9(CE_CONT, "(%d): started, cmd=%d\n", ha->instance, cmd);
266
267 if (ha->xioctl == NULL) {
268 QL_PRINT_9(CE_CONT, "(%d): no context\n", ha->instance);
269 return (ENXIO);
270 }
271
272 switch (cmd) {
273 case EXT_CC_QUERY:
274 case EXT_CC_SEND_FCCT_PASSTHRU:
275 case EXT_CC_REG_AEN:
276 case EXT_CC_GET_AEN:
277 case EXT_CC_SEND_SCSI_PASSTHRU:
278 case EXT_CC_WWPN_TO_SCSIADDR:
279 case EXT_CC_SEND_ELS_RNID:
280 case EXT_CC_SET_DATA:
281 case EXT_CC_GET_DATA:
282 case EXT_CC_HOST_IDX:
283 case EXT_CC_READ_NVRAM:
284 case EXT_CC_UPDATE_NVRAM:
285 case EXT_CC_READ_OPTION_ROM:
286 case EXT_CC_READ_OPTION_ROM_EX:
287 case EXT_CC_UPDATE_OPTION_ROM:
288 case EXT_CC_UPDATE_OPTION_ROM_EX:
289 case EXT_CC_GET_VPD:
290 case EXT_CC_SET_VPD:
291 case EXT_CC_LOOPBACK:
292 case EXT_CC_GET_FCACHE:
293 case EXT_CC_GET_FCACHE_EX:
294 case EXT_CC_HOST_DRVNAME:
295 case EXT_CC_GET_SFP_DATA:
296 case EXT_CC_PORT_PARAM:
297 case EXT_CC_GET_PCI_DATA:
298 case EXT_CC_GET_FWEXTTRACE:
299 case EXT_CC_GET_FWFCETRACE:
300 case EXT_CC_GET_VP_CNT_ID:
301 case EXT_CC_VPORT_CMD:
302 case EXT_CC_ACCESS_FLASH:
303 case EXT_CC_RESET_FW:
304 case EXT_CC_MENLO_MANAGE_INFO:
305 rval = ql_sdm_ioctl(ha, cmd, (void *)arg, mode);
306 break;
307 default:
308 /* function not supported. */
309 EL(ha, "function=%d not supported\n", cmd);
310 rval = ENOPROTOOPT;
311 }
312
313 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
314
315 return (rval);
316 }
317
318 /*
319 * ql_sdm_ioctl
320 * Provides ioctl functions for SAN/Device Management functions
321 * AKA External Ioctl functions.
322 *
323 * Input:
324 * ha: adapter state pointer.
325 * ioctl_code: ioctl function to perform
326 * arg: Pointer to EXT_IOCTL cmd data in application land.
327 * mode: flags
328 *
329 * Returns:
330 * 0: success
331 * ENOMEM: Alloc of local EXT_IOCTL struct failed.
332 * EFAULT: Copyin of caller's EXT_IOCTL struct failed or
333 * copyout of EXT_IOCTL status info failed.
334 * EINVAL: Signature or version of caller's EXT_IOCTL invalid.
335 * EBUSY: Device busy
336 *
337 * Context:
338 * Kernel context.
339 */
340 static int
ql_sdm_ioctl(ql_adapter_state_t * ha,int ioctl_code,void * arg,int mode)341 ql_sdm_ioctl(ql_adapter_state_t *ha, int ioctl_code, void *arg, int mode)
342 {
343 EXT_IOCTL *cmd;
344 int rval;
345 ql_adapter_state_t *vha;
346
347 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
348
349 /* Copy argument structure (EXT_IOCTL) from application land. */
350 if ((rval = ql_sdm_setup(ha, &cmd, arg, mode,
351 ql_validate_signature)) != 0) {
352 /*
353 * a non-zero value at this time means a problem getting
354 * the requested information from application land, just
355 * return the error code and hope for the best.
356 */
357 EL(ha, "failed, sdm_setup\n");
358 return (rval);
359 }
360
361 /*
362 * Map the physical ha ptr (which the ioctl is called with)
363 * to the virtual ha that the caller is addressing.
364 */
365 if (ha->flags & VP_ENABLED) {
366 /* Check that it is within range. */
367 if (cmd->HbaSelect > (CFG_IST(ha, CFG_CTRL_2422) ?
368 MAX_24_VIRTUAL_PORTS : MAX_25_VIRTUAL_PORTS)) {
369 EL(ha, "Invalid HbaSelect vp index: %xh\n",
370 cmd->HbaSelect);
371 cmd->Status = EXT_STATUS_INVALID_VPINDEX;
372 cmd->ResponseLen = 0;
373 return (EFAULT);
374 }
375 /*
376 * Special case: HbaSelect == 0 is physical ha
377 */
378 if (cmd->HbaSelect != 0) {
379 vha = ha->vp_next;
380 while (vha != NULL) {
381 if (vha->vp_index == cmd->HbaSelect) {
382 ha = vha;
383 break;
384 }
385 vha = vha->vp_next;
386 }
387 /*
388 * The specified vp index may be valid(within range)
389 * but it's not in the list. Currently this is all
390 * we can say.
391 */
392 if (vha == NULL) {
393 cmd->Status = EXT_STATUS_INVALID_VPINDEX;
394 cmd->ResponseLen = 0;
395 return (EFAULT);
396 }
397 }
398 }
399
400 /*
401 * If driver is suspended, stalled, or powered down rtn BUSY
402 */
403 if (ha->flags & ADAPTER_SUSPENDED ||
404 ha->task_daemon_flags & DRIVER_STALL ||
405 ha->power_level != PM_LEVEL_D0) {
406 EL(ha, " %s\n", ha->flags & ADAPTER_SUSPENDED ?
407 "driver suspended" :
408 (ha->task_daemon_flags & DRIVER_STALL ? "driver stalled" :
409 "FCA powered down"));
410 cmd->Status = EXT_STATUS_BUSY;
411 cmd->ResponseLen = 0;
412 rval = EBUSY;
413
414 /* Return results to caller */
415 if ((ql_sdm_return(ha, cmd, arg, mode)) == -1) {
416 EL(ha, "failed, sdm_return\n");
417 rval = EFAULT;
418 }
419 return (rval);
420 }
421
422 switch (ioctl_code) {
423 case EXT_CC_QUERY_OS:
424 ql_query(ha, cmd, mode);
425 break;
426 case EXT_CC_SEND_FCCT_PASSTHRU_OS:
427 ql_fcct(ha, cmd, mode);
428 break;
429 case EXT_CC_REG_AEN_OS:
430 ql_aen_reg(ha, cmd, mode);
431 break;
432 case EXT_CC_GET_AEN_OS:
433 ql_aen_get(ha, cmd, mode);
434 break;
435 case EXT_CC_GET_DATA_OS:
436 ql_get_host_data(ha, cmd, mode);
437 break;
438 case EXT_CC_SET_DATA_OS:
439 ql_set_host_data(ha, cmd, mode);
440 break;
441 case EXT_CC_SEND_ELS_RNID_OS:
442 ql_send_els_rnid(ha, cmd, mode);
443 break;
444 case EXT_CC_SCSI_PASSTHRU_OS:
445 ql_scsi_passthru(ha, cmd, mode);
446 break;
447 case EXT_CC_WWPN_TO_SCSIADDR_OS:
448 ql_wwpn_to_scsiaddr(ha, cmd, mode);
449 break;
450 case EXT_CC_HOST_IDX_OS:
451 ql_host_idx(ha, cmd, mode);
452 break;
453 case EXT_CC_HOST_DRVNAME_OS:
454 ql_host_drvname(ha, cmd, mode);
455 break;
456 case EXT_CC_READ_NVRAM_OS:
457 ql_read_nvram(ha, cmd, mode);
458 break;
459 case EXT_CC_UPDATE_NVRAM_OS:
460 ql_write_nvram(ha, cmd, mode);
461 break;
462 case EXT_CC_READ_OPTION_ROM_OS:
463 case EXT_CC_READ_OPTION_ROM_EX_OS:
464 ql_read_flash(ha, cmd, mode);
465 break;
466 case EXT_CC_UPDATE_OPTION_ROM_OS:
467 case EXT_CC_UPDATE_OPTION_ROM_EX_OS:
468 ql_write_flash(ha, cmd, mode);
469 break;
470 case EXT_CC_LOOPBACK_OS:
471 ql_diagnostic_loopback(ha, cmd, mode);
472 break;
473 case EXT_CC_GET_VPD_OS:
474 ql_read_vpd(ha, cmd, mode);
475 break;
476 case EXT_CC_SET_VPD_OS:
477 ql_write_vpd(ha, cmd, mode);
478 break;
479 case EXT_CC_GET_FCACHE_OS:
480 ql_get_fcache(ha, cmd, mode);
481 break;
482 case EXT_CC_GET_FCACHE_EX_OS:
483 ql_get_fcache_ex(ha, cmd, mode);
484 break;
485 case EXT_CC_GET_SFP_DATA_OS:
486 ql_get_sfp(ha, cmd, mode);
487 break;
488 case EXT_CC_PORT_PARAM_OS:
489 ql_port_param(ha, cmd, mode);
490 break;
491 case EXT_CC_GET_PCI_DATA_OS:
492 ql_get_pci_data(ha, cmd, mode);
493 break;
494 case EXT_CC_GET_FWEXTTRACE_OS:
495 ql_get_fwexttrace(ha, cmd, mode);
496 break;
497 case EXT_CC_GET_FWFCETRACE_OS:
498 ql_get_fwfcetrace(ha, cmd, mode);
499 break;
500 case EXT_CC_MENLO_RESET:
501 ql_menlo_reset(ha, cmd, mode);
502 break;
503 case EXT_CC_MENLO_GET_FW_VERSION:
504 ql_menlo_get_fw_version(ha, cmd, mode);
505 break;
506 case EXT_CC_MENLO_UPDATE_FW:
507 ql_menlo_update_fw(ha, cmd, mode);
508 break;
509 case EXT_CC_MENLO_MANAGE_INFO:
510 ql_menlo_manage_info(ha, cmd, mode);
511 break;
512 case EXT_CC_GET_VP_CNT_ID_OS:
513 ql_get_vp_cnt_id(ha, cmd, mode);
514 break;
515 case EXT_CC_VPORT_CMD_OS:
516 ql_vp_ioctl(ha, cmd, mode);
517 break;
518 case EXT_CC_ACCESS_FLASH_OS:
519 ql_access_flash(ha, cmd, mode);
520 break;
521 case EXT_CC_RESET_FW_OS:
522 ql_reset_cmd(ha, cmd);
523 break;
524 default:
525 /* function not supported. */
526 EL(ha, "failed, function not supported=%d\n", ioctl_code);
527
528 cmd->Status = EXT_STATUS_INVALID_REQUEST;
529 cmd->ResponseLen = 0;
530 break;
531 }
532
533 /* Return results to caller */
534 if (ql_sdm_return(ha, cmd, arg, mode) == -1) {
535 EL(ha, "failed, sdm_return\n");
536 return (EFAULT);
537 }
538
539 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
540
541 return (0);
542 }
543
544 /*
545 * ql_sdm_setup
546 * Make a local copy of the EXT_IOCTL struct and validate it.
547 *
548 * Input:
549 * ha: adapter state pointer.
550 * cmd_struct: Pointer to location to store local adrs of EXT_IOCTL.
551 * arg: Address of application EXT_IOCTL cmd data
552 * mode: flags
553 * val_sig: Pointer to a function to validate the ioctl signature.
554 *
555 * Returns:
556 * 0: success
557 * EFAULT: Copy in error of application EXT_IOCTL struct.
558 * EINVAL: Invalid version, signature.
559 * ENOMEM: Local allocation of EXT_IOCTL failed.
560 *
561 * Context:
562 * Kernel context.
563 */
564 static int
ql_sdm_setup(ql_adapter_state_t * ha,EXT_IOCTL ** cmd_struct,void * arg,int mode,boolean_t (* val_sig)(EXT_IOCTL *))565 ql_sdm_setup(ql_adapter_state_t *ha, EXT_IOCTL **cmd_struct, void *arg,
566 int mode, boolean_t (*val_sig)(EXT_IOCTL *))
567 {
568 int rval;
569 EXT_IOCTL *cmd;
570
571 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
572
573 /* Allocate local memory for EXT_IOCTL. */
574 *cmd_struct = NULL;
575 cmd = (EXT_IOCTL *)kmem_zalloc(sizeof (EXT_IOCTL), KM_SLEEP);
576 if (cmd == NULL) {
577 EL(ha, "failed, kmem_zalloc\n");
578 return (ENOMEM);
579 }
580 /* Get argument structure. */
581 rval = ddi_copyin(arg, (void *)cmd, sizeof (EXT_IOCTL), mode);
582 if (rval != 0) {
583 EL(ha, "failed, ddi_copyin\n");
584 rval = EFAULT;
585 } else {
586 /*
587 * Check signature and the version.
588 * If either are not valid then neither is the
589 * structure so don't attempt to return any error status
590 * because we can't trust what caller's arg points to.
591 * Just return the errno.
592 */
593 if (val_sig(cmd) == 0) {
594 EL(ha, "failed, signature\n");
595 rval = EINVAL;
596 } else if (cmd->Version > EXT_VERSION) {
597 EL(ha, "failed, version\n");
598 rval = EINVAL;
599 }
600 }
601
602 if (rval == 0) {
603 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
604 *cmd_struct = cmd;
605 cmd->Status = EXT_STATUS_OK;
606 cmd->DetailStatus = 0;
607 } else {
608 kmem_free((void *)cmd, sizeof (EXT_IOCTL));
609 }
610
611 return (rval);
612 }
613
614 /*
615 * ql_validate_signature
616 * Validate the signature string for an external ioctl call.
617 *
618 * Input:
619 * sg: Pointer to EXT_IOCTL signature to validate.
620 *
621 * Returns:
622 * B_TRUE: Signature is valid.
623 * B_FALSE: Signature is NOT valid.
624 *
625 * Context:
626 * Kernel context.
627 */
628 static boolean_t
ql_validate_signature(EXT_IOCTL * cmd_struct)629 ql_validate_signature(EXT_IOCTL *cmd_struct)
630 {
631 /*
632 * Check signature.
633 *
634 * If signature is not valid then neither is the rest of
635 * the structure (e.g., can't trust it), so don't attempt
636 * to return any error status other than the errno.
637 */
638 if (bcmp(&cmd_struct->Signature, "QLOGIC", 6) != 0) {
639 QL_PRINT_2(CE_CONT, "failed,\n");
640 return (B_FALSE);
641 }
642
643 return (B_TRUE);
644 }
645
646 /*
647 * ql_sdm_return
648 * Copies return data/status to application land for
649 * ioctl call using the SAN/Device Management EXT_IOCTL call interface.
650 *
651 * Input:
652 * ha: adapter state pointer.
653 * cmd: Pointer to kernel copy of requestor's EXT_IOCTL struct.
654 * ioctl_code: ioctl function to perform
655 * arg: EXT_IOCTL cmd data in application land.
656 * mode: flags
657 *
658 * Returns:
659 * 0: success
660 * EFAULT: Copy out error.
661 *
662 * Context:
663 * Kernel context.
664 */
665 /* ARGSUSED */
666 static int
ql_sdm_return(ql_adapter_state_t * ha,EXT_IOCTL * cmd,void * arg,int mode)667 ql_sdm_return(ql_adapter_state_t *ha, EXT_IOCTL *cmd, void *arg, int mode)
668 {
669 int rval = 0;
670
671 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
672
673 rval |= ddi_copyout((void *)&cmd->ResponseLen,
674 (void *)&(((EXT_IOCTL*)arg)->ResponseLen), sizeof (uint32_t),
675 mode);
676
677 rval |= ddi_copyout((void *)&cmd->Status,
678 (void *)&(((EXT_IOCTL*)arg)->Status),
679 sizeof (cmd->Status), mode);
680 rval |= ddi_copyout((void *)&cmd->DetailStatus,
681 (void *)&(((EXT_IOCTL*)arg)->DetailStatus),
682 sizeof (cmd->DetailStatus), mode);
683
684 kmem_free((void *)cmd, sizeof (EXT_IOCTL));
685
686 if (rval != 0) {
687 /* Some copyout operation failed */
688 EL(ha, "failed, ddi_copyout\n");
689 return (EFAULT);
690 }
691
692 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
693
694 return (0);
695 }
696
697 /*
698 * ql_query
699 * Performs all EXT_CC_QUERY functions.
700 *
701 * Input:
702 * ha: adapter state pointer.
703 * cmd: Local EXT_IOCTL cmd struct pointer.
704 * mode: flags.
705 *
706 * Returns:
707 * None, request status indicated in cmd->Status.
708 *
709 * Context:
710 * Kernel context.
711 */
712 static void
ql_query(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)713 ql_query(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
714 {
715 QL_PRINT_9(CE_CONT, "(%d): started, cmd=%d\n", ha->instance,
716 cmd->SubCode);
717
718 /* case off on command subcode */
719 switch (cmd->SubCode) {
720 case EXT_SC_QUERY_HBA_NODE:
721 ql_qry_hba_node(ha, cmd, mode);
722 break;
723 case EXT_SC_QUERY_HBA_PORT:
724 ql_qry_hba_port(ha, cmd, mode);
725 break;
726 case EXT_SC_QUERY_DISC_PORT:
727 ql_qry_disc_port(ha, cmd, mode);
728 break;
729 case EXT_SC_QUERY_DISC_TGT:
730 ql_qry_disc_tgt(ha, cmd, mode);
731 break;
732 case EXT_SC_QUERY_DRIVER:
733 ql_qry_driver(ha, cmd, mode);
734 break;
735 case EXT_SC_QUERY_FW:
736 ql_qry_fw(ha, cmd, mode);
737 break;
738 case EXT_SC_QUERY_CHIP:
739 ql_qry_chip(ha, cmd, mode);
740 break;
741 case EXT_SC_QUERY_CNA_PORT:
742 ql_qry_cna_port(ha, cmd, mode);
743 break;
744 case EXT_SC_QUERY_ADAPTER_VERSIONS:
745 ql_qry_adapter_versions(ha, cmd, mode);
746 break;
747 case EXT_SC_QUERY_DISC_LUN:
748 default:
749 /* function not supported. */
750 cmd->Status = EXT_STATUS_UNSUPPORTED_SUBCODE;
751 EL(ha, "failed, Unsupported Subcode=%xh\n",
752 cmd->SubCode);
753 break;
754 }
755
756 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
757 }
758
759 /*
760 * ql_qry_hba_node
761 * Performs EXT_SC_QUERY_HBA_NODE subfunction.
762 *
763 * Input:
764 * ha: adapter state pointer.
765 * cmd: EXT_IOCTL cmd struct pointer.
766 * mode: flags.
767 *
768 * Returns:
769 * None, request status indicated in cmd->Status.
770 *
771 * Context:
772 * Kernel context.
773 */
774 static void
ql_qry_hba_node(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)775 ql_qry_hba_node(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
776 {
777 EXT_HBA_NODE tmp_node = {0};
778 uint_t len;
779 caddr_t bufp;
780
781 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
782
783 if (cmd->ResponseLen < sizeof (EXT_HBA_NODE)) {
784 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
785 cmd->DetailStatus = sizeof (EXT_HBA_NODE);
786 EL(ha, "failed, ResponseLen < EXT_HBA_NODE, "
787 "Len=%xh\n", cmd->ResponseLen);
788 cmd->ResponseLen = 0;
789 return;
790 }
791
792 /* fill in the values */
793
794 bcopy(ha->loginparams.node_ww_name.raw_wwn, tmp_node.WWNN,
795 EXT_DEF_WWN_NAME_SIZE);
796
797 (void) sprintf((char *)(tmp_node.Manufacturer), "QLogic Corporation");
798
799 (void) sprintf((char *)(tmp_node.Model), "%x", ha->device_id);
800
801 bcopy(&tmp_node.WWNN[5], tmp_node.SerialNum, 3);
802
803 (void) sprintf((char *)(tmp_node.DriverVersion), QL_VERSION);
804
805 if (CFG_IST(ha, CFG_SBUS_CARD)) {
806 size_t verlen;
807 uint16_t w;
808 char *tmpptr;
809
810 verlen = strlen((char *)(tmp_node.DriverVersion));
811 if (verlen + 5 > EXT_DEF_MAX_STR_SIZE) {
812 EL(ha, "failed, No room for fpga version string\n");
813 } else {
814 w = (uint16_t)ddi_get16(ha->sbus_fpga_dev_handle,
815 (uint16_t *)
816 (ha->sbus_fpga_iobase + FPGA_REVISION));
817
818 tmpptr = (char *)&(tmp_node.DriverVersion[verlen+1]);
819 if (tmpptr == NULL) {
820 EL(ha, "Unable to insert fpga version str\n");
821 } else {
822 (void) sprintf(tmpptr, "%d.%d",
823 ((w & 0xf0) >> 4), (w & 0x0f));
824 tmp_node.DriverAttr |= EXT_CC_HBA_NODE_SBUS;
825 }
826 }
827 }
828
829 (void) sprintf((char *)(tmp_node.FWVersion), "%01d.%02d.%02d",
830 ha->fw_major_version, ha->fw_minor_version,
831 ha->fw_subminor_version);
832
833 if ((CFG_IST(ha, CFG_CTRL_24258081)) == 0) {
834 switch (ha->fw_attributes) {
835 case FWATTRIB_EF:
836 (void) strcat((char *)(tmp_node.FWVersion), " EF");
837 break;
838 case FWATTRIB_TP:
839 (void) strcat((char *)(tmp_node.FWVersion), " TP");
840 break;
841 case FWATTRIB_IP:
842 (void) strcat((char *)(tmp_node.FWVersion), " IP");
843 break;
844 case FWATTRIB_IPX:
845 (void) strcat((char *)(tmp_node.FWVersion), " IPX");
846 break;
847 case FWATTRIB_FL:
848 (void) strcat((char *)(tmp_node.FWVersion), " FL");
849 break;
850 case FWATTRIB_FPX:
851 (void) strcat((char *)(tmp_node.FWVersion), " FLX");
852 break;
853 default:
854 break;
855 }
856 }
857
858 /* FCode version. */
859 /*LINTED [Solaris DDI_DEV_T_ANY Lint error]*/
860 if (ddi_getlongprop(DDI_DEV_T_ANY, ha->dip, PROP_LEN_AND_VAL_ALLOC |
861 DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, "version", (caddr_t)&bufp,
862 (int *)&len) == DDI_PROP_SUCCESS) {
863 if (len < EXT_DEF_MAX_STR_SIZE) {
864 bcopy(bufp, tmp_node.OptRomVersion, len);
865 } else {
866 bcopy(bufp, tmp_node.OptRomVersion,
867 EXT_DEF_MAX_STR_SIZE - 1);
868 tmp_node.OptRomVersion[EXT_DEF_MAX_STR_SIZE - 1] =
869 '\0';
870 }
871 kmem_free(bufp, len);
872 } else {
873 (void) sprintf((char *)tmp_node.OptRomVersion, "0");
874 }
875 tmp_node.PortCount = 1;
876 tmp_node.InterfaceType = EXT_DEF_FC_INTF_TYPE;
877
878 if (ddi_copyout((void *)&tmp_node,
879 (void *)(uintptr_t)(cmd->ResponseAdr),
880 sizeof (EXT_HBA_NODE), mode) != 0) {
881 cmd->Status = EXT_STATUS_COPY_ERR;
882 cmd->ResponseLen = 0;
883 EL(ha, "failed, ddi_copyout\n");
884 } else {
885 cmd->ResponseLen = sizeof (EXT_HBA_NODE);
886 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
887 }
888 }
889
890 /*
891 * ql_qry_hba_port
892 * Performs EXT_SC_QUERY_HBA_PORT subfunction.
893 *
894 * Input:
895 * ha: adapter state pointer.
896 * cmd: EXT_IOCTL cmd struct pointer.
897 * mode: flags.
898 *
899 * Returns:
900 * None, request status indicated in cmd->Status.
901 *
902 * Context:
903 * Kernel context.
904 */
905 static void
ql_qry_hba_port(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)906 ql_qry_hba_port(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
907 {
908 ql_link_t *link;
909 ql_tgt_t *tq;
910 ql_mbx_data_t mr;
911 EXT_HBA_PORT tmp_port = {0};
912 int rval;
913 uint16_t port_cnt, tgt_cnt, index;
914
915 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
916
917 if (cmd->ResponseLen < sizeof (EXT_HBA_PORT)) {
918 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
919 cmd->DetailStatus = sizeof (EXT_HBA_PORT);
920 EL(ha, "failed, ResponseLen < EXT_HBA_NODE, Len=%xh\n",
921 cmd->ResponseLen);
922 cmd->ResponseLen = 0;
923 return;
924 }
925
926 /* fill in the values */
927
928 bcopy(ha->loginparams.nport_ww_name.raw_wwn, tmp_port.WWPN,
929 EXT_DEF_WWN_NAME_SIZE);
930 tmp_port.Id[0] = 0;
931 tmp_port.Id[1] = ha->d_id.b.domain;
932 tmp_port.Id[2] = ha->d_id.b.area;
933 tmp_port.Id[3] = ha->d_id.b.al_pa;
934
935 /* For now we are initiator only driver */
936 tmp_port.Type = EXT_DEF_INITIATOR_DEV;
937
938 if (ha->task_daemon_flags & LOOP_DOWN) {
939 tmp_port.State = EXT_DEF_HBA_LOOP_DOWN;
940 } else if (DRIVER_SUSPENDED(ha)) {
941 tmp_port.State = EXT_DEF_HBA_SUSPENDED;
942 } else {
943 tmp_port.State = EXT_DEF_HBA_OK;
944 }
945
946 if (ha->flags & POINT_TO_POINT) {
947 tmp_port.Mode = EXT_DEF_P2P_MODE;
948 } else {
949 tmp_port.Mode = EXT_DEF_LOOP_MODE;
950 }
951 /*
952 * fill in the portspeed values.
953 *
954 * default to not yet negotiated state
955 */
956 tmp_port.PortSpeed = EXT_PORTSPEED_NOT_NEGOTIATED;
957
958 if (tmp_port.State == EXT_DEF_HBA_OK) {
959 switch (ha->iidma_rate) {
960 case IIDMA_RATE_1GB:
961 tmp_port.PortSpeed = EXT_DEF_PORTSPEED_1GBIT;
962 break;
963 case IIDMA_RATE_2GB:
964 tmp_port.PortSpeed = EXT_DEF_PORTSPEED_2GBIT;
965 break;
966 case IIDMA_RATE_4GB:
967 tmp_port.PortSpeed = EXT_DEF_PORTSPEED_4GBIT;
968 break;
969 case IIDMA_RATE_8GB:
970 tmp_port.PortSpeed = EXT_DEF_PORTSPEED_8GBIT;
971 break;
972 case IIDMA_RATE_10GB:
973 tmp_port.PortSpeed = EXT_DEF_PORTSPEED_10GBIT;
974 break;
975 default:
976 tmp_port.PortSpeed = EXT_DEF_PORTSPEED_UNKNOWN;
977 EL(ha, "failed, data rate=%xh\n", mr.mb[1]);
978 break;
979 }
980 }
981
982 /* Report all supported port speeds */
983 if (CFG_IST(ha, CFG_CTRL_25XX)) {
984 tmp_port.PortSupportedSpeed = (EXT_DEF_PORTSPEED_8GBIT |
985 EXT_DEF_PORTSPEED_4GBIT | EXT_DEF_PORTSPEED_2GBIT |
986 EXT_DEF_PORTSPEED_1GBIT);
987 /*
988 * Correct supported speeds based on type of
989 * sfp that is present
990 */
991 switch (ha->sfp_stat) {
992 case 1:
993 /* no sfp detected */
994 break;
995 case 2:
996 case 4:
997 /* 4GB sfp */
998 tmp_port.PortSupportedSpeed &=
999 ~EXT_DEF_PORTSPEED_8GBIT;
1000 break;
1001 case 3:
1002 case 5:
1003 /* 8GB sfp */
1004 tmp_port.PortSupportedSpeed &=
1005 ~EXT_DEF_PORTSPEED_1GBIT;
1006 break;
1007 default:
1008 EL(ha, "sfp_stat: %xh\n", ha->sfp_stat);
1009 break;
1010
1011 }
1012 } else if (CFG_IST(ha, CFG_CTRL_8081)) {
1013 tmp_port.PortSupportedSpeed = EXT_DEF_PORTSPEED_10GBIT;
1014 } else if (CFG_IST(ha, CFG_CTRL_2422)) {
1015 tmp_port.PortSupportedSpeed = (EXT_DEF_PORTSPEED_4GBIT |
1016 EXT_DEF_PORTSPEED_2GBIT | EXT_DEF_PORTSPEED_1GBIT);
1017 } else if (CFG_IST(ha, CFG_CTRL_2300)) {
1018 tmp_port.PortSupportedSpeed = (EXT_DEF_PORTSPEED_2GBIT |
1019 EXT_DEF_PORTSPEED_1GBIT);
1020 } else if (CFG_IST(ha, CFG_CTRL_6322)) {
1021 tmp_port.PortSupportedSpeed = EXT_DEF_PORTSPEED_2GBIT;
1022 } else if (CFG_IST(ha, CFG_CTRL_2200)) {
1023 tmp_port.PortSupportedSpeed = EXT_DEF_PORTSPEED_1GBIT;
1024 } else {
1025 tmp_port.PortSupportedSpeed = EXT_DEF_PORTSPEED_UNKNOWN;
1026 EL(ha, "unknown HBA type: %xh\n", ha->device_id);
1027 }
1028 tmp_port.LinkState2 = LSB(ha->sfp_stat);
1029 port_cnt = 0;
1030 tgt_cnt = 0;
1031
1032 for (index = 0; index < DEVICE_HEAD_LIST_SIZE; index++) {
1033 for (link = ha->dev[index].first; link != NULL;
1034 link = link->next) {
1035 tq = link->base_address;
1036
1037 if (!VALID_TARGET_ID(ha, tq->loop_id)) {
1038 continue;
1039 }
1040
1041 port_cnt++;
1042 if ((tq->flags & TQF_INITIATOR_DEVICE) == 0) {
1043 tgt_cnt++;
1044 }
1045 }
1046 }
1047
1048 tmp_port.DiscPortCount = port_cnt;
1049 tmp_port.DiscTargetCount = tgt_cnt;
1050
1051 tmp_port.DiscPortNameType = EXT_DEF_USE_NODE_NAME;
1052
1053 rval = ddi_copyout((void *)&tmp_port,
1054 (void *)(uintptr_t)(cmd->ResponseAdr),
1055 sizeof (EXT_HBA_PORT), mode);
1056 if (rval != 0) {
1057 cmd->Status = EXT_STATUS_COPY_ERR;
1058 cmd->ResponseLen = 0;
1059 EL(ha, "failed, ddi_copyout\n");
1060 } else {
1061 cmd->ResponseLen = sizeof (EXT_HBA_PORT);
1062 QL_PRINT_9(CE_CONT, "(%d): done, ports=%d, targets=%d\n",
1063 ha->instance, port_cnt, tgt_cnt);
1064 }
1065 }
1066
1067 /*
1068 * ql_qry_disc_port
1069 * Performs EXT_SC_QUERY_DISC_PORT subfunction.
1070 *
1071 * Input:
1072 * ha: adapter state pointer.
1073 * cmd: EXT_IOCTL cmd struct pointer.
1074 * mode: flags.
1075 *
1076 * cmd->Instance = Port instance in fcport chain.
1077 *
1078 * Returns:
1079 * None, request status indicated in cmd->Status.
1080 *
1081 * Context:
1082 * Kernel context.
1083 */
1084 static void
ql_qry_disc_port(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)1085 ql_qry_disc_port(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
1086 {
1087 EXT_DISC_PORT tmp_port = {0};
1088 ql_link_t *link;
1089 ql_tgt_t *tq;
1090 uint16_t index;
1091 uint16_t inst = 0;
1092
1093 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
1094
1095 if (cmd->ResponseLen < sizeof (EXT_DISC_PORT)) {
1096 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
1097 cmd->DetailStatus = sizeof (EXT_DISC_PORT);
1098 EL(ha, "failed, ResponseLen < EXT_DISC_PORT, Len=%xh\n",
1099 cmd->ResponseLen);
1100 cmd->ResponseLen = 0;
1101 return;
1102 }
1103
1104 for (link = NULL, index = 0;
1105 index < DEVICE_HEAD_LIST_SIZE && link == NULL; index++) {
1106 for (link = ha->dev[index].first; link != NULL;
1107 link = link->next) {
1108 tq = link->base_address;
1109
1110 if (!VALID_TARGET_ID(ha, tq->loop_id)) {
1111 continue;
1112 }
1113 if (inst != cmd->Instance) {
1114 inst++;
1115 continue;
1116 }
1117
1118 /* fill in the values */
1119 bcopy(tq->node_name, tmp_port.WWNN,
1120 EXT_DEF_WWN_NAME_SIZE);
1121 bcopy(tq->port_name, tmp_port.WWPN,
1122 EXT_DEF_WWN_NAME_SIZE);
1123
1124 break;
1125 }
1126 }
1127
1128 if (link == NULL) {
1129 /* no matching device */
1130 cmd->Status = EXT_STATUS_DEV_NOT_FOUND;
1131 EL(ha, "failed, port not found port=%d\n", cmd->Instance);
1132 cmd->ResponseLen = 0;
1133 return;
1134 }
1135
1136 tmp_port.Id[0] = 0;
1137 tmp_port.Id[1] = tq->d_id.b.domain;
1138 tmp_port.Id[2] = tq->d_id.b.area;
1139 tmp_port.Id[3] = tq->d_id.b.al_pa;
1140
1141 tmp_port.Type = 0;
1142 if (tq->flags & TQF_INITIATOR_DEVICE) {
1143 tmp_port.Type = (uint16_t)(tmp_port.Type |
1144 EXT_DEF_INITIATOR_DEV);
1145 } else if ((tq->flags & TQF_TAPE_DEVICE) == 0) {
1146 (void) ql_inq_scan(ha, tq, 1);
1147 } else if (tq->flags & TQF_TAPE_DEVICE) {
1148 tmp_port.Type = (uint16_t)(tmp_port.Type | EXT_DEF_TAPE_DEV);
1149 }
1150
1151 if (tq->flags & TQF_FABRIC_DEVICE) {
1152 tmp_port.Type = (uint16_t)(tmp_port.Type | EXT_DEF_FABRIC_DEV);
1153 } else {
1154 tmp_port.Type = (uint16_t)(tmp_port.Type | EXT_DEF_TARGET_DEV);
1155 }
1156
1157 tmp_port.Status = 0;
1158 tmp_port.Bus = 0; /* Hard-coded for Solaris */
1159
1160 bcopy(tq->port_name, &tmp_port.TargetId, 8);
1161
1162 if (ddi_copyout((void *)&tmp_port,
1163 (void *)(uintptr_t)(cmd->ResponseAdr),
1164 sizeof (EXT_DISC_PORT), mode) != 0) {
1165 cmd->Status = EXT_STATUS_COPY_ERR;
1166 cmd->ResponseLen = 0;
1167 EL(ha, "failed, ddi_copyout\n");
1168 } else {
1169 cmd->ResponseLen = sizeof (EXT_DISC_PORT);
1170 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
1171 }
1172 }
1173
1174 /*
1175 * ql_qry_disc_tgt
1176 * Performs EXT_SC_QUERY_DISC_TGT subfunction.
1177 *
1178 * Input:
1179 * ha: adapter state pointer.
1180 * cmd: EXT_IOCTL cmd struct pointer.
1181 * mode: flags.
1182 *
1183 * cmd->Instance = Port instance in fcport chain.
1184 *
1185 * Returns:
1186 * None, request status indicated in cmd->Status.
1187 *
1188 * Context:
1189 * Kernel context.
1190 */
1191 static void
ql_qry_disc_tgt(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)1192 ql_qry_disc_tgt(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
1193 {
1194 EXT_DISC_TARGET tmp_tgt = {0};
1195 ql_link_t *link;
1196 ql_tgt_t *tq;
1197 uint16_t index;
1198 uint16_t inst = 0;
1199
1200 QL_PRINT_9(CE_CONT, "(%d): started, target=%d\n", ha->instance,
1201 cmd->Instance);
1202
1203 if (cmd->ResponseLen < sizeof (EXT_DISC_TARGET)) {
1204 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
1205 cmd->DetailStatus = sizeof (EXT_DISC_TARGET);
1206 EL(ha, "failed, ResponseLen < EXT_DISC_TARGET, Len=%xh\n",
1207 cmd->ResponseLen);
1208 cmd->ResponseLen = 0;
1209 return;
1210 }
1211
1212 /* Scan port list for requested target and fill in the values */
1213 for (link = NULL, index = 0;
1214 index < DEVICE_HEAD_LIST_SIZE && link == NULL; index++) {
1215 for (link = ha->dev[index].first; link != NULL;
1216 link = link->next) {
1217 tq = link->base_address;
1218
1219 if (!VALID_TARGET_ID(ha, tq->loop_id) ||
1220 tq->flags & TQF_INITIATOR_DEVICE) {
1221 continue;
1222 }
1223 if (inst != cmd->Instance) {
1224 inst++;
1225 continue;
1226 }
1227
1228 /* fill in the values */
1229 bcopy(tq->node_name, tmp_tgt.WWNN,
1230 EXT_DEF_WWN_NAME_SIZE);
1231 bcopy(tq->port_name, tmp_tgt.WWPN,
1232 EXT_DEF_WWN_NAME_SIZE);
1233
1234 break;
1235 }
1236 }
1237
1238 if (link == NULL) {
1239 /* no matching device */
1240 cmd->Status = EXT_STATUS_DEV_NOT_FOUND;
1241 cmd->DetailStatus = EXT_DSTATUS_TARGET;
1242 EL(ha, "failed, not found target=%d\n", cmd->Instance);
1243 cmd->ResponseLen = 0;
1244 return;
1245 }
1246 tmp_tgt.Id[0] = 0;
1247 tmp_tgt.Id[1] = tq->d_id.b.domain;
1248 tmp_tgt.Id[2] = tq->d_id.b.area;
1249 tmp_tgt.Id[3] = tq->d_id.b.al_pa;
1250
1251 tmp_tgt.LunCount = (uint16_t)ql_lun_count(ha, tq);
1252
1253 if ((tq->flags & TQF_TAPE_DEVICE) == 0) {
1254 (void) ql_inq_scan(ha, tq, 1);
1255 }
1256
1257 tmp_tgt.Type = 0;
1258 if (tq->flags & TQF_TAPE_DEVICE) {
1259 tmp_tgt.Type = (uint16_t)(tmp_tgt.Type | EXT_DEF_TAPE_DEV);
1260 }
1261
1262 if (tq->flags & TQF_FABRIC_DEVICE) {
1263 tmp_tgt.Type = (uint16_t)(tmp_tgt.Type | EXT_DEF_FABRIC_DEV);
1264 } else {
1265 tmp_tgt.Type = (uint16_t)(tmp_tgt.Type | EXT_DEF_TARGET_DEV);
1266 }
1267
1268 tmp_tgt.Status = 0;
1269
1270 tmp_tgt.Bus = 0; /* Hard-coded for Solaris. */
1271
1272 bcopy(tq->port_name, &tmp_tgt.TargetId, 8);
1273
1274 if (ddi_copyout((void *)&tmp_tgt,
1275 (void *)(uintptr_t)(cmd->ResponseAdr),
1276 sizeof (EXT_DISC_TARGET), mode) != 0) {
1277 cmd->Status = EXT_STATUS_COPY_ERR;
1278 cmd->ResponseLen = 0;
1279 EL(ha, "failed, ddi_copyout\n");
1280 } else {
1281 cmd->ResponseLen = sizeof (EXT_DISC_TARGET);
1282 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
1283 }
1284 }
1285
1286 /*
1287 * ql_qry_fw
1288 * Performs EXT_SC_QUERY_FW subfunction.
1289 *
1290 * Input:
1291 * ha: adapter state pointer.
1292 * cmd: EXT_IOCTL cmd struct pointer.
1293 * mode: flags.
1294 *
1295 * Returns:
1296 * None, request status indicated in cmd->Status.
1297 *
1298 * Context:
1299 * Kernel context.
1300 */
1301 static void
ql_qry_fw(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)1302 ql_qry_fw(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
1303 {
1304 EXT_FW fw_info = {0};
1305
1306 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
1307
1308 if (cmd->ResponseLen < sizeof (EXT_FW)) {
1309 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
1310 cmd->DetailStatus = sizeof (EXT_FW);
1311 EL(ha, "failed, ResponseLen < EXT_FW, Len=%xh\n",
1312 cmd->ResponseLen);
1313 cmd->ResponseLen = 0;
1314 return;
1315 }
1316
1317 (void) sprintf((char *)(fw_info.Version), "%d.%02d.%02d",
1318 ha->fw_major_version, ha->fw_minor_version,
1319 ha->fw_subminor_version);
1320
1321 fw_info.Attrib = ha->fw_attributes;
1322
1323 if (ddi_copyout((void *)&fw_info,
1324 (void *)(uintptr_t)(cmd->ResponseAdr),
1325 sizeof (EXT_FW), mode) != 0) {
1326 cmd->Status = EXT_STATUS_COPY_ERR;
1327 cmd->ResponseLen = 0;
1328 EL(ha, "failed, ddi_copyout\n");
1329 return;
1330 } else {
1331 cmd->ResponseLen = sizeof (EXT_FW);
1332 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
1333 }
1334 }
1335
1336 /*
1337 * ql_qry_chip
1338 * Performs EXT_SC_QUERY_CHIP subfunction.
1339 *
1340 * Input:
1341 * ha: adapter state pointer.
1342 * cmd: EXT_IOCTL cmd struct pointer.
1343 * mode: flags.
1344 *
1345 * Returns:
1346 * None, request status indicated in cmd->Status.
1347 *
1348 * Context:
1349 * Kernel context.
1350 */
1351 static void
ql_qry_chip(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)1352 ql_qry_chip(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
1353 {
1354 EXT_CHIP chip = {0};
1355
1356 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
1357
1358 if (cmd->ResponseLen < sizeof (EXT_CHIP)) {
1359 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
1360 cmd->DetailStatus = sizeof (EXT_CHIP);
1361 EL(ha, "failed, ResponseLen < EXT_CHIP, Len=%xh\n",
1362 cmd->ResponseLen);
1363 cmd->ResponseLen = 0;
1364 return;
1365 }
1366
1367 chip.VendorId = ha->ven_id;
1368 chip.DeviceId = ha->device_id;
1369 chip.SubVendorId = ha->subven_id;
1370 chip.SubSystemId = ha->subsys_id;
1371 chip.IoAddr = ql_pci_config_get32(ha, PCI_CONF_BASE0);
1372 chip.IoAddrLen = 0x100;
1373 chip.MemAddr = ql_pci_config_get32(ha, PCI_CONF_BASE1);
1374 chip.MemAddrLen = 0x100;
1375 chip.ChipRevID = ha->rev_id;
1376 if (ha->flags & FUNCTION_1) {
1377 chip.FuncNo = 1;
1378 }
1379
1380 if (ddi_copyout((void *)&chip,
1381 (void *)(uintptr_t)(cmd->ResponseAdr),
1382 sizeof (EXT_CHIP), mode) != 0) {
1383 cmd->Status = EXT_STATUS_COPY_ERR;
1384 cmd->ResponseLen = 0;
1385 EL(ha, "failed, ddi_copyout\n");
1386 } else {
1387 cmd->ResponseLen = sizeof (EXT_CHIP);
1388 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
1389 }
1390 }
1391
1392 /*
1393 * ql_qry_driver
1394 * Performs EXT_SC_QUERY_DRIVER subfunction.
1395 *
1396 * Input:
1397 * ha: adapter state pointer.
1398 * cmd: EXT_IOCTL cmd struct pointer.
1399 * mode: flags.
1400 *
1401 * Returns:
1402 * None, request status indicated in cmd->Status.
1403 *
1404 * Context:
1405 * Kernel context.
1406 */
1407 static void
ql_qry_driver(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)1408 ql_qry_driver(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
1409 {
1410 EXT_DRIVER qd = {0};
1411
1412 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
1413
1414 if (cmd->ResponseLen < sizeof (EXT_DRIVER)) {
1415 cmd->Status = EXT_STATUS_DATA_OVERRUN;
1416 cmd->DetailStatus = sizeof (EXT_DRIVER);
1417 EL(ha, "failed, ResponseLen < EXT_DRIVER, Len=%xh\n",
1418 cmd->ResponseLen);
1419 cmd->ResponseLen = 0;
1420 return;
1421 }
1422
1423 (void) strcpy((void *)&qd.Version[0], QL_VERSION);
1424 qd.NumOfBus = 1; /* Fixed for Solaris */
1425 qd.TargetsPerBus = (uint16_t)
1426 (CFG_IST(ha, (CFG_CTRL_24258081 | CFG_EXT_FW_INTERFACE)) ?
1427 MAX_24_FIBRE_DEVICES : MAX_22_FIBRE_DEVICES);
1428 qd.LunsPerTarget = 2030;
1429 qd.MaxTransferLen = QL_DMA_MAX_XFER_SIZE;
1430 qd.MaxDataSegments = QL_DMA_SG_LIST_LENGTH;
1431
1432 if (ddi_copyout((void *)&qd, (void *)(uintptr_t)cmd->ResponseAdr,
1433 sizeof (EXT_DRIVER), mode) != 0) {
1434 cmd->Status = EXT_STATUS_COPY_ERR;
1435 cmd->ResponseLen = 0;
1436 EL(ha, "failed, ddi_copyout\n");
1437 } else {
1438 cmd->ResponseLen = sizeof (EXT_DRIVER);
1439 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
1440 }
1441 }
1442
1443 /*
1444 * ql_fcct
1445 * IOCTL management server FC-CT passthrough.
1446 *
1447 * Input:
1448 * ha: adapter state pointer.
1449 * cmd: User space CT arguments pointer.
1450 * mode: flags.
1451 *
1452 * Returns:
1453 * None, request status indicated in cmd->Status.
1454 *
1455 * Context:
1456 * Kernel context.
1457 */
1458 static void
ql_fcct(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)1459 ql_fcct(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
1460 {
1461 ql_mbx_iocb_t *pkt;
1462 ql_mbx_data_t mr;
1463 dma_mem_t *dma_mem;
1464 caddr_t pld;
1465 uint32_t pkt_size, pld_byte_cnt, *long_ptr;
1466 int rval;
1467 ql_ct_iu_preamble_t *ct;
1468 ql_xioctl_t *xp = ha->xioctl;
1469 ql_tgt_t tq;
1470 uint16_t comp_status, loop_id;
1471
1472 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
1473
1474 /* Get CT argument structure. */
1475 if ((ha->topology & QL_SNS_CONNECTION) == 0) {
1476 EL(ha, "failed, No switch\n");
1477 cmd->Status = EXT_STATUS_DEV_NOT_FOUND;
1478 cmd->ResponseLen = 0;
1479 return;
1480 }
1481
1482 if (DRIVER_SUSPENDED(ha)) {
1483 EL(ha, "failed, LOOP_NOT_READY\n");
1484 cmd->Status = EXT_STATUS_BUSY;
1485 cmd->ResponseLen = 0;
1486 return;
1487 }
1488
1489 /* Login management server device. */
1490 if ((xp->flags & QL_MGMT_SERVER_LOGIN) == 0) {
1491 tq.d_id.b.al_pa = 0xfa;
1492 tq.d_id.b.area = 0xff;
1493 tq.d_id.b.domain = 0xff;
1494 tq.loop_id = (uint16_t)(CFG_IST(ha, CFG_CTRL_24258081) ?
1495 MANAGEMENT_SERVER_24XX_LOOP_ID :
1496 MANAGEMENT_SERVER_LOOP_ID);
1497 rval = ql_login_fport(ha, &tq, tq.loop_id, LFF_NO_PRLI, &mr);
1498 if (rval != QL_SUCCESS) {
1499 EL(ha, "failed, server login\n");
1500 cmd->Status = EXT_STATUS_DEV_NOT_FOUND;
1501 cmd->ResponseLen = 0;
1502 return;
1503 } else {
1504 xp->flags |= QL_MGMT_SERVER_LOGIN;
1505 }
1506 }
1507
1508 QL_PRINT_9(CE_CONT, "(%d): cmd\n", ha->instance);
1509 QL_DUMP_9(cmd, 8, sizeof (EXT_IOCTL));
1510
1511 /* Allocate a DMA Memory Descriptor */
1512 dma_mem = (dma_mem_t *)kmem_zalloc(sizeof (dma_mem_t), KM_SLEEP);
1513 if (dma_mem == NULL) {
1514 EL(ha, "failed, kmem_zalloc\n");
1515 cmd->Status = EXT_STATUS_NO_MEMORY;
1516 cmd->ResponseLen = 0;
1517 return;
1518 }
1519 /* Determine maximum buffer size. */
1520 if (cmd->RequestLen < cmd->ResponseLen) {
1521 pld_byte_cnt = cmd->ResponseLen;
1522 } else {
1523 pld_byte_cnt = cmd->RequestLen;
1524 }
1525
1526 /* Allocate command block. */
1527 pkt_size = (uint32_t)(sizeof (ql_mbx_iocb_t) + pld_byte_cnt);
1528 pkt = kmem_zalloc(pkt_size, KM_SLEEP);
1529 if (pkt == NULL) {
1530 EL(ha, "failed, kmem_zalloc\n");
1531 cmd->Status = EXT_STATUS_NO_MEMORY;
1532 cmd->ResponseLen = 0;
1533 return;
1534 }
1535 pld = (caddr_t)pkt + sizeof (ql_mbx_iocb_t);
1536
1537 /* Get command payload data. */
1538 if (ql_get_buffer_data((caddr_t)(uintptr_t)cmd->RequestAdr, pld,
1539 cmd->RequestLen, mode) != cmd->RequestLen) {
1540 EL(ha, "failed, get_buffer_data\n");
1541 kmem_free(pkt, pkt_size);
1542 cmd->Status = EXT_STATUS_COPY_ERR;
1543 cmd->ResponseLen = 0;
1544 return;
1545 }
1546
1547 /* Get DMA memory for the IOCB */
1548 if (ql_get_dma_mem(ha, dma_mem, pkt_size, LITTLE_ENDIAN_DMA,
1549 QL_DMA_RING_ALIGN) != QL_SUCCESS) {
1550 cmn_err(CE_WARN, "%s(%d): DMA memory "
1551 "alloc failed", QL_NAME, ha->instance);
1552 kmem_free(pkt, pkt_size);
1553 kmem_free(dma_mem, sizeof (dma_mem_t));
1554 cmd->Status = EXT_STATUS_MS_NO_RESPONSE;
1555 cmd->ResponseLen = 0;
1556 return;
1557 }
1558
1559 /* Copy out going payload data to IOCB DMA buffer. */
1560 ddi_rep_put8(dma_mem->acc_handle, (uint8_t *)pld,
1561 (uint8_t *)dma_mem->bp, pld_byte_cnt, DDI_DEV_AUTOINCR);
1562
1563 /* Sync IOCB DMA buffer. */
1564 (void) ddi_dma_sync(dma_mem->dma_handle, 0, pld_byte_cnt,
1565 DDI_DMA_SYNC_FORDEV);
1566
1567 /*
1568 * Setup IOCB
1569 */
1570 ct = (ql_ct_iu_preamble_t *)pld;
1571 if (CFG_IST(ha, CFG_CTRL_24258081)) {
1572 pkt->ms24.entry_type = CT_PASSTHRU_TYPE;
1573 pkt->ms24.entry_count = 1;
1574
1575 pkt->ms24.vp_index = ha->vp_index;
1576
1577 /* Set loop ID */
1578 pkt->ms24.n_port_hdl = (uint16_t)
1579 (ct->gs_type == GS_TYPE_DIR_SERVER ?
1580 LE_16(SNS_24XX_HDL) :
1581 LE_16(MANAGEMENT_SERVER_24XX_LOOP_ID));
1582
1583 /* Set ISP command timeout. */
1584 pkt->ms24.timeout = LE_16(120);
1585
1586 /* Set cmd/response data segment counts. */
1587 pkt->ms24.cmd_dseg_count = LE_16(1);
1588 pkt->ms24.resp_dseg_count = LE_16(1);
1589
1590 /* Load ct cmd byte count. */
1591 pkt->ms24.cmd_byte_count = LE_32(cmd->RequestLen);
1592
1593 /* Load ct rsp byte count. */
1594 pkt->ms24.resp_byte_count = LE_32(cmd->ResponseLen);
1595
1596 long_ptr = (uint32_t *)&pkt->ms24.dseg_0_address;
1597
1598 /* Load MS command entry data segments. */
1599 *long_ptr++ = (uint32_t)
1600 LE_32(LSD(dma_mem->cookie.dmac_laddress));
1601 *long_ptr++ = (uint32_t)
1602 LE_32(MSD(dma_mem->cookie.dmac_laddress));
1603 *long_ptr++ = (uint32_t)(LE_32(cmd->RequestLen));
1604
1605 /* Load MS response entry data segments. */
1606 *long_ptr++ = (uint32_t)
1607 LE_32(LSD(dma_mem->cookie.dmac_laddress));
1608 *long_ptr++ = (uint32_t)
1609 LE_32(MSD(dma_mem->cookie.dmac_laddress));
1610 *long_ptr = (uint32_t)LE_32(cmd->ResponseLen);
1611
1612 rval = ql_issue_mbx_iocb(ha, (caddr_t)pkt,
1613 sizeof (ql_mbx_iocb_t));
1614
1615 comp_status = (uint16_t)LE_16(pkt->sts24.comp_status);
1616 if (comp_status == CS_DATA_UNDERRUN) {
1617 if ((BE_16(ct->max_residual_size)) == 0) {
1618 comp_status = CS_COMPLETE;
1619 }
1620 }
1621
1622 if (rval != QL_SUCCESS || (pkt->sts24.entry_status & 0x3c) !=
1623 0) {
1624 EL(ha, "failed, I/O timeout or "
1625 "es=%xh, ss_l=%xh, rval=%xh\n",
1626 pkt->sts24.entry_status,
1627 pkt->sts24.scsi_status_l, rval);
1628 kmem_free(pkt, pkt_size);
1629 ql_free_dma_resource(ha, dma_mem);
1630 kmem_free(dma_mem, sizeof (dma_mem_t));
1631 cmd->Status = EXT_STATUS_MS_NO_RESPONSE;
1632 cmd->ResponseLen = 0;
1633 return;
1634 }
1635 } else {
1636 pkt->ms.entry_type = MS_TYPE;
1637 pkt->ms.entry_count = 1;
1638
1639 /* Set loop ID */
1640 loop_id = (uint16_t)(ct->gs_type == GS_TYPE_DIR_SERVER ?
1641 SIMPLE_NAME_SERVER_LOOP_ID : MANAGEMENT_SERVER_LOOP_ID);
1642 if (CFG_IST(ha, CFG_EXT_FW_INTERFACE)) {
1643 pkt->ms.loop_id_l = LSB(loop_id);
1644 pkt->ms.loop_id_h = MSB(loop_id);
1645 } else {
1646 pkt->ms.loop_id_h = LSB(loop_id);
1647 }
1648
1649 /* Set ISP command timeout. */
1650 pkt->ms.timeout = LE_16(120);
1651
1652 /* Set data segment counts. */
1653 pkt->ms.cmd_dseg_count_l = 1;
1654 pkt->ms.total_dseg_count = LE_16(2);
1655
1656 /* Response total byte count. */
1657 pkt->ms.resp_byte_count = LE_32(cmd->ResponseLen);
1658 pkt->ms.dseg_1_length = LE_32(cmd->ResponseLen);
1659
1660 /* Command total byte count. */
1661 pkt->ms.cmd_byte_count = LE_32(cmd->RequestLen);
1662 pkt->ms.dseg_0_length = LE_32(cmd->RequestLen);
1663
1664 /* Load command/response data segments. */
1665 pkt->ms.dseg_0_address[0] = (uint32_t)
1666 LE_32(LSD(dma_mem->cookie.dmac_laddress));
1667 pkt->ms.dseg_0_address[1] = (uint32_t)
1668 LE_32(MSD(dma_mem->cookie.dmac_laddress));
1669 pkt->ms.dseg_1_address[0] = (uint32_t)
1670 LE_32(LSD(dma_mem->cookie.dmac_laddress));
1671 pkt->ms.dseg_1_address[1] = (uint32_t)
1672 LE_32(MSD(dma_mem->cookie.dmac_laddress));
1673
1674 rval = ql_issue_mbx_iocb(ha, (caddr_t)pkt,
1675 sizeof (ql_mbx_iocb_t));
1676
1677 comp_status = (uint16_t)LE_16(pkt->sts.comp_status);
1678 if (comp_status == CS_DATA_UNDERRUN) {
1679 if ((BE_16(ct->max_residual_size)) == 0) {
1680 comp_status = CS_COMPLETE;
1681 }
1682 }
1683 if (rval != QL_SUCCESS || (pkt->sts.entry_status & 0x7e) != 0) {
1684 EL(ha, "failed, I/O timeout or "
1685 "es=%xh, rval=%xh\n", pkt->sts.entry_status, rval);
1686 kmem_free(pkt, pkt_size);
1687 ql_free_dma_resource(ha, dma_mem);
1688 kmem_free(dma_mem, sizeof (dma_mem_t));
1689 cmd->Status = EXT_STATUS_MS_NO_RESPONSE;
1690 cmd->ResponseLen = 0;
1691 return;
1692 }
1693 }
1694
1695 /* Sync in coming DMA buffer. */
1696 (void) ddi_dma_sync(dma_mem->dma_handle, 0,
1697 pld_byte_cnt, DDI_DMA_SYNC_FORKERNEL);
1698 /* Copy in coming DMA data. */
1699 ddi_rep_get8(dma_mem->acc_handle, (uint8_t *)pld,
1700 (uint8_t *)dma_mem->bp, pld_byte_cnt,
1701 DDI_DEV_AUTOINCR);
1702
1703 /* Copy response payload from DMA buffer to application. */
1704 if (cmd->ResponseLen != 0) {
1705 QL_PRINT_9(CE_CONT, "(%d): ResponseLen=%d\n", ha->instance,
1706 cmd->ResponseLen);
1707 QL_DUMP_9(pld, 8, cmd->ResponseLen);
1708
1709 /* Send response payload. */
1710 if (ql_send_buffer_data(pld,
1711 (caddr_t)(uintptr_t)cmd->ResponseAdr,
1712 cmd->ResponseLen, mode) != cmd->ResponseLen) {
1713 EL(ha, "failed, send_buffer_data\n");
1714 cmd->Status = EXT_STATUS_COPY_ERR;
1715 cmd->ResponseLen = 0;
1716 }
1717 }
1718
1719 kmem_free(pkt, pkt_size);
1720 ql_free_dma_resource(ha, dma_mem);
1721 kmem_free(dma_mem, sizeof (dma_mem_t));
1722
1723 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
1724 }
1725
1726 /*
1727 * ql_aen_reg
1728 * IOCTL management server Asynchronous Event Tracking Enable/Disable.
1729 *
1730 * Input:
1731 * ha: adapter state pointer.
1732 * cmd: EXT_IOCTL cmd struct pointer.
1733 * mode: flags.
1734 *
1735 * Returns:
1736 * None, request status indicated in cmd->Status.
1737 *
1738 * Context:
1739 * Kernel context.
1740 */
1741 static void
ql_aen_reg(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)1742 ql_aen_reg(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
1743 {
1744 EXT_REG_AEN reg_struct;
1745 int rval = 0;
1746 ql_xioctl_t *xp = ha->xioctl;
1747
1748 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
1749
1750 rval = ddi_copyin((void*)(uintptr_t)cmd->RequestAdr, ®_struct,
1751 cmd->RequestLen, mode);
1752
1753 if (rval == 0) {
1754 if (reg_struct.Enable) {
1755 xp->flags |= QL_AEN_TRACKING_ENABLE;
1756 } else {
1757 xp->flags &= ~QL_AEN_TRACKING_ENABLE;
1758 /* Empty the queue. */
1759 INTR_LOCK(ha);
1760 xp->aen_q_head = 0;
1761 xp->aen_q_tail = 0;
1762 INTR_UNLOCK(ha);
1763 }
1764 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
1765 } else {
1766 cmd->Status = EXT_STATUS_COPY_ERR;
1767 EL(ha, "failed, ddi_copyin\n");
1768 }
1769 }
1770
1771 /*
1772 * ql_aen_get
1773 * IOCTL management server Asynchronous Event Record Transfer.
1774 *
1775 * Input:
1776 * ha: adapter state pointer.
1777 * cmd: EXT_IOCTL cmd struct pointer.
1778 * mode: flags.
1779 *
1780 * Returns:
1781 * None, request status indicated in cmd->Status.
1782 *
1783 * Context:
1784 * Kernel context.
1785 */
1786 static void
ql_aen_get(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)1787 ql_aen_get(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
1788 {
1789 uint32_t out_size;
1790 EXT_ASYNC_EVENT *tmp_q;
1791 EXT_ASYNC_EVENT aen[EXT_DEF_MAX_AEN_QUEUE];
1792 uint8_t i;
1793 uint8_t queue_cnt;
1794 uint8_t request_cnt;
1795 ql_xioctl_t *xp = ha->xioctl;
1796
1797 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
1798
1799 /* Compute the number of events that can be returned */
1800 request_cnt = (uint8_t)(cmd->ResponseLen / sizeof (EXT_ASYNC_EVENT));
1801
1802 if (request_cnt < EXT_DEF_MAX_AEN_QUEUE) {
1803 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
1804 cmd->DetailStatus = EXT_DEF_MAX_AEN_QUEUE;
1805 EL(ha, "failed, request_cnt < EXT_DEF_MAX_AEN_QUEUE, "
1806 "Len=%xh\n", request_cnt);
1807 cmd->ResponseLen = 0;
1808 return;
1809 }
1810
1811 /* 1st: Make a local copy of the entire queue content. */
1812 tmp_q = (EXT_ASYNC_EVENT *)xp->aen_tracking_queue;
1813 queue_cnt = 0;
1814
1815 INTR_LOCK(ha);
1816 i = xp->aen_q_head;
1817
1818 for (; queue_cnt < EXT_DEF_MAX_AEN_QUEUE; ) {
1819 if (tmp_q[i].AsyncEventCode != 0) {
1820 bcopy(&tmp_q[i], &aen[queue_cnt],
1821 sizeof (EXT_ASYNC_EVENT));
1822 queue_cnt++;
1823 tmp_q[i].AsyncEventCode = 0; /* empty out the slot */
1824 }
1825 if (i == xp->aen_q_tail) {
1826 /* done. */
1827 break;
1828 }
1829 i++;
1830 if (i == EXT_DEF_MAX_AEN_QUEUE) {
1831 i = 0;
1832 }
1833 }
1834
1835 /* Empty the queue. */
1836 xp->aen_q_head = 0;
1837 xp->aen_q_tail = 0;
1838
1839 INTR_UNLOCK(ha);
1840
1841 /* 2nd: Now transfer the queue content to user buffer */
1842 /* Copy the entire queue to user's buffer. */
1843 out_size = (uint32_t)(queue_cnt * sizeof (EXT_ASYNC_EVENT));
1844 if (queue_cnt == 0) {
1845 cmd->ResponseLen = 0;
1846 } else if (ddi_copyout((void *)&aen[0],
1847 (void *)(uintptr_t)(cmd->ResponseAdr),
1848 out_size, mode) != 0) {
1849 cmd->Status = EXT_STATUS_COPY_ERR;
1850 cmd->ResponseLen = 0;
1851 EL(ha, "failed, ddi_copyout\n");
1852 } else {
1853 cmd->ResponseLen = out_size;
1854 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
1855 }
1856 }
1857
1858 /*
1859 * ql_enqueue_aen
1860 *
1861 * Input:
1862 * ha: adapter state pointer.
1863 * event_code: async event code of the event to add to queue.
1864 * payload: event payload for the queue.
1865 * INTR_LOCK must be already obtained.
1866 *
1867 * Context:
1868 * Interrupt or Kernel context, no mailbox commands allowed.
1869 */
1870 void
ql_enqueue_aen(ql_adapter_state_t * ha,uint16_t event_code,void * payload)1871 ql_enqueue_aen(ql_adapter_state_t *ha, uint16_t event_code, void *payload)
1872 {
1873 uint8_t new_entry; /* index to current entry */
1874 uint16_t *mbx;
1875 EXT_ASYNC_EVENT *aen_queue;
1876 ql_xioctl_t *xp = ha->xioctl;
1877
1878 QL_PRINT_9(CE_CONT, "(%d): started, event_code=%d\n", ha->instance,
1879 event_code);
1880
1881 if (xp == NULL) {
1882 QL_PRINT_9(CE_CONT, "(%d): no context\n", ha->instance);
1883 return;
1884 }
1885 aen_queue = (EXT_ASYNC_EVENT *)xp->aen_tracking_queue;
1886
1887 if (aen_queue[xp->aen_q_tail].AsyncEventCode != NULL) {
1888 /* Need to change queue pointers to make room. */
1889
1890 /* Increment tail for adding new entry. */
1891 xp->aen_q_tail++;
1892 if (xp->aen_q_tail == EXT_DEF_MAX_AEN_QUEUE) {
1893 xp->aen_q_tail = 0;
1894 }
1895 if (xp->aen_q_head == xp->aen_q_tail) {
1896 /*
1897 * We're overwriting the oldest entry, so need to
1898 * update the head pointer.
1899 */
1900 xp->aen_q_head++;
1901 if (xp->aen_q_head == EXT_DEF_MAX_AEN_QUEUE) {
1902 xp->aen_q_head = 0;
1903 }
1904 }
1905 }
1906
1907 new_entry = xp->aen_q_tail;
1908 aen_queue[new_entry].AsyncEventCode = event_code;
1909
1910 /* Update payload */
1911 if (payload != NULL) {
1912 switch (event_code) {
1913 case MBA_LIP_OCCURRED:
1914 case MBA_LOOP_UP:
1915 case MBA_LOOP_DOWN:
1916 case MBA_LIP_F8:
1917 case MBA_LIP_RESET:
1918 case MBA_PORT_UPDATE:
1919 break;
1920 case MBA_RSCN_UPDATE:
1921 mbx = (uint16_t *)payload;
1922 /* al_pa */
1923 aen_queue[new_entry].Payload.RSCN.RSCNInfo[0] =
1924 LSB(mbx[2]);
1925 /* area */
1926 aen_queue[new_entry].Payload.RSCN.RSCNInfo[1] =
1927 MSB(mbx[2]);
1928 /* domain */
1929 aen_queue[new_entry].Payload.RSCN.RSCNInfo[2] =
1930 LSB(mbx[1]);
1931 /* save in big endian */
1932 BIG_ENDIAN_24(&aen_queue[new_entry].
1933 Payload.RSCN.RSCNInfo[0]);
1934
1935 aen_queue[new_entry].Payload.RSCN.AddrFormat =
1936 MSB(mbx[1]);
1937
1938 break;
1939 default:
1940 /* Not supported */
1941 EL(ha, "failed, event code not supported=%xh\n",
1942 event_code);
1943 aen_queue[new_entry].AsyncEventCode = 0;
1944 break;
1945 }
1946 }
1947
1948 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
1949 }
1950
1951 /*
1952 * ql_scsi_passthru
1953 * IOCTL SCSI passthrough.
1954 *
1955 * Input:
1956 * ha: adapter state pointer.
1957 * cmd: User space SCSI command pointer.
1958 * mode: flags.
1959 *
1960 * Returns:
1961 * None, request status indicated in cmd->Status.
1962 *
1963 * Context:
1964 * Kernel context.
1965 */
1966 static void
ql_scsi_passthru(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)1967 ql_scsi_passthru(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
1968 {
1969 ql_mbx_iocb_t *pkt;
1970 ql_mbx_data_t mr;
1971 dma_mem_t *dma_mem;
1972 caddr_t pld;
1973 uint32_t pkt_size, pld_size;
1974 uint16_t qlnt, retries, cnt, cnt2;
1975 uint8_t *name;
1976 EXT_FC_SCSI_PASSTHRU *ufc_req;
1977 EXT_SCSI_PASSTHRU *usp_req;
1978 int rval;
1979 union _passthru {
1980 EXT_SCSI_PASSTHRU sp_cmd;
1981 EXT_FC_SCSI_PASSTHRU fc_cmd;
1982 } pt_req; /* Passthru request */
1983 uint32_t status, sense_sz = 0;
1984 ql_tgt_t *tq = NULL;
1985 EXT_SCSI_PASSTHRU *sp_req = &pt_req.sp_cmd;
1986 EXT_FC_SCSI_PASSTHRU *fc_req = &pt_req.fc_cmd;
1987
1988 /* SCSI request struct for SCSI passthrough IOs. */
1989 struct {
1990 uint16_t lun;
1991 uint16_t sense_length; /* Sense buffer size */
1992 size_t resid; /* Residual */
1993 uint8_t *cdbp; /* Requestor's CDB */
1994 uint8_t *u_sense; /* Requestor's sense buffer */
1995 uint8_t cdb_len; /* Requestor's CDB length */
1996 uint8_t direction;
1997 } scsi_req;
1998
1999 struct {
2000 uint8_t *rsp_info;
2001 uint8_t *req_sense_data;
2002 uint32_t residual_length;
2003 uint32_t rsp_info_length;
2004 uint32_t req_sense_length;
2005 uint16_t comp_status;
2006 uint8_t state_flags_l;
2007 uint8_t state_flags_h;
2008 uint8_t scsi_status_l;
2009 uint8_t scsi_status_h;
2010 } sts;
2011
2012 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
2013
2014 /* Verify Sub Code and set cnt to needed request size. */
2015 if (cmd->SubCode == EXT_SC_SEND_SCSI_PASSTHRU) {
2016 pld_size = sizeof (EXT_SCSI_PASSTHRU);
2017 } else if (cmd->SubCode == EXT_SC_SEND_FC_SCSI_PASSTHRU) {
2018 pld_size = sizeof (EXT_FC_SCSI_PASSTHRU);
2019 } else {
2020 EL(ha, "failed, invalid SubCode=%xh\n", cmd->SubCode);
2021 cmd->Status = EXT_STATUS_UNSUPPORTED_SUBCODE;
2022 cmd->ResponseLen = 0;
2023 return;
2024 }
2025
2026 dma_mem = (dma_mem_t *)kmem_zalloc(sizeof (dma_mem_t), KM_SLEEP);
2027 if (dma_mem == NULL) {
2028 EL(ha, "failed, kmem_zalloc\n");
2029 cmd->Status = EXT_STATUS_NO_MEMORY;
2030 cmd->ResponseLen = 0;
2031 return;
2032 }
2033 /* Verify the size of and copy in the passthru request structure. */
2034 if (cmd->RequestLen != pld_size) {
2035 /* Return error */
2036 EL(ha, "failed, RequestLen != cnt, is=%xh, expected=%xh\n",
2037 cmd->RequestLen, pld_size);
2038 cmd->Status = EXT_STATUS_INVALID_PARAM;
2039 cmd->DetailStatus = EXT_DSTATUS_REQUEST_LEN;
2040 cmd->ResponseLen = 0;
2041 return;
2042 }
2043
2044 if (ddi_copyin((void *)(uintptr_t)cmd->RequestAdr, &pt_req,
2045 pld_size, mode) != 0) {
2046 EL(ha, "failed, ddi_copyin\n");
2047 cmd->Status = EXT_STATUS_COPY_ERR;
2048 cmd->ResponseLen = 0;
2049 return;
2050 }
2051
2052 /*
2053 * Find fc_port from SCSI PASSTHRU structure fill in the scsi_req
2054 * request data structure.
2055 */
2056 if (cmd->SubCode == EXT_SC_SEND_SCSI_PASSTHRU) {
2057 scsi_req.lun = sp_req->TargetAddr.Lun;
2058 scsi_req.sense_length = sizeof (sp_req->SenseData);
2059 scsi_req.cdbp = &sp_req->Cdb[0];
2060 scsi_req.cdb_len = sp_req->CdbLength;
2061 scsi_req.direction = sp_req->Direction;
2062 usp_req = (EXT_SCSI_PASSTHRU *)(uintptr_t)cmd->RequestAdr;
2063 scsi_req.u_sense = &usp_req->SenseData[0];
2064 cmd->DetailStatus = EXT_DSTATUS_TARGET;
2065
2066 qlnt = QLNT_PORT;
2067 name = (uint8_t *)&sp_req->TargetAddr.Target;
2068 QL_PRINT_9(CE_CONT, "(%d): SubCode=%xh, Target=%lld\n",
2069 ha->instance, cmd->SubCode, sp_req->TargetAddr.Target);
2070 tq = ql_find_port(ha, name, qlnt);
2071 } else {
2072 /*
2073 * Must be FC PASSTHRU, verified above.
2074 */
2075 if (fc_req->FCScsiAddr.DestType == EXT_DEF_DESTTYPE_WWPN) {
2076 qlnt = QLNT_PORT;
2077 name = &fc_req->FCScsiAddr.DestAddr.WWPN[0];
2078 QL_PRINT_9(CE_CONT, "(%d): SubCode=%xh, "
2079 "wwpn=%02x%02x%02x%02x%02x%02x%02x%02x\n",
2080 ha->instance, cmd->SubCode, name[0], name[1],
2081 name[2], name[3], name[4], name[5], name[6],
2082 name[7]);
2083 tq = ql_find_port(ha, name, qlnt);
2084 } else if (fc_req->FCScsiAddr.DestType ==
2085 EXT_DEF_DESTTYPE_WWNN) {
2086 qlnt = QLNT_NODE;
2087 name = &fc_req->FCScsiAddr.DestAddr.WWNN[0];
2088 QL_PRINT_9(CE_CONT, "(%d): SubCode=%xh, "
2089 "wwnn=%02x%02x%02x%02x%02x%02x%02x%02x\n",
2090 ha->instance, cmd->SubCode, name[0], name[1],
2091 name[2], name[3], name[4], name[5], name[6],
2092 name[7]);
2093 tq = ql_find_port(ha, name, qlnt);
2094 } else if (fc_req->FCScsiAddr.DestType ==
2095 EXT_DEF_DESTTYPE_PORTID) {
2096 qlnt = QLNT_PID;
2097 name = &fc_req->FCScsiAddr.DestAddr.Id[0];
2098 QL_PRINT_9(CE_CONT, "(%d): SubCode=%xh, PID="
2099 "%02x%02x%02x\n", ha->instance, cmd->SubCode,
2100 name[0], name[1], name[2]);
2101 tq = ql_find_port(ha, name, qlnt);
2102 } else {
2103 EL(ha, "failed, SubCode=%xh invalid DestType=%xh\n",
2104 cmd->SubCode, fc_req->FCScsiAddr.DestType);
2105 cmd->Status = EXT_STATUS_INVALID_PARAM;
2106 cmd->ResponseLen = 0;
2107 return;
2108 }
2109 scsi_req.lun = fc_req->FCScsiAddr.Lun;
2110 scsi_req.sense_length = sizeof (fc_req->SenseData);
2111 scsi_req.cdbp = &sp_req->Cdb[0];
2112 scsi_req.cdb_len = sp_req->CdbLength;
2113 ufc_req = (EXT_FC_SCSI_PASSTHRU *)(uintptr_t)cmd->RequestAdr;
2114 scsi_req.u_sense = &ufc_req->SenseData[0];
2115 scsi_req.direction = fc_req->Direction;
2116 }
2117
2118 if (tq == NULL || !VALID_TARGET_ID(ha, tq->loop_id)) {
2119 EL(ha, "failed, fc_port not found\n");
2120 cmd->Status = EXT_STATUS_DEV_NOT_FOUND;
2121 cmd->ResponseLen = 0;
2122 return;
2123 }
2124
2125 if (tq->flags & TQF_NEED_AUTHENTICATION) {
2126 EL(ha, "target not available; loopid=%xh\n", tq->loop_id);
2127 cmd->Status = EXT_STATUS_DEVICE_OFFLINE;
2128 cmd->ResponseLen = 0;
2129 return;
2130 }
2131
2132 /* Allocate command block. */
2133 if ((scsi_req.direction == EXT_DEF_SCSI_PASSTHRU_DATA_IN ||
2134 scsi_req.direction == EXT_DEF_SCSI_PASSTHRU_DATA_OUT) &&
2135 cmd->ResponseLen) {
2136 pld_size = cmd->ResponseLen;
2137 pkt_size = (uint32_t)(sizeof (ql_mbx_iocb_t) + pld_size);
2138 pkt = kmem_zalloc(pkt_size, KM_SLEEP);
2139 if (pkt == NULL) {
2140 EL(ha, "failed, kmem_zalloc\n");
2141 cmd->Status = EXT_STATUS_NO_MEMORY;
2142 cmd->ResponseLen = 0;
2143 return;
2144 }
2145 pld = (caddr_t)pkt + sizeof (ql_mbx_iocb_t);
2146
2147 /* Get DMA memory for the IOCB */
2148 if (ql_get_dma_mem(ha, dma_mem, pld_size, LITTLE_ENDIAN_DMA,
2149 QL_DMA_DATA_ALIGN) != QL_SUCCESS) {
2150 cmn_err(CE_WARN, "%s(%d): request queue DMA memory "
2151 "alloc failed", QL_NAME, ha->instance);
2152 kmem_free(pkt, pkt_size);
2153 cmd->Status = EXT_STATUS_MS_NO_RESPONSE;
2154 cmd->ResponseLen = 0;
2155 return;
2156 }
2157
2158 if (scsi_req.direction == EXT_DEF_SCSI_PASSTHRU_DATA_IN) {
2159 scsi_req.direction = (uint8_t)
2160 (CFG_IST(ha, CFG_CTRL_24258081) ?
2161 CF_RD : CF_DATA_IN | CF_STAG);
2162 } else {
2163 scsi_req.direction = (uint8_t)
2164 (CFG_IST(ha, CFG_CTRL_24258081) ?
2165 CF_WR : CF_DATA_OUT | CF_STAG);
2166 cmd->ResponseLen = 0;
2167
2168 /* Get command payload. */
2169 if (ql_get_buffer_data(
2170 (caddr_t)(uintptr_t)cmd->ResponseAdr,
2171 pld, pld_size, mode) != pld_size) {
2172 EL(ha, "failed, get_buffer_data\n");
2173 cmd->Status = EXT_STATUS_COPY_ERR;
2174
2175 kmem_free(pkt, pkt_size);
2176 ql_free_dma_resource(ha, dma_mem);
2177 kmem_free(dma_mem, sizeof (dma_mem_t));
2178 return;
2179 }
2180
2181 /* Copy out going data to DMA buffer. */
2182 ddi_rep_put8(dma_mem->acc_handle, (uint8_t *)pld,
2183 (uint8_t *)dma_mem->bp, pld_size,
2184 DDI_DEV_AUTOINCR);
2185
2186 /* Sync DMA buffer. */
2187 (void) ddi_dma_sync(dma_mem->dma_handle, 0,
2188 dma_mem->size, DDI_DMA_SYNC_FORDEV);
2189 }
2190 } else {
2191 scsi_req.direction = (uint8_t)
2192 (CFG_IST(ha, CFG_CTRL_24258081) ? 0 : CF_STAG);
2193 cmd->ResponseLen = 0;
2194
2195 pkt_size = sizeof (ql_mbx_iocb_t);
2196 pkt = kmem_zalloc(pkt_size, KM_SLEEP);
2197 if (pkt == NULL) {
2198 EL(ha, "failed, kmem_zalloc-2\n");
2199 cmd->Status = EXT_STATUS_NO_MEMORY;
2200 return;
2201 }
2202 pld = NULL;
2203 pld_size = 0;
2204 }
2205
2206 /* retries = ha->port_down_retry_count; */
2207 retries = 1;
2208 cmd->Status = EXT_STATUS_OK;
2209 cmd->DetailStatus = EXT_DSTATUS_NOADNL_INFO;
2210
2211 QL_PRINT_9(CE_CONT, "(%d): SCSI cdb\n", ha->instance);
2212 QL_DUMP_9(scsi_req.cdbp, 8, scsi_req.cdb_len);
2213
2214 do {
2215 if (DRIVER_SUSPENDED(ha)) {
2216 sts.comp_status = CS_LOOP_DOWN_ABORT;
2217 break;
2218 }
2219
2220 if (CFG_IST(ha, CFG_CTRL_24258081)) {
2221 pkt->cmd24.entry_type = IOCB_CMD_TYPE_7;
2222 pkt->cmd24.entry_count = 1;
2223
2224 /* Set LUN number */
2225 pkt->cmd24.fcp_lun[2] = LSB(scsi_req.lun);
2226 pkt->cmd24.fcp_lun[3] = MSB(scsi_req.lun);
2227
2228 /* Set N_port handle */
2229 pkt->cmd24.n_port_hdl = (uint16_t)LE_16(tq->loop_id);
2230
2231 /* Set VP Index */
2232 pkt->cmd24.vp_index = ha->vp_index;
2233
2234 /* Set target ID */
2235 pkt->cmd24.target_id[0] = tq->d_id.b.al_pa;
2236 pkt->cmd24.target_id[1] = tq->d_id.b.area;
2237 pkt->cmd24.target_id[2] = tq->d_id.b.domain;
2238
2239 /* Set ISP command timeout. */
2240 pkt->cmd24.timeout = (uint16_t)LE_16(15);
2241
2242 /* Load SCSI CDB */
2243 ddi_rep_put8(ha->hba_buf.acc_handle, scsi_req.cdbp,
2244 pkt->cmd24.scsi_cdb, scsi_req.cdb_len,
2245 DDI_DEV_AUTOINCR);
2246 for (cnt = 0; cnt < MAX_CMDSZ;
2247 cnt = (uint16_t)(cnt + 4)) {
2248 ql_chg_endian((uint8_t *)&pkt->cmd24.scsi_cdb
2249 + cnt, 4);
2250 }
2251
2252 /* Set tag queue control flags */
2253 pkt->cmd24.task = TA_STAG;
2254
2255 if (pld_size) {
2256 /* Set transfer direction. */
2257 pkt->cmd24.control_flags = scsi_req.direction;
2258
2259 /* Set data segment count. */
2260 pkt->cmd24.dseg_count = LE_16(1);
2261
2262 /* Load total byte count. */
2263 pkt->cmd24.total_byte_count = LE_32(pld_size);
2264
2265 /* Load data descriptor. */
2266 pkt->cmd24.dseg_0_address[0] = (uint32_t)
2267 LE_32(LSD(dma_mem->cookie.dmac_laddress));
2268 pkt->cmd24.dseg_0_address[1] = (uint32_t)
2269 LE_32(MSD(dma_mem->cookie.dmac_laddress));
2270 pkt->cmd24.dseg_0_length = LE_32(pld_size);
2271 }
2272 } else if (CFG_IST(ha, CFG_ENABLE_64BIT_ADDRESSING)) {
2273 pkt->cmd3.entry_type = IOCB_CMD_TYPE_3;
2274 pkt->cmd3.entry_count = 1;
2275 if (CFG_IST(ha, CFG_EXT_FW_INTERFACE)) {
2276 pkt->cmd3.target_l = LSB(tq->loop_id);
2277 pkt->cmd3.target_h = MSB(tq->loop_id);
2278 } else {
2279 pkt->cmd3.target_h = LSB(tq->loop_id);
2280 }
2281 pkt->cmd3.lun_l = LSB(scsi_req.lun);
2282 pkt->cmd3.lun_h = MSB(scsi_req.lun);
2283 pkt->cmd3.control_flags_l = scsi_req.direction;
2284 pkt->cmd3.timeout = LE_16(15);
2285 for (cnt = 0; cnt < scsi_req.cdb_len; cnt++) {
2286 pkt->cmd3.scsi_cdb[cnt] = scsi_req.cdbp[cnt];
2287 }
2288 if (pld_size) {
2289 pkt->cmd3.dseg_count = LE_16(1);
2290 pkt->cmd3.byte_count = LE_32(pld_size);
2291 pkt->cmd3.dseg_0_address[0] = (uint32_t)
2292 LE_32(LSD(dma_mem->cookie.dmac_laddress));
2293 pkt->cmd3.dseg_0_address[1] = (uint32_t)
2294 LE_32(MSD(dma_mem->cookie.dmac_laddress));
2295 pkt->cmd3.dseg_0_length = LE_32(pld_size);
2296 }
2297 } else {
2298 pkt->cmd.entry_type = IOCB_CMD_TYPE_2;
2299 pkt->cmd.entry_count = 1;
2300 if (CFG_IST(ha, CFG_EXT_FW_INTERFACE)) {
2301 pkt->cmd.target_l = LSB(tq->loop_id);
2302 pkt->cmd.target_h = MSB(tq->loop_id);
2303 } else {
2304 pkt->cmd.target_h = LSB(tq->loop_id);
2305 }
2306 pkt->cmd.lun_l = LSB(scsi_req.lun);
2307 pkt->cmd.lun_h = MSB(scsi_req.lun);
2308 pkt->cmd.control_flags_l = scsi_req.direction;
2309 pkt->cmd.timeout = LE_16(15);
2310 for (cnt = 0; cnt < scsi_req.cdb_len; cnt++) {
2311 pkt->cmd.scsi_cdb[cnt] = scsi_req.cdbp[cnt];
2312 }
2313 if (pld_size) {
2314 pkt->cmd.dseg_count = LE_16(1);
2315 pkt->cmd.byte_count = LE_32(pld_size);
2316 pkt->cmd.dseg_0_address = (uint32_t)
2317 LE_32(LSD(dma_mem->cookie.dmac_laddress));
2318 pkt->cmd.dseg_0_length = LE_32(pld_size);
2319 }
2320 }
2321 /* Go issue command and wait for completion. */
2322 QL_PRINT_9(CE_CONT, "(%d): request pkt\n", ha->instance);
2323 QL_DUMP_9(pkt, 8, pkt_size);
2324
2325 status = ql_issue_mbx_iocb(ha, (caddr_t)pkt, pkt_size);
2326
2327 if (pld_size) {
2328 /* Sync in coming DMA buffer. */
2329 (void) ddi_dma_sync(dma_mem->dma_handle, 0,
2330 dma_mem->size, DDI_DMA_SYNC_FORKERNEL);
2331 /* Copy in coming DMA data. */
2332 ddi_rep_get8(dma_mem->acc_handle, (uint8_t *)pld,
2333 (uint8_t *)dma_mem->bp, pld_size,
2334 DDI_DEV_AUTOINCR);
2335 }
2336
2337 if (CFG_IST(ha, CFG_CTRL_24258081)) {
2338 pkt->sts24.entry_status = (uint8_t)
2339 (pkt->sts24.entry_status & 0x3c);
2340 } else {
2341 pkt->sts.entry_status = (uint8_t)
2342 (pkt->sts.entry_status & 0x7e);
2343 }
2344
2345 if (status == QL_SUCCESS && pkt->sts.entry_status != 0) {
2346 EL(ha, "failed, entry_status=%xh, d_id=%xh\n",
2347 pkt->sts.entry_status, tq->d_id.b24);
2348 status = QL_FUNCTION_PARAMETER_ERROR;
2349 }
2350
2351 sts.comp_status = (uint16_t)(CFG_IST(ha, CFG_CTRL_24258081) ?
2352 LE_16(pkt->sts24.comp_status) :
2353 LE_16(pkt->sts.comp_status));
2354
2355 /*
2356 * We have verified about all the request that can be so far.
2357 * Now we need to start verification of our ability to
2358 * actually issue the CDB.
2359 */
2360 if (DRIVER_SUSPENDED(ha)) {
2361 sts.comp_status = CS_LOOP_DOWN_ABORT;
2362 break;
2363 } else if (status == QL_SUCCESS &&
2364 (sts.comp_status == CS_PORT_LOGGED_OUT ||
2365 sts.comp_status == CS_PORT_UNAVAILABLE)) {
2366 EL(ha, "login retry d_id=%xh\n", tq->d_id.b24);
2367 if (tq->flags & TQF_FABRIC_DEVICE) {
2368 rval = ql_login_fport(ha, tq, tq->loop_id,
2369 LFF_NO_PLOGI, &mr);
2370 if (rval != QL_SUCCESS) {
2371 EL(ha, "failed, login_fport=%xh, "
2372 "d_id=%xh\n", rval, tq->d_id.b24);
2373 }
2374 } else {
2375 rval = ql_login_lport(ha, tq, tq->loop_id,
2376 LLF_NONE);
2377 if (rval != QL_SUCCESS) {
2378 EL(ha, "failed, login_lport=%xh, "
2379 "d_id=%xh\n", rval, tq->d_id.b24);
2380 }
2381 }
2382 } else {
2383 break;
2384 }
2385
2386 bzero((caddr_t)pkt, sizeof (ql_mbx_iocb_t));
2387
2388 } while (retries--);
2389
2390 if (sts.comp_status == CS_LOOP_DOWN_ABORT) {
2391 /* Cannot issue command now, maybe later */
2392 EL(ha, "failed, suspended\n");
2393 kmem_free(pkt, pkt_size);
2394 ql_free_dma_resource(ha, dma_mem);
2395 kmem_free(dma_mem, sizeof (dma_mem_t));
2396 cmd->Status = EXT_STATUS_SUSPENDED;
2397 cmd->ResponseLen = 0;
2398 return;
2399 }
2400
2401 if (status != QL_SUCCESS) {
2402 /* Command error */
2403 EL(ha, "failed, I/O\n");
2404 kmem_free(pkt, pkt_size);
2405 ql_free_dma_resource(ha, dma_mem);
2406 kmem_free(dma_mem, sizeof (dma_mem_t));
2407 cmd->Status = EXT_STATUS_ERR;
2408 cmd->DetailStatus = status;
2409 cmd->ResponseLen = 0;
2410 return;
2411 }
2412
2413 /* Setup status. */
2414 if (CFG_IST(ha, CFG_CTRL_24258081)) {
2415 sts.scsi_status_l = pkt->sts24.scsi_status_l;
2416 sts.scsi_status_h = pkt->sts24.scsi_status_h;
2417
2418 /* Setup residuals. */
2419 sts.residual_length = LE_32(pkt->sts24.residual_length);
2420
2421 /* Setup state flags. */
2422 sts.state_flags_l = pkt->sts24.state_flags_l;
2423 sts.state_flags_h = pkt->sts24.state_flags_h;
2424 if (pld_size && sts.comp_status != CS_DATA_UNDERRUN) {
2425 sts.state_flags_h = (uint8_t)(sts.state_flags_h |
2426 SF_GOT_BUS | SF_GOT_TARGET | SF_SENT_CMD |
2427 SF_XFERRED_DATA | SF_GOT_STATUS);
2428 } else {
2429 sts.state_flags_h = (uint8_t)(sts.state_flags_h |
2430 SF_GOT_BUS | SF_GOT_TARGET | SF_SENT_CMD |
2431 SF_GOT_STATUS);
2432 }
2433 if (scsi_req.direction & CF_WR) {
2434 sts.state_flags_l = (uint8_t)(sts.state_flags_l |
2435 SF_DATA_OUT);
2436 } else if (scsi_req.direction & CF_RD) {
2437 sts.state_flags_l = (uint8_t)(sts.state_flags_l |
2438 SF_DATA_IN);
2439 }
2440 sts.state_flags_l = (uint8_t)(sts.state_flags_l | SF_SIMPLE_Q);
2441
2442 /* Setup FCP response info. */
2443 sts.rsp_info_length = sts.scsi_status_h & FCP_RSP_LEN_VALID ?
2444 LE_32(pkt->sts24.fcp_rsp_data_length) : 0;
2445 sts.rsp_info = &pkt->sts24.rsp_sense_data[0];
2446 for (cnt = 0; cnt < sts.rsp_info_length;
2447 cnt = (uint16_t)(cnt + 4)) {
2448 ql_chg_endian(sts.rsp_info + cnt, 4);
2449 }
2450
2451 /* Setup sense data. */
2452 if (sts.scsi_status_h & FCP_SNS_LEN_VALID) {
2453 sts.req_sense_length =
2454 LE_32(pkt->sts24.fcp_sense_length);
2455 sts.state_flags_h = (uint8_t)(sts.state_flags_h |
2456 SF_ARQ_DONE);
2457 } else {
2458 sts.req_sense_length = 0;
2459 }
2460 sts.req_sense_data =
2461 &pkt->sts24.rsp_sense_data[sts.rsp_info_length];
2462 cnt2 = (uint16_t)(((uintptr_t)pkt + sizeof (sts_24xx_entry_t)) -
2463 (uintptr_t)sts.req_sense_data);
2464 for (cnt = 0; cnt < cnt2; cnt = (uint16_t)(cnt + 4)) {
2465 ql_chg_endian(sts.req_sense_data + cnt, 4);
2466 }
2467 } else {
2468 sts.scsi_status_l = pkt->sts.scsi_status_l;
2469 sts.scsi_status_h = pkt->sts.scsi_status_h;
2470
2471 /* Setup residuals. */
2472 sts.residual_length = LE_32(pkt->sts.residual_length);
2473
2474 /* Setup state flags. */
2475 sts.state_flags_l = pkt->sts.state_flags_l;
2476 sts.state_flags_h = pkt->sts.state_flags_h;
2477
2478 /* Setup FCP response info. */
2479 sts.rsp_info_length = sts.scsi_status_h & FCP_RSP_LEN_VALID ?
2480 LE_16(pkt->sts.rsp_info_length) : 0;
2481 sts.rsp_info = &pkt->sts.rsp_info[0];
2482
2483 /* Setup sense data. */
2484 sts.req_sense_length = sts.scsi_status_h & FCP_SNS_LEN_VALID ?
2485 LE_16(pkt->sts.req_sense_length) : 0;
2486 sts.req_sense_data = &pkt->sts.req_sense_data[0];
2487 }
2488
2489 QL_PRINT_9(CE_CONT, "(%d): response pkt\n", ha->instance);
2490 QL_DUMP_9(&pkt->sts, 8, sizeof (sts_entry_t));
2491
2492 switch (sts.comp_status) {
2493 case CS_INCOMPLETE:
2494 case CS_ABORTED:
2495 case CS_DEVICE_UNAVAILABLE:
2496 case CS_PORT_UNAVAILABLE:
2497 case CS_PORT_LOGGED_OUT:
2498 case CS_PORT_CONFIG_CHG:
2499 case CS_PORT_BUSY:
2500 case CS_LOOP_DOWN_ABORT:
2501 cmd->Status = EXT_STATUS_BUSY;
2502 break;
2503 case CS_RESET:
2504 case CS_QUEUE_FULL:
2505 cmd->Status = EXT_STATUS_ERR;
2506 break;
2507 case CS_TIMEOUT:
2508 cmd->Status = EXT_STATUS_ERR;
2509 break;
2510 case CS_DATA_OVERRUN:
2511 cmd->Status = EXT_STATUS_DATA_OVERRUN;
2512 break;
2513 case CS_DATA_UNDERRUN:
2514 cmd->Status = EXT_STATUS_DATA_UNDERRUN;
2515 break;
2516 }
2517
2518 /*
2519 * If non data transfer commands fix tranfer counts.
2520 */
2521 if (scsi_req.cdbp[0] == SCMD_TEST_UNIT_READY ||
2522 scsi_req.cdbp[0] == SCMD_REZERO_UNIT ||
2523 scsi_req.cdbp[0] == SCMD_SEEK ||
2524 scsi_req.cdbp[0] == SCMD_SEEK_G1 ||
2525 scsi_req.cdbp[0] == SCMD_RESERVE ||
2526 scsi_req.cdbp[0] == SCMD_RELEASE ||
2527 scsi_req.cdbp[0] == SCMD_START_STOP ||
2528 scsi_req.cdbp[0] == SCMD_DOORLOCK ||
2529 scsi_req.cdbp[0] == SCMD_VERIFY ||
2530 scsi_req.cdbp[0] == SCMD_WRITE_FILE_MARK ||
2531 scsi_req.cdbp[0] == SCMD_VERIFY_G0 ||
2532 scsi_req.cdbp[0] == SCMD_SPACE ||
2533 scsi_req.cdbp[0] == SCMD_ERASE ||
2534 (scsi_req.cdbp[0] == SCMD_FORMAT &&
2535 (scsi_req.cdbp[1] & FPB_DATA) == 0)) {
2536 /*
2537 * Non data transfer command, clear sts_entry residual
2538 * length.
2539 */
2540 sts.residual_length = 0;
2541 cmd->ResponseLen = 0;
2542 if (sts.comp_status == CS_DATA_UNDERRUN) {
2543 sts.comp_status = CS_COMPLETE;
2544 cmd->Status = EXT_STATUS_OK;
2545 }
2546 } else {
2547 cmd->ResponseLen = pld_size;
2548 }
2549
2550 /* Correct ISP completion status */
2551 if (sts.comp_status == CS_COMPLETE && sts.scsi_status_l == 0 &&
2552 (sts.scsi_status_h & FCP_RSP_MASK) == 0) {
2553 QL_PRINT_9(CE_CONT, "(%d): Correct completion\n",
2554 ha->instance);
2555 scsi_req.resid = 0;
2556 } else if (sts.comp_status == CS_DATA_UNDERRUN) {
2557 QL_PRINT_9(CE_CONT, "(%d): Correct UNDERRUN\n",
2558 ha->instance);
2559 scsi_req.resid = sts.residual_length;
2560 if (sts.scsi_status_h & FCP_RESID_UNDER) {
2561 cmd->Status = (uint32_t)EXT_STATUS_OK;
2562
2563 cmd->ResponseLen = (uint32_t)
2564 (pld_size - scsi_req.resid);
2565 } else {
2566 EL(ha, "failed, Transfer ERROR\n");
2567 cmd->Status = EXT_STATUS_ERR;
2568 cmd->ResponseLen = 0;
2569 }
2570 } else {
2571 QL_PRINT_9(CE_CONT, "(%d): error d_id=%xh, comp_status=%xh, "
2572 "scsi_status_h=%xh, scsi_status_l=%xh\n", ha->instance,
2573 tq->d_id.b24, sts.comp_status, sts.scsi_status_h,
2574 sts.scsi_status_l);
2575
2576 scsi_req.resid = pld_size;
2577 /*
2578 * Handle residual count on SCSI check
2579 * condition.
2580 *
2581 * - If Residual Under / Over is set, use the
2582 * Residual Transfer Length field in IOCB.
2583 * - If Residual Under / Over is not set, and
2584 * Transferred Data bit is set in State Flags
2585 * field of IOCB, report residual value of 0
2586 * (you may want to do this for tape
2587 * Write-type commands only). This takes care
2588 * of logical end of tape problem and does
2589 * not break Unit Attention.
2590 * - If Residual Under / Over is not set, and
2591 * Transferred Data bit is not set in State
2592 * Flags, report residual value equal to
2593 * original data transfer length.
2594 */
2595 if (sts.scsi_status_l & STATUS_CHECK) {
2596 cmd->Status = EXT_STATUS_SCSI_STATUS;
2597 cmd->DetailStatus = sts.scsi_status_l;
2598 if (sts.scsi_status_h &
2599 (FCP_RESID_OVER | FCP_RESID_UNDER)) {
2600 scsi_req.resid = sts.residual_length;
2601 } else if (sts.state_flags_h &
2602 STATE_XFERRED_DATA) {
2603 scsi_req.resid = 0;
2604 }
2605 }
2606 }
2607
2608 if (sts.scsi_status_l & STATUS_CHECK &&
2609 sts.scsi_status_h & FCP_SNS_LEN_VALID &&
2610 sts.req_sense_length) {
2611 /*
2612 * Check condition with vaild sense data flag set and sense
2613 * length != 0
2614 */
2615 if (sts.req_sense_length > scsi_req.sense_length) {
2616 sense_sz = scsi_req.sense_length;
2617 } else {
2618 sense_sz = sts.req_sense_length;
2619 }
2620
2621 EL(ha, "failed, Check Condition Status, d_id=%xh\n",
2622 tq->d_id.b24);
2623 QL_DUMP_2(sts.req_sense_data, 8, sts.req_sense_length);
2624
2625 if (ddi_copyout(sts.req_sense_data, scsi_req.u_sense,
2626 (size_t)sense_sz, mode) != 0) {
2627 EL(ha, "failed, request sense ddi_copyout\n");
2628 }
2629
2630 cmd->Status = EXT_STATUS_SCSI_STATUS;
2631 cmd->DetailStatus = sts.scsi_status_l;
2632 }
2633
2634 /* Copy response payload from DMA buffer to application. */
2635 if (scsi_req.direction & (CF_RD | CF_DATA_IN) &&
2636 cmd->ResponseLen != 0) {
2637 QL_PRINT_9(CE_CONT, "(%d): Data Return resid=%lu, "
2638 "byte_count=%u, ResponseLen=%xh\n", ha->instance,
2639 scsi_req.resid, pld_size, cmd->ResponseLen);
2640 QL_DUMP_9(pld, 8, cmd->ResponseLen);
2641
2642 /* Send response payload. */
2643 if (ql_send_buffer_data(pld,
2644 (caddr_t)(uintptr_t)cmd->ResponseAdr,
2645 cmd->ResponseLen, mode) != cmd->ResponseLen) {
2646 EL(ha, "failed, send_buffer_data\n");
2647 cmd->Status = EXT_STATUS_COPY_ERR;
2648 cmd->ResponseLen = 0;
2649 }
2650 }
2651
2652 if (cmd->Status != EXT_STATUS_OK) {
2653 EL(ha, "failed, cmd->Status=%xh, comp_status=%xh, "
2654 "d_id=%xh\n", cmd->Status, sts.comp_status, tq->d_id.b24);
2655 } else {
2656 /*EMPTY*/
2657 QL_PRINT_9(CE_CONT, "(%d): done, ResponseLen=%d\n",
2658 ha->instance, cmd->ResponseLen);
2659 }
2660
2661 kmem_free(pkt, pkt_size);
2662 ql_free_dma_resource(ha, dma_mem);
2663 kmem_free(dma_mem, sizeof (dma_mem_t));
2664 }
2665
2666 /*
2667 * ql_wwpn_to_scsiaddr
2668 *
2669 * Input:
2670 * ha: adapter state pointer.
2671 * cmd: EXT_IOCTL cmd struct pointer.
2672 * mode: flags.
2673 *
2674 * Context:
2675 * Kernel context.
2676 */
2677 static void
ql_wwpn_to_scsiaddr(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)2678 ql_wwpn_to_scsiaddr(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
2679 {
2680 int status;
2681 uint8_t wwpn[EXT_DEF_WWN_NAME_SIZE];
2682 EXT_SCSI_ADDR *tmp_addr;
2683 ql_tgt_t *tq;
2684
2685 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
2686
2687 if (cmd->RequestLen != EXT_DEF_WWN_NAME_SIZE) {
2688 /* Return error */
2689 EL(ha, "incorrect RequestLen\n");
2690 cmd->Status = EXT_STATUS_INVALID_PARAM;
2691 cmd->DetailStatus = EXT_DSTATUS_REQUEST_LEN;
2692 return;
2693 }
2694
2695 status = ddi_copyin((void*)(uintptr_t)cmd->RequestAdr, wwpn,
2696 cmd->RequestLen, mode);
2697
2698 if (status != 0) {
2699 cmd->Status = EXT_STATUS_COPY_ERR;
2700 EL(ha, "failed, ddi_copyin\n");
2701 return;
2702 }
2703
2704 tq = ql_find_port(ha, wwpn, QLNT_PORT);
2705
2706 if (tq == NULL || tq->flags & TQF_INITIATOR_DEVICE) {
2707 /* no matching device */
2708 cmd->Status = EXT_STATUS_DEV_NOT_FOUND;
2709 EL(ha, "failed, device not found\n");
2710 return;
2711 }
2712
2713 /* Copy out the IDs found. For now we can only return target ID. */
2714 tmp_addr = (EXT_SCSI_ADDR *)(uintptr_t)cmd->ResponseAdr;
2715
2716 status = ddi_copyout((void *)wwpn, (void *)&tmp_addr->Target, 8, mode);
2717
2718 if (status != 0) {
2719 cmd->Status = EXT_STATUS_COPY_ERR;
2720 EL(ha, "failed, ddi_copyout\n");
2721 } else {
2722 cmd->Status = EXT_STATUS_OK;
2723 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
2724 }
2725 }
2726
2727 /*
2728 * ql_host_idx
2729 * Gets host order index.
2730 *
2731 * Input:
2732 * ha: adapter state pointer.
2733 * cmd: EXT_IOCTL cmd struct pointer.
2734 * mode: flags.
2735 *
2736 * Returns:
2737 * None, request status indicated in cmd->Status.
2738 *
2739 * Context:
2740 * Kernel context.
2741 */
2742 static void
ql_host_idx(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)2743 ql_host_idx(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
2744 {
2745 uint16_t idx;
2746
2747 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
2748
2749 if (cmd->ResponseLen < sizeof (uint16_t)) {
2750 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
2751 cmd->DetailStatus = sizeof (uint16_t);
2752 EL(ha, "failed, ResponseLen < Len=%xh\n", cmd->ResponseLen);
2753 cmd->ResponseLen = 0;
2754 return;
2755 }
2756
2757 idx = (uint16_t)ha->instance;
2758
2759 if (ddi_copyout((void *)&idx, (void *)(uintptr_t)(cmd->ResponseAdr),
2760 sizeof (uint16_t), mode) != 0) {
2761 cmd->Status = EXT_STATUS_COPY_ERR;
2762 cmd->ResponseLen = 0;
2763 EL(ha, "failed, ddi_copyout\n");
2764 } else {
2765 cmd->ResponseLen = sizeof (uint16_t);
2766 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
2767 }
2768 }
2769
2770 /*
2771 * ql_host_drvname
2772 * Gets host driver name
2773 *
2774 * Input:
2775 * ha: adapter state pointer.
2776 * cmd: EXT_IOCTL cmd struct pointer.
2777 * mode: flags.
2778 *
2779 * Returns:
2780 * None, request status indicated in cmd->Status.
2781 *
2782 * Context:
2783 * Kernel context.
2784 */
2785 static void
ql_host_drvname(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)2786 ql_host_drvname(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
2787 {
2788
2789 char drvname[] = QL_NAME;
2790 uint32_t qlnamelen;
2791
2792 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
2793
2794 qlnamelen = (uint32_t)(strlen(QL_NAME)+1);
2795
2796 if (cmd->ResponseLen < qlnamelen) {
2797 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
2798 cmd->DetailStatus = qlnamelen;
2799 EL(ha, "failed, ResponseLen: %xh, needed: %xh\n",
2800 cmd->ResponseLen, qlnamelen);
2801 cmd->ResponseLen = 0;
2802 return;
2803 }
2804
2805 if (ddi_copyout((void *)&drvname,
2806 (void *)(uintptr_t)(cmd->ResponseAdr),
2807 qlnamelen, mode) != 0) {
2808 cmd->Status = EXT_STATUS_COPY_ERR;
2809 cmd->ResponseLen = 0;
2810 EL(ha, "failed, ddi_copyout\n");
2811 } else {
2812 cmd->ResponseLen = qlnamelen-1;
2813 }
2814
2815 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
2816 }
2817
2818 /*
2819 * ql_read_nvram
2820 * Get NVRAM contents.
2821 *
2822 * Input:
2823 * ha: adapter state pointer.
2824 * cmd: EXT_IOCTL cmd struct pointer.
2825 * mode: flags.
2826 *
2827 * Returns:
2828 * None, request status indicated in cmd->Status.
2829 *
2830 * Context:
2831 * Kernel context.
2832 */
2833 static void
ql_read_nvram(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)2834 ql_read_nvram(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
2835 {
2836
2837 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
2838
2839 if (cmd->ResponseLen < ha->nvram_cache->size) {
2840 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
2841 cmd->DetailStatus = ha->nvram_cache->size;
2842 EL(ha, "failed, ResponseLen != NVRAM, Len=%xh\n",
2843 cmd->ResponseLen);
2844 cmd->ResponseLen = 0;
2845 return;
2846 }
2847
2848 /* Get NVRAM data. */
2849 if (ql_nv_util_dump(ha, (void *)(uintptr_t)(cmd->ResponseAdr),
2850 mode) != 0) {
2851 cmd->Status = EXT_STATUS_COPY_ERR;
2852 cmd->ResponseLen = 0;
2853 EL(ha, "failed, copy error\n");
2854 } else {
2855 cmd->ResponseLen = ha->nvram_cache->size;
2856 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
2857 }
2858 }
2859
2860 /*
2861 * ql_write_nvram
2862 * Loads NVRAM contents.
2863 *
2864 * Input:
2865 * ha: adapter state pointer.
2866 * cmd: EXT_IOCTL cmd struct pointer.
2867 * mode: flags.
2868 *
2869 * Returns:
2870 * None, request status indicated in cmd->Status.
2871 *
2872 * Context:
2873 * Kernel context.
2874 */
2875 static void
ql_write_nvram(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)2876 ql_write_nvram(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
2877 {
2878
2879 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
2880
2881 if (cmd->RequestLen < ha->nvram_cache->size) {
2882 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
2883 cmd->DetailStatus = ha->nvram_cache->size;
2884 EL(ha, "failed, RequestLen != NVRAM, Len=%xh\n",
2885 cmd->RequestLen);
2886 return;
2887 }
2888
2889 /* Load NVRAM data. */
2890 if (ql_nv_util_load(ha, (void *)(uintptr_t)(cmd->RequestAdr),
2891 mode) != 0) {
2892 cmd->Status = EXT_STATUS_COPY_ERR;
2893 EL(ha, "failed, copy error\n");
2894 } else {
2895 /*EMPTY*/
2896 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
2897 }
2898 }
2899
2900 /*
2901 * ql_write_vpd
2902 * Loads VPD contents.
2903 *
2904 * Input:
2905 * ha: adapter state pointer.
2906 * cmd: EXT_IOCTL cmd struct pointer.
2907 * mode: flags.
2908 *
2909 * Returns:
2910 * None, request status indicated in cmd->Status.
2911 *
2912 * Context:
2913 * Kernel context.
2914 */
2915 static void
ql_write_vpd(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)2916 ql_write_vpd(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
2917 {
2918 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
2919
2920 int32_t rval = 0;
2921
2922 if ((CFG_IST(ha, CFG_CTRL_24258081)) == 0) {
2923 cmd->Status = EXT_STATUS_INVALID_REQUEST;
2924 EL(ha, "failed, invalid request for HBA\n");
2925 return;
2926 }
2927
2928 if (cmd->RequestLen < QL_24XX_VPD_SIZE) {
2929 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
2930 cmd->DetailStatus = QL_24XX_VPD_SIZE;
2931 EL(ha, "failed, RequestLen != VPD len, len passed=%xh\n",
2932 cmd->RequestLen);
2933 return;
2934 }
2935
2936 /* Load VPD data. */
2937 if ((rval = ql_vpd_load(ha, (void *)(uintptr_t)(cmd->RequestAdr),
2938 mode)) != 0) {
2939 cmd->Status = EXT_STATUS_COPY_ERR;
2940 cmd->DetailStatus = rval;
2941 EL(ha, "failed, errno=%x\n", rval);
2942 } else {
2943 /*EMPTY*/
2944 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
2945 }
2946 }
2947
2948 /*
2949 * ql_read_vpd
2950 * Dumps VPD contents.
2951 *
2952 * Input:
2953 * ha: adapter state pointer.
2954 * cmd: EXT_IOCTL cmd struct pointer.
2955 * mode: flags.
2956 *
2957 * Returns:
2958 * None, request status indicated in cmd->Status.
2959 *
2960 * Context:
2961 * Kernel context.
2962 */
2963 static void
ql_read_vpd(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)2964 ql_read_vpd(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
2965 {
2966 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
2967
2968 if ((CFG_IST(ha, CFG_CTRL_24258081)) == 0) {
2969 cmd->Status = EXT_STATUS_INVALID_REQUEST;
2970 EL(ha, "failed, invalid request for HBA\n");
2971 return;
2972 }
2973
2974 if (cmd->ResponseLen < QL_24XX_VPD_SIZE) {
2975 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
2976 cmd->DetailStatus = QL_24XX_VPD_SIZE;
2977 EL(ha, "failed, ResponseLen < VPD len, len passed=%xh\n",
2978 cmd->ResponseLen);
2979 return;
2980 }
2981
2982 /* Dump VPD data. */
2983 if ((ql_vpd_dump(ha, (void *)(uintptr_t)(cmd->ResponseAdr),
2984 mode)) != 0) {
2985 cmd->Status = EXT_STATUS_COPY_ERR;
2986 EL(ha, "failed,\n");
2987 } else {
2988 /*EMPTY*/
2989 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
2990 }
2991 }
2992
2993 /*
2994 * ql_get_fcache
2995 * Dumps flash cache contents.
2996 *
2997 * Input:
2998 * ha: adapter state pointer.
2999 * cmd: EXT_IOCTL cmd struct pointer.
3000 * mode: flags.
3001 *
3002 * Returns:
3003 * None, request status indicated in cmd->Status.
3004 *
3005 * Context:
3006 * Kernel context.
3007 */
3008 static void
ql_get_fcache(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)3009 ql_get_fcache(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
3010 {
3011 uint32_t bsize, boff, types, cpsize, hsize;
3012 ql_fcache_t *fptr;
3013
3014 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
3015
3016 CACHE_LOCK(ha);
3017
3018 if (ha->fcache == NULL) {
3019 CACHE_UNLOCK(ha);
3020 cmd->Status = EXT_STATUS_ERR;
3021 EL(ha, "failed, adapter fcache not setup\n");
3022 return;
3023 }
3024
3025 if ((CFG_IST(ha, CFG_CTRL_24258081)) == 0) {
3026 bsize = 100;
3027 } else {
3028 bsize = 400;
3029 }
3030
3031 if (cmd->ResponseLen < bsize) {
3032 CACHE_UNLOCK(ha);
3033 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
3034 cmd->DetailStatus = bsize;
3035 EL(ha, "failed, ResponseLen < %d, len passed=%xh\n",
3036 bsize, cmd->ResponseLen);
3037 return;
3038 }
3039
3040 boff = 0;
3041 bsize = 0;
3042 fptr = ha->fcache;
3043
3044 /*
3045 * For backwards compatibility, get one of each image type
3046 */
3047 types = (FTYPE_BIOS | FTYPE_FCODE | FTYPE_EFI);
3048 while ((fptr != NULL) && (fptr->buf != NULL) && (types != 0)) {
3049 /* Get the next image */
3050 if ((fptr = ql_get_fbuf(ha->fcache, types)) != NULL) {
3051
3052 cpsize = (fptr->buflen < 100 ? fptr->buflen : 100);
3053
3054 if (ddi_copyout(fptr->buf,
3055 (void *)(uintptr_t)(cmd->ResponseAdr + boff),
3056 cpsize, mode) != 0) {
3057 CACHE_UNLOCK(ha);
3058 EL(ha, "ddicopy failed, done\n");
3059 cmd->Status = EXT_STATUS_COPY_ERR;
3060 cmd->DetailStatus = 0;
3061 return;
3062 }
3063 boff += 100;
3064 bsize += cpsize;
3065 types &= ~(fptr->type);
3066 }
3067 }
3068
3069 /*
3070 * Get the firmware image -- it needs to be last in the
3071 * buffer at offset 300 for backwards compatibility. Also for
3072 * backwards compatibility, the pci header is stripped off.
3073 */
3074 if ((fptr = ql_get_fbuf(ha->fcache, FTYPE_FW)) != NULL) {
3075
3076 hsize = sizeof (pci_header_t) + sizeof (pci_data_t);
3077 if (hsize > fptr->buflen) {
3078 CACHE_UNLOCK(ha);
3079 EL(ha, "header size (%xh) exceeds buflen (%xh)\n",
3080 hsize, fptr->buflen);
3081 cmd->Status = EXT_STATUS_COPY_ERR;
3082 cmd->DetailStatus = 0;
3083 return;
3084 }
3085
3086 cpsize = ((fptr->buflen - hsize) < 100 ?
3087 fptr->buflen - hsize : 100);
3088
3089 if (ddi_copyout(fptr->buf+hsize,
3090 (void *)(uintptr_t)(cmd->ResponseAdr + 300),
3091 cpsize, mode) != 0) {
3092 CACHE_UNLOCK(ha);
3093 EL(ha, "fw ddicopy failed, done\n");
3094 cmd->Status = EXT_STATUS_COPY_ERR;
3095 cmd->DetailStatus = 0;
3096 return;
3097 }
3098 bsize += 100;
3099 }
3100
3101 CACHE_UNLOCK(ha);
3102 cmd->Status = EXT_STATUS_OK;
3103 cmd->DetailStatus = bsize;
3104
3105 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
3106 }
3107
3108 /*
3109 * ql_get_fcache_ex
3110 * Dumps flash cache contents.
3111 *
3112 * Input:
3113 * ha: adapter state pointer.
3114 * cmd: EXT_IOCTL cmd struct pointer.
3115 * mode: flags.
3116 *
3117 * Returns:
3118 * None, request status indicated in cmd->Status.
3119 *
3120 * Context:
3121 * Kernel context.
3122 */
3123 static void
ql_get_fcache_ex(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)3124 ql_get_fcache_ex(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
3125 {
3126 uint32_t bsize = 0;
3127 uint32_t boff = 0;
3128 ql_fcache_t *fptr;
3129
3130 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
3131
3132 CACHE_LOCK(ha);
3133 if (ha->fcache == NULL) {
3134 CACHE_UNLOCK(ha);
3135 cmd->Status = EXT_STATUS_ERR;
3136 EL(ha, "failed, adapter fcache not setup\n");
3137 return;
3138 }
3139
3140 /* Make sure user passed enough buffer space */
3141 for (fptr = ha->fcache; fptr != NULL; fptr = fptr->next) {
3142 bsize += FBUFSIZE;
3143 }
3144
3145 if (cmd->ResponseLen < bsize) {
3146 CACHE_UNLOCK(ha);
3147 if (cmd->ResponseLen != 0) {
3148 EL(ha, "failed, ResponseLen < %d, len passed=%xh\n",
3149 bsize, cmd->ResponseLen);
3150 }
3151 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
3152 cmd->DetailStatus = bsize;
3153 return;
3154 }
3155
3156 boff = 0;
3157 fptr = ha->fcache;
3158 while ((fptr != NULL) && (fptr->buf != NULL)) {
3159 /* Get the next image */
3160 if (ddi_copyout(fptr->buf,
3161 (void *)(uintptr_t)(cmd->ResponseAdr + boff),
3162 (fptr->buflen < FBUFSIZE ? fptr->buflen : FBUFSIZE),
3163 mode) != 0) {
3164 CACHE_UNLOCK(ha);
3165 EL(ha, "failed, ddicopy at %xh, done\n", boff);
3166 cmd->Status = EXT_STATUS_COPY_ERR;
3167 cmd->DetailStatus = 0;
3168 return;
3169 }
3170 boff += FBUFSIZE;
3171 fptr = fptr->next;
3172 }
3173
3174 CACHE_UNLOCK(ha);
3175 cmd->Status = EXT_STATUS_OK;
3176 cmd->DetailStatus = bsize;
3177
3178 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
3179 }
3180
3181 /*
3182 * ql_read_flash
3183 * Get flash contents.
3184 *
3185 * Input:
3186 * ha: adapter state pointer.
3187 * cmd: EXT_IOCTL cmd struct pointer.
3188 * mode: flags.
3189 *
3190 * Returns:
3191 * None, request status indicated in cmd->Status.
3192 *
3193 * Context:
3194 * Kernel context.
3195 */
3196 static void
ql_read_flash(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)3197 ql_read_flash(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
3198 {
3199 ql_xioctl_t *xp = ha->xioctl;
3200
3201 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
3202
3203 if (ql_stall_driver(ha, 0) != QL_SUCCESS) {
3204 EL(ha, "ql_stall_driver failed\n");
3205 cmd->Status = EXT_STATUS_BUSY;
3206 cmd->DetailStatus = xp->fdesc.flash_size;
3207 cmd->ResponseLen = 0;
3208 return;
3209 }
3210
3211 if (ql_setup_fcache(ha) != QL_SUCCESS) {
3212 cmd->Status = EXT_STATUS_ERR;
3213 cmd->DetailStatus = xp->fdesc.flash_size;
3214 EL(ha, "failed, ResponseLen=%xh, flash size=%xh\n",
3215 cmd->ResponseLen, xp->fdesc.flash_size);
3216 cmd->ResponseLen = 0;
3217 } else {
3218 /* adjust read size to flash size */
3219 if (cmd->ResponseLen > xp->fdesc.flash_size) {
3220 EL(ha, "adjusting req=%xh, max=%xh\n",
3221 cmd->ResponseLen, xp->fdesc.flash_size);
3222 cmd->ResponseLen = xp->fdesc.flash_size;
3223 }
3224
3225 /* Get flash data. */
3226 if (ql_flash_fcode_dump(ha,
3227 (void *)(uintptr_t)(cmd->ResponseAdr),
3228 (size_t)(cmd->ResponseLen), 0, mode) != 0) {
3229 cmd->Status = EXT_STATUS_COPY_ERR;
3230 cmd->ResponseLen = 0;
3231 EL(ha, "failed,\n");
3232 }
3233 }
3234
3235 /* Resume I/O */
3236 if (CFG_IST(ha, CFG_CTRL_24258081)) {
3237 ql_restart_driver(ha);
3238 } else {
3239 EL(ha, "isp_abort_needed for restart\n");
3240 ql_awaken_task_daemon(ha, NULL, ISP_ABORT_NEEDED,
3241 DRIVER_STALL);
3242 }
3243
3244 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
3245 }
3246
3247 /*
3248 * ql_write_flash
3249 * Loads flash contents.
3250 *
3251 * Input:
3252 * ha: adapter state pointer.
3253 * cmd: EXT_IOCTL cmd struct pointer.
3254 * mode: flags.
3255 *
3256 * Returns:
3257 * None, request status indicated in cmd->Status.
3258 *
3259 * Context:
3260 * Kernel context.
3261 */
3262 static void
ql_write_flash(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)3263 ql_write_flash(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
3264 {
3265 ql_xioctl_t *xp = ha->xioctl;
3266
3267 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
3268
3269 if (ql_stall_driver(ha, 0) != QL_SUCCESS) {
3270 EL(ha, "ql_stall_driver failed\n");
3271 cmd->Status = EXT_STATUS_BUSY;
3272 cmd->DetailStatus = xp->fdesc.flash_size;
3273 cmd->ResponseLen = 0;
3274 return;
3275 }
3276
3277 if (ql_setup_fcache(ha) != QL_SUCCESS) {
3278 cmd->Status = EXT_STATUS_ERR;
3279 cmd->DetailStatus = xp->fdesc.flash_size;
3280 EL(ha, "failed, RequestLen=%xh, size=%xh\n",
3281 cmd->RequestLen, xp->fdesc.flash_size);
3282 cmd->ResponseLen = 0;
3283 } else {
3284 /* Load flash data. */
3285 if (cmd->RequestLen > xp->fdesc.flash_size) {
3286 cmd->Status = EXT_STATUS_ERR;
3287 cmd->DetailStatus = xp->fdesc.flash_size;
3288 EL(ha, "failed, RequestLen=%xh, flash size=%xh\n",
3289 cmd->RequestLen, xp->fdesc.flash_size);
3290 } else if (ql_flash_fcode_load(ha,
3291 (void *)(uintptr_t)(cmd->RequestAdr),
3292 (size_t)(cmd->RequestLen), mode) != 0) {
3293 cmd->Status = EXT_STATUS_COPY_ERR;
3294 EL(ha, "failed,\n");
3295 }
3296 }
3297
3298 /* Resume I/O */
3299 if (CFG_IST(ha, CFG_CTRL_24258081)) {
3300 ql_restart_driver(ha);
3301 } else {
3302 EL(ha, "isp_abort_needed for restart\n");
3303 ql_awaken_task_daemon(ha, NULL, ISP_ABORT_NEEDED,
3304 DRIVER_STALL);
3305 }
3306
3307 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
3308 }
3309
3310 /*
3311 * ql_diagnostic_loopback
3312 * Performs EXT_CC_LOOPBACK Command
3313 *
3314 * Input:
3315 * ha: adapter state pointer.
3316 * cmd: Local EXT_IOCTL cmd struct pointer.
3317 * mode: flags.
3318 *
3319 * Returns:
3320 * None, request status indicated in cmd->Status.
3321 *
3322 * Context:
3323 * Kernel context.
3324 */
3325 static void
ql_diagnostic_loopback(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)3326 ql_diagnostic_loopback(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
3327 {
3328 EXT_LOOPBACK_REQ plbreq;
3329 EXT_LOOPBACK_RSP plbrsp;
3330 ql_mbx_data_t mr;
3331 uint32_t rval;
3332 caddr_t bp;
3333 uint16_t opt;
3334
3335 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
3336
3337 /* Get loop back request. */
3338 if (ddi_copyin((void *)(uintptr_t)cmd->RequestAdr,
3339 (void *)&plbreq, sizeof (EXT_LOOPBACK_REQ), mode) != 0) {
3340 EL(ha, "failed, ddi_copyin\n");
3341 cmd->Status = EXT_STATUS_COPY_ERR;
3342 cmd->ResponseLen = 0;
3343 return;
3344 }
3345
3346 opt = (uint16_t)(plbreq.Options & MBC_LOOPBACK_POINT_MASK);
3347
3348 /* Check transfer length fits in buffer. */
3349 if (plbreq.BufferLength < plbreq.TransferCount &&
3350 plbreq.TransferCount < MAILBOX_BUFFER_SIZE) {
3351 EL(ha, "failed, BufferLength=%d, xfercnt=%d, "
3352 "mailbox_buffer_size=%d\n", plbreq.BufferLength,
3353 plbreq.TransferCount, MAILBOX_BUFFER_SIZE);
3354 cmd->Status = EXT_STATUS_INVALID_PARAM;
3355 cmd->ResponseLen = 0;
3356 return;
3357 }
3358
3359 /* Allocate command memory. */
3360 bp = kmem_zalloc(plbreq.TransferCount, KM_SLEEP);
3361 if (bp == NULL) {
3362 EL(ha, "failed, kmem_zalloc\n");
3363 cmd->Status = EXT_STATUS_NO_MEMORY;
3364 cmd->ResponseLen = 0;
3365 return;
3366 }
3367
3368 /* Get loopback data. */
3369 if (ql_get_buffer_data((caddr_t)(uintptr_t)plbreq.BufferAddress,
3370 bp, plbreq.TransferCount, mode) != plbreq.TransferCount) {
3371 EL(ha, "failed, ddi_copyin-2\n");
3372 kmem_free(bp, plbreq.TransferCount);
3373 cmd->Status = EXT_STATUS_COPY_ERR;
3374 cmd->ResponseLen = 0;
3375 return;
3376 }
3377
3378 if ((ha->task_daemon_flags & (QL_LOOP_TRANSITION | DRIVER_STALL)) ||
3379 ql_stall_driver(ha, 0) != QL_SUCCESS) {
3380 EL(ha, "failed, LOOP_NOT_READY\n");
3381 kmem_free(bp, plbreq.TransferCount);
3382 cmd->Status = EXT_STATUS_BUSY;
3383 cmd->ResponseLen = 0;
3384 return;
3385 }
3386
3387 /* Shutdown IP. */
3388 if (ha->flags & IP_INITIALIZED) {
3389 (void) ql_shutdown_ip(ha);
3390 }
3391
3392 /* determine topology so we can send the loopback or the echo */
3393 /* Echo is supported on 2300's only and above */
3394
3395 if (CFG_IST(ha, CFG_CTRL_8081)) {
3396 if (!(ha->task_daemon_flags & LOOP_DOWN) && opt ==
3397 MBC_LOOPBACK_POINT_EXTERNAL) {
3398 if (plbreq.TransferCount > 252) {
3399 EL(ha, "transfer count (%d) > 252\n",
3400 plbreq.TransferCount);
3401 kmem_free(bp, plbreq.TransferCount);
3402 cmd->Status = EXT_STATUS_INVALID_PARAM;
3403 cmd->ResponseLen = 0;
3404 return;
3405 }
3406 plbrsp.CommandSent = INT_DEF_LB_ECHO_CMD;
3407 rval = ql_diag_echo(ha, 0, bp, plbreq.TransferCount,
3408 MBC_ECHO_ELS, &mr);
3409 } else {
3410 if (CFG_IST(ha, CFG_CTRL_81XX)) {
3411 (void) ql_set_loop_point(ha, opt);
3412 }
3413 plbrsp.CommandSent = INT_DEF_LB_LOOPBACK_CMD;
3414 rval = ql_diag_loopback(ha, 0, bp, plbreq.TransferCount,
3415 opt, plbreq.IterationCount, &mr);
3416 if (CFG_IST(ha, CFG_CTRL_81XX)) {
3417 (void) ql_set_loop_point(ha, 0);
3418 }
3419 }
3420 } else {
3421 if (!(ha->task_daemon_flags & LOOP_DOWN) &&
3422 (ha->topology & QL_F_PORT) &&
3423 ha->device_id >= 0x2300) {
3424 QL_PRINT_9(CE_CONT, "(%d): F_PORT topology -- using "
3425 "echo\n", ha->instance);
3426 plbrsp.CommandSent = INT_DEF_LB_ECHO_CMD;
3427 rval = ql_diag_echo(ha, 0, bp, plbreq.TransferCount,
3428 (uint16_t)(CFG_IST(ha, CFG_CTRL_8081) ?
3429 MBC_ECHO_ELS : MBC_ECHO_64BIT), &mr);
3430 } else {
3431 plbrsp.CommandSent = INT_DEF_LB_LOOPBACK_CMD;
3432 rval = ql_diag_loopback(ha, 0, bp, plbreq.TransferCount,
3433 opt, plbreq.IterationCount, &mr);
3434 }
3435 }
3436
3437 ql_restart_driver(ha);
3438
3439 /* Restart IP if it was shutdown. */
3440 if (ha->flags & IP_ENABLED && !(ha->flags & IP_INITIALIZED)) {
3441 (void) ql_initialize_ip(ha);
3442 ql_isp_rcvbuf(ha);
3443 }
3444
3445 if (rval != QL_SUCCESS) {
3446 EL(ha, "failed, diagnostic_loopback_mbx=%xh\n", rval);
3447 kmem_free(bp, plbreq.TransferCount);
3448 cmd->Status = EXT_STATUS_MAILBOX;
3449 cmd->DetailStatus = rval;
3450 cmd->ResponseLen = 0;
3451 return;
3452 }
3453
3454 /* Return loopback data. */
3455 if (ql_send_buffer_data(bp, (caddr_t)(uintptr_t)plbreq.BufferAddress,
3456 plbreq.TransferCount, mode) != plbreq.TransferCount) {
3457 EL(ha, "failed, ddi_copyout\n");
3458 kmem_free(bp, plbreq.TransferCount);
3459 cmd->Status = EXT_STATUS_COPY_ERR;
3460 cmd->ResponseLen = 0;
3461 return;
3462 }
3463 kmem_free(bp, plbreq.TransferCount);
3464
3465 /* Return loopback results. */
3466 plbrsp.BufferAddress = plbreq.BufferAddress;
3467 plbrsp.BufferLength = plbreq.TransferCount;
3468 plbrsp.CompletionStatus = mr.mb[0];
3469
3470 if (plbrsp.CommandSent == INT_DEF_LB_ECHO_CMD) {
3471 plbrsp.CrcErrorCount = 0;
3472 plbrsp.DisparityErrorCount = 0;
3473 plbrsp.FrameLengthErrorCount = 0;
3474 plbrsp.IterationCountLastError = 0;
3475 } else {
3476 plbrsp.CrcErrorCount = mr.mb[1];
3477 plbrsp.DisparityErrorCount = mr.mb[2];
3478 plbrsp.FrameLengthErrorCount = mr.mb[3];
3479 plbrsp.IterationCountLastError = (mr.mb[19] >> 16) | mr.mb[18];
3480 }
3481
3482 rval = ddi_copyout((void *)&plbrsp,
3483 (void *)(uintptr_t)cmd->ResponseAdr,
3484 sizeof (EXT_LOOPBACK_RSP), mode);
3485 if (rval != 0) {
3486 EL(ha, "failed, ddi_copyout-2\n");
3487 cmd->Status = EXT_STATUS_COPY_ERR;
3488 cmd->ResponseLen = 0;
3489 return;
3490 }
3491 cmd->ResponseLen = sizeof (EXT_LOOPBACK_RSP);
3492
3493 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
3494 }
3495
3496 /*
3497 * ql_set_loop_point
3498 * Setup loop point for port configuration.
3499 *
3500 * Input:
3501 * ha: adapter state structure.
3502 * opt: loop point option.
3503 *
3504 * Returns:
3505 * ql local function return status code.
3506 *
3507 * Context:
3508 * Kernel context.
3509 */
3510 static int
ql_set_loop_point(ql_adapter_state_t * ha,uint16_t opt)3511 ql_set_loop_point(ql_adapter_state_t *ha, uint16_t opt)
3512 {
3513 ql_mbx_data_t mr;
3514 int rval;
3515 uint32_t timer;
3516
3517 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
3518
3519 /*
3520 * We get the current port config, modify the loopback field and
3521 * write it back out.
3522 */
3523 if ((rval = ql_get_port_config(ha, &mr)) != QL_SUCCESS) {
3524 EL(ha, "get_port_config status=%xh\n", rval);
3525 return (rval);
3526 }
3527 /*
3528 * Set the loopback mode field while maintaining the others.
3529 * Currently only internal or none are supported.
3530 */
3531 mr.mb[1] = (uint16_t)(mr.mb[1] &~LOOPBACK_MODE_FIELD_MASK);
3532 if (opt == MBC_LOOPBACK_POINT_INTERNAL) {
3533 mr.mb[1] = (uint16_t)(mr.mb[1] |
3534 LOOPBACK_MODE(LOOPBACK_MODE_INTERNAL));
3535 }
3536 /*
3537 * Changing the port configuration will cause the port state to cycle
3538 * down and back up. The indication that this has happened is that
3539 * the point to point flag gets set.
3540 */
3541 ADAPTER_STATE_LOCK(ha);
3542 ha->flags &= ~POINT_TO_POINT;
3543 ADAPTER_STATE_UNLOCK(ha);
3544 if ((rval = ql_set_port_config(ha, &mr)) != QL_SUCCESS) {
3545 EL(ha, "set_port_config status=%xh\n", rval);
3546 }
3547
3548 /* wait for a while */
3549 for (timer = opt ? 10 : 0; timer; timer--) {
3550 if (ha->flags & POINT_TO_POINT) {
3551 break;
3552 }
3553 /* Delay for 1000000 usec (1 second). */
3554 ql_delay(ha, 1000000);
3555 }
3556
3557 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
3558
3559 return (rval);
3560 }
3561
3562 /*
3563 * ql_send_els_rnid
3564 * IOCTL for extended link service RNID command.
3565 *
3566 * Input:
3567 * ha: adapter state pointer.
3568 * cmd: User space CT arguments pointer.
3569 * mode: flags.
3570 *
3571 * Returns:
3572 * None, request status indicated in cmd->Status.
3573 *
3574 * Context:
3575 * Kernel context.
3576 */
3577 static void
ql_send_els_rnid(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)3578 ql_send_els_rnid(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
3579 {
3580 EXT_RNID_REQ tmp_rnid;
3581 port_id_t tmp_fcid;
3582 caddr_t tmp_buf, bptr;
3583 uint32_t copy_len;
3584 ql_tgt_t *tq;
3585 EXT_RNID_DATA rnid_data;
3586 uint32_t loop_ready_wait = 10 * 60 * 10;
3587 int rval = 0;
3588 uint32_t local_hba = 0;
3589
3590 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
3591
3592 if (DRIVER_SUSPENDED(ha)) {
3593 EL(ha, "failed, LOOP_NOT_READY\n");
3594 cmd->Status = EXT_STATUS_BUSY;
3595 cmd->ResponseLen = 0;
3596 return;
3597 }
3598
3599 if (cmd->RequestLen != sizeof (EXT_RNID_REQ)) {
3600 /* parameter error */
3601 EL(ha, "failed, RequestLen < EXT_RNID_REQ, Len=%xh\n",
3602 cmd->RequestLen);
3603 cmd->Status = EXT_STATUS_INVALID_PARAM;
3604 cmd->DetailStatus = EXT_DSTATUS_REQUEST_LEN;
3605 cmd->ResponseLen = 0;
3606 return;
3607 }
3608
3609 if (ddi_copyin((void*)(uintptr_t)cmd->RequestAdr,
3610 &tmp_rnid, cmd->RequestLen, mode) != 0) {
3611 EL(ha, "failed, ddi_copyin\n");
3612 cmd->Status = EXT_STATUS_COPY_ERR;
3613 cmd->ResponseLen = 0;
3614 return;
3615 }
3616
3617 /* Find loop ID of the device */
3618 if (tmp_rnid.Addr.Type == EXT_DEF_TYPE_WWNN) {
3619 bptr = CFG_IST(ha, CFG_CTRL_24258081) ?
3620 (caddr_t)&ha->init_ctrl_blk.cb24.node_name :
3621 (caddr_t)&ha->init_ctrl_blk.cb.node_name;
3622 if (bcmp((void *)bptr, (void *)tmp_rnid.Addr.FcAddr.WWNN,
3623 EXT_DEF_WWN_NAME_SIZE) == 0) {
3624 local_hba = 1;
3625 } else {
3626 tq = ql_find_port(ha,
3627 (uint8_t *)tmp_rnid.Addr.FcAddr.WWNN, QLNT_NODE);
3628 }
3629 } else if (tmp_rnid.Addr.Type == EXT_DEF_TYPE_WWPN) {
3630 bptr = CFG_IST(ha, CFG_CTRL_24258081) ?
3631 (caddr_t)&ha->init_ctrl_blk.cb24.port_name :
3632 (caddr_t)&ha->init_ctrl_blk.cb.port_name;
3633 if (bcmp((void *)bptr, (void *)tmp_rnid.Addr.FcAddr.WWPN,
3634 EXT_DEF_WWN_NAME_SIZE) == 0) {
3635 local_hba = 1;
3636 } else {
3637 tq = ql_find_port(ha,
3638 (uint8_t *)tmp_rnid.Addr.FcAddr.WWPN, QLNT_PORT);
3639 }
3640 } else if (tmp_rnid.Addr.Type == EXT_DEF_TYPE_PORTID) {
3641 /*
3642 * Copy caller's d_id to tmp space.
3643 */
3644 bcopy(&tmp_rnid.Addr.FcAddr.Id[1], tmp_fcid.r.d_id,
3645 EXT_DEF_PORTID_SIZE_ACTUAL);
3646 BIG_ENDIAN_24(&tmp_fcid.r.d_id[0]);
3647
3648 if (bcmp((void *)&ha->d_id, (void *)tmp_fcid.r.d_id,
3649 EXT_DEF_PORTID_SIZE_ACTUAL) == 0) {
3650 local_hba = 1;
3651 } else {
3652 tq = ql_find_port(ha, (uint8_t *)tmp_fcid.r.d_id,
3653 QLNT_PID);
3654 }
3655 }
3656
3657 /* Allocate memory for command. */
3658 tmp_buf = kmem_zalloc(SEND_RNID_RSP_SIZE, KM_SLEEP);
3659 if (tmp_buf == NULL) {
3660 EL(ha, "failed, kmem_zalloc\n");
3661 cmd->Status = EXT_STATUS_NO_MEMORY;
3662 cmd->ResponseLen = 0;
3663 return;
3664 }
3665
3666 if (local_hba) {
3667 rval = ql_get_rnid_params(ha, SEND_RNID_RSP_SIZE, tmp_buf);
3668 if (rval != QL_SUCCESS) {
3669 EL(ha, "failed, get_rnid_params_mbx=%xh\n", rval);
3670 kmem_free(tmp_buf, SEND_RNID_RSP_SIZE);
3671 cmd->Status = EXT_STATUS_ERR;
3672 cmd->ResponseLen = 0;
3673 return;
3674 }
3675
3676 /* Save gotten RNID data. */
3677 bcopy(tmp_buf, &rnid_data, sizeof (EXT_RNID_DATA));
3678
3679 /* Now build the Send RNID response */
3680 tmp_buf[0] = (char)(EXT_DEF_RNID_DFORMAT_TOPO_DISC);
3681 tmp_buf[1] = (2 * EXT_DEF_WWN_NAME_SIZE);
3682 tmp_buf[2] = 0;
3683 tmp_buf[3] = sizeof (EXT_RNID_DATA);
3684
3685 if (CFG_IST(ha, CFG_CTRL_24258081)) {
3686 bcopy(ha->init_ctrl_blk.cb24.port_name, &tmp_buf[4],
3687 EXT_DEF_WWN_NAME_SIZE);
3688 bcopy(ha->init_ctrl_blk.cb24.node_name,
3689 &tmp_buf[4 + EXT_DEF_WWN_NAME_SIZE],
3690 EXT_DEF_WWN_NAME_SIZE);
3691 } else {
3692 bcopy(ha->init_ctrl_blk.cb.port_name, &tmp_buf[4],
3693 EXT_DEF_WWN_NAME_SIZE);
3694 bcopy(ha->init_ctrl_blk.cb.node_name,
3695 &tmp_buf[4 + EXT_DEF_WWN_NAME_SIZE],
3696 EXT_DEF_WWN_NAME_SIZE);
3697 }
3698
3699 bcopy((uint8_t *)&rnid_data,
3700 &tmp_buf[4 + 2 * EXT_DEF_WWN_NAME_SIZE],
3701 sizeof (EXT_RNID_DATA));
3702 } else {
3703 if (tq == NULL) {
3704 /* no matching device */
3705 EL(ha, "failed, device not found\n");
3706 kmem_free(tmp_buf, SEND_RNID_RSP_SIZE);
3707 cmd->Status = EXT_STATUS_DEV_NOT_FOUND;
3708 cmd->DetailStatus = EXT_DSTATUS_TARGET;
3709 cmd->ResponseLen = 0;
3710 return;
3711 }
3712
3713 /* Send command */
3714 rval = ql_send_rnid_els(ha, tq->loop_id,
3715 (uint8_t)tmp_rnid.DataFormat, SEND_RNID_RSP_SIZE, tmp_buf);
3716 if (rval != QL_SUCCESS) {
3717 EL(ha, "failed, send_rnid_mbx=%xh, id=%xh\n",
3718 rval, tq->loop_id);
3719 while (LOOP_NOT_READY(ha)) {
3720 ql_delay(ha, 100000);
3721 if (loop_ready_wait-- == 0) {
3722 EL(ha, "failed, loop not ready\n");
3723 cmd->Status = EXT_STATUS_ERR;
3724 cmd->ResponseLen = 0;
3725 }
3726 }
3727 rval = ql_send_rnid_els(ha, tq->loop_id,
3728 (uint8_t)tmp_rnid.DataFormat, SEND_RNID_RSP_SIZE,
3729 tmp_buf);
3730 if (rval != QL_SUCCESS) {
3731 /* error */
3732 EL(ha, "failed, send_rnid_mbx=%xh, id=%xh\n",
3733 rval, tq->loop_id);
3734 kmem_free(tmp_buf, SEND_RNID_RSP_SIZE);
3735 cmd->Status = EXT_STATUS_ERR;
3736 cmd->ResponseLen = 0;
3737 return;
3738 }
3739 }
3740 }
3741
3742 /* Copy the response */
3743 copy_len = (cmd->ResponseLen > SEND_RNID_RSP_SIZE) ?
3744 SEND_RNID_RSP_SIZE : cmd->ResponseLen;
3745
3746 if (ql_send_buffer_data(tmp_buf, (caddr_t)(uintptr_t)cmd->ResponseAdr,
3747 copy_len, mode) != copy_len) {
3748 cmd->Status = EXT_STATUS_COPY_ERR;
3749 EL(ha, "failed, ddi_copyout\n");
3750 } else {
3751 cmd->ResponseLen = copy_len;
3752 if (copy_len < SEND_RNID_RSP_SIZE) {
3753 cmd->Status = EXT_STATUS_DATA_OVERRUN;
3754 EL(ha, "failed, EXT_STATUS_DATA_OVERRUN\n");
3755
3756 } else if (cmd->ResponseLen > SEND_RNID_RSP_SIZE) {
3757 cmd->Status = EXT_STATUS_DATA_UNDERRUN;
3758 EL(ha, "failed, EXT_STATUS_DATA_UNDERRUN\n");
3759 } else {
3760 cmd->Status = EXT_STATUS_OK;
3761 QL_PRINT_9(CE_CONT, "(%d): done\n",
3762 ha->instance);
3763 }
3764 }
3765
3766 kmem_free(tmp_buf, SEND_RNID_RSP_SIZE);
3767 }
3768
3769 /*
3770 * ql_set_host_data
3771 * Process IOCTL subcommand to set host/adapter related data.
3772 *
3773 * Input:
3774 * ha: adapter state pointer.
3775 * cmd: User space CT arguments pointer.
3776 * mode: flags.
3777 *
3778 * Returns:
3779 * None, request status indicated in cmd->Status.
3780 *
3781 * Context:
3782 * Kernel context.
3783 */
3784 static void
ql_set_host_data(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)3785 ql_set_host_data(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
3786 {
3787 QL_PRINT_9(CE_CONT, "(%d): started, SubCode=%d\n", ha->instance,
3788 cmd->SubCode);
3789
3790 /*
3791 * case off on command subcode
3792 */
3793 switch (cmd->SubCode) {
3794 case EXT_SC_SET_RNID:
3795 ql_set_rnid_parameters(ha, cmd, mode);
3796 break;
3797 case EXT_SC_RST_STATISTICS:
3798 (void) ql_reset_statistics(ha, cmd);
3799 break;
3800 case EXT_SC_SET_BEACON_STATE:
3801 ql_set_led_state(ha, cmd, mode);
3802 break;
3803 case EXT_SC_SET_PARMS:
3804 case EXT_SC_SET_BUS_MODE:
3805 case EXT_SC_SET_DR_DUMP_BUF:
3806 case EXT_SC_SET_RISC_CODE:
3807 case EXT_SC_SET_FLASH_RAM:
3808 case EXT_SC_SET_LUN_BITMASK:
3809 case EXT_SC_SET_RETRY_CNT:
3810 case EXT_SC_SET_RTIN:
3811 case EXT_SC_SET_FC_LUN_BITMASK:
3812 case EXT_SC_ADD_TARGET_DEVICE:
3813 case EXT_SC_SWAP_TARGET_DEVICE:
3814 case EXT_SC_SET_SEL_TIMEOUT:
3815 default:
3816 /* function not supported. */
3817 EL(ha, "failed, function not supported=%d\n", cmd->SubCode);
3818 cmd->Status = EXT_STATUS_UNSUPPORTED_SUBCODE;
3819 break;
3820 }
3821
3822 if (cmd->Status != EXT_STATUS_OK) {
3823 EL(ha, "failed, Status=%d\n", cmd->Status);
3824 } else {
3825 /*EMPTY*/
3826 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
3827 }
3828 }
3829
3830 /*
3831 * ql_get_host_data
3832 * Performs EXT_CC_GET_DATA subcommands.
3833 *
3834 * Input:
3835 * ha: adapter state pointer.
3836 * cmd: Local EXT_IOCTL cmd struct pointer.
3837 * mode: flags.
3838 *
3839 * Returns:
3840 * None, request status indicated in cmd->Status.
3841 *
3842 * Context:
3843 * Kernel context.
3844 */
3845 static void
ql_get_host_data(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)3846 ql_get_host_data(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
3847 {
3848 int out_size = 0;
3849
3850 QL_PRINT_9(CE_CONT, "(%d): started, SubCode=%d\n", ha->instance,
3851 cmd->SubCode);
3852
3853 /* case off on command subcode */
3854 switch (cmd->SubCode) {
3855 case EXT_SC_GET_STATISTICS:
3856 out_size = sizeof (EXT_HBA_PORT_STAT);
3857 break;
3858 case EXT_SC_GET_FC_STATISTICS:
3859 out_size = sizeof (EXT_HBA_PORT_STAT);
3860 break;
3861 case EXT_SC_GET_PORT_SUMMARY:
3862 out_size = sizeof (EXT_DEVICEDATA);
3863 break;
3864 case EXT_SC_GET_RNID:
3865 out_size = sizeof (EXT_RNID_DATA);
3866 break;
3867 case EXT_SC_GET_TARGET_ID:
3868 out_size = sizeof (EXT_DEST_ADDR);
3869 break;
3870 case EXT_SC_GET_BEACON_STATE:
3871 out_size = sizeof (EXT_BEACON_CONTROL);
3872 break;
3873 case EXT_SC_GET_FC4_STATISTICS:
3874 out_size = sizeof (EXT_HBA_FC4STATISTICS);
3875 break;
3876 case EXT_SC_GET_DCBX_PARAM:
3877 out_size = EXT_DEF_DCBX_PARAM_BUF_SIZE;
3878 break;
3879 case EXT_SC_GET_RESOURCE_CNTS:
3880 out_size = sizeof (EXT_RESOURCE_CNTS);
3881 break;
3882 case EXT_SC_GET_FCF_LIST:
3883 out_size = sizeof (EXT_FCF_LIST);
3884 break;
3885 case EXT_SC_GET_SCSI_ADDR:
3886 case EXT_SC_GET_ERR_DETECTIONS:
3887 case EXT_SC_GET_BUS_MODE:
3888 case EXT_SC_GET_DR_DUMP_BUF:
3889 case EXT_SC_GET_RISC_CODE:
3890 case EXT_SC_GET_FLASH_RAM:
3891 case EXT_SC_GET_LINK_STATUS:
3892 case EXT_SC_GET_LOOP_ID:
3893 case EXT_SC_GET_LUN_BITMASK:
3894 case EXT_SC_GET_PORT_DATABASE:
3895 case EXT_SC_GET_PORT_DATABASE_MEM:
3896 case EXT_SC_GET_POSITION_MAP:
3897 case EXT_SC_GET_RETRY_CNT:
3898 case EXT_SC_GET_RTIN:
3899 case EXT_SC_GET_FC_LUN_BITMASK:
3900 case EXT_SC_GET_SEL_TIMEOUT:
3901 default:
3902 /* function not supported. */
3903 EL(ha, "failed, function not supported=%d\n", cmd->SubCode);
3904 cmd->Status = EXT_STATUS_UNSUPPORTED_SUBCODE;
3905 cmd->ResponseLen = 0;
3906 return;
3907 }
3908
3909 if (cmd->ResponseLen < out_size) {
3910 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
3911 cmd->DetailStatus = out_size;
3912 EL(ha, "failed, ResponseLen=%xh, size=%xh\n",
3913 cmd->ResponseLen, out_size);
3914 cmd->ResponseLen = 0;
3915 return;
3916 }
3917
3918 switch (cmd->SubCode) {
3919 case EXT_SC_GET_RNID:
3920 ql_get_rnid_parameters(ha, cmd, mode);
3921 break;
3922 case EXT_SC_GET_STATISTICS:
3923 ql_get_statistics(ha, cmd, mode);
3924 break;
3925 case EXT_SC_GET_FC_STATISTICS:
3926 ql_get_statistics_fc(ha, cmd, mode);
3927 break;
3928 case EXT_SC_GET_FC4_STATISTICS:
3929 ql_get_statistics_fc4(ha, cmd, mode);
3930 break;
3931 case EXT_SC_GET_PORT_SUMMARY:
3932 ql_get_port_summary(ha, cmd, mode);
3933 break;
3934 case EXT_SC_GET_TARGET_ID:
3935 ql_get_target_id(ha, cmd, mode);
3936 break;
3937 case EXT_SC_GET_BEACON_STATE:
3938 ql_get_led_state(ha, cmd, mode);
3939 break;
3940 case EXT_SC_GET_DCBX_PARAM:
3941 ql_get_dcbx_parameters(ha, cmd, mode);
3942 break;
3943 case EXT_SC_GET_FCF_LIST:
3944 ql_get_fcf_list(ha, cmd, mode);
3945 break;
3946 case EXT_SC_GET_RESOURCE_CNTS:
3947 ql_get_resource_counts(ha, cmd, mode);
3948 break;
3949 }
3950
3951 if (cmd->Status != EXT_STATUS_OK) {
3952 EL(ha, "failed, Status=%d\n", cmd->Status);
3953 } else {
3954 /*EMPTY*/
3955 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
3956 }
3957 }
3958
3959 /* ******************************************************************** */
3960 /* Helper Functions */
3961 /* ******************************************************************** */
3962
3963 /*
3964 * ql_lun_count
3965 * Get numbers of LUNS on target.
3966 *
3967 * Input:
3968 * ha: adapter state pointer.
3969 * q: device queue pointer.
3970 *
3971 * Returns:
3972 * Number of LUNs.
3973 *
3974 * Context:
3975 * Kernel context.
3976 */
3977 static int
ql_lun_count(ql_adapter_state_t * ha,ql_tgt_t * tq)3978 ql_lun_count(ql_adapter_state_t *ha, ql_tgt_t *tq)
3979 {
3980 int cnt;
3981
3982 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
3983
3984 /* Bypass LUNs that failed. */
3985 cnt = ql_report_lun(ha, tq);
3986 if (cnt == 0) {
3987 cnt = ql_inq_scan(ha, tq, ha->maximum_luns_per_target);
3988 }
3989
3990 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
3991
3992 return (cnt);
3993 }
3994
3995 /*
3996 * ql_report_lun
3997 * Get numbers of LUNS using report LUN command.
3998 *
3999 * Input:
4000 * ha: adapter state pointer.
4001 * q: target queue pointer.
4002 *
4003 * Returns:
4004 * Number of LUNs.
4005 *
4006 * Context:
4007 * Kernel context.
4008 */
4009 static int
ql_report_lun(ql_adapter_state_t * ha,ql_tgt_t * tq)4010 ql_report_lun(ql_adapter_state_t *ha, ql_tgt_t *tq)
4011 {
4012 int rval;
4013 uint8_t retries;
4014 ql_mbx_iocb_t *pkt;
4015 ql_rpt_lun_lst_t *rpt;
4016 dma_mem_t dma_mem;
4017 uint32_t pkt_size, cnt;
4018 uint16_t comp_status;
4019 uint8_t scsi_status_h, scsi_status_l, *reqs;
4020
4021 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
4022
4023 if (DRIVER_SUSPENDED(ha)) {
4024 EL(ha, "failed, LOOP_NOT_READY\n");
4025 return (0);
4026 }
4027
4028 pkt_size = sizeof (ql_mbx_iocb_t) + sizeof (ql_rpt_lun_lst_t);
4029 pkt = kmem_zalloc(pkt_size, KM_SLEEP);
4030 if (pkt == NULL) {
4031 EL(ha, "failed, kmem_zalloc\n");
4032 return (0);
4033 }
4034 rpt = (ql_rpt_lun_lst_t *)((caddr_t)pkt + sizeof (ql_mbx_iocb_t));
4035
4036 /* Get DMA memory for the IOCB */
4037 if (ql_get_dma_mem(ha, &dma_mem, sizeof (ql_rpt_lun_lst_t),
4038 LITTLE_ENDIAN_DMA, QL_DMA_RING_ALIGN) != QL_SUCCESS) {
4039 cmn_err(CE_WARN, "%s(%d): DMA memory "
4040 "alloc failed", QL_NAME, ha->instance);
4041 kmem_free(pkt, pkt_size);
4042 return (0);
4043 }
4044
4045 for (retries = 0; retries < 4; retries++) {
4046 if (CFG_IST(ha, CFG_CTRL_24258081)) {
4047 pkt->cmd24.entry_type = IOCB_CMD_TYPE_7;
4048 pkt->cmd24.entry_count = 1;
4049
4050 /* Set N_port handle */
4051 pkt->cmd24.n_port_hdl = (uint16_t)LE_16(tq->loop_id);
4052
4053 /* Set target ID */
4054 pkt->cmd24.target_id[0] = tq->d_id.b.al_pa;
4055 pkt->cmd24.target_id[1] = tq->d_id.b.area;
4056 pkt->cmd24.target_id[2] = tq->d_id.b.domain;
4057
4058 /* Set Virtual Port ID */
4059 pkt->cmd24.vp_index = ha->vp_index;
4060
4061 /* Set ISP command timeout. */
4062 pkt->cmd24.timeout = LE_16(15);
4063
4064 /* Load SCSI CDB */
4065 pkt->cmd24.scsi_cdb[0] = SCMD_REPORT_LUNS;
4066 pkt->cmd24.scsi_cdb[6] =
4067 MSB(MSW(sizeof (ql_rpt_lun_lst_t)));
4068 pkt->cmd24.scsi_cdb[7] =
4069 LSB(MSW(sizeof (ql_rpt_lun_lst_t)));
4070 pkt->cmd24.scsi_cdb[8] =
4071 MSB(LSW(sizeof (ql_rpt_lun_lst_t)));
4072 pkt->cmd24.scsi_cdb[9] =
4073 LSB(LSW(sizeof (ql_rpt_lun_lst_t)));
4074 for (cnt = 0; cnt < MAX_CMDSZ; cnt += 4) {
4075 ql_chg_endian((uint8_t *)&pkt->cmd24.scsi_cdb
4076 + cnt, 4);
4077 }
4078
4079 /* Set tag queue control flags */
4080 pkt->cmd24.task = TA_STAG;
4081
4082 /* Set transfer direction. */
4083 pkt->cmd24.control_flags = CF_RD;
4084
4085 /* Set data segment count. */
4086 pkt->cmd24.dseg_count = LE_16(1);
4087
4088 /* Load total byte count. */
4089 /* Load data descriptor. */
4090 pkt->cmd24.dseg_0_address[0] = (uint32_t)
4091 LE_32(LSD(dma_mem.cookie.dmac_laddress));
4092 pkt->cmd24.dseg_0_address[1] = (uint32_t)
4093 LE_32(MSD(dma_mem.cookie.dmac_laddress));
4094 pkt->cmd24.total_byte_count =
4095 LE_32(sizeof (ql_rpt_lun_lst_t));
4096 pkt->cmd24.dseg_0_length =
4097 LE_32(sizeof (ql_rpt_lun_lst_t));
4098 } else if (CFG_IST(ha, CFG_ENABLE_64BIT_ADDRESSING)) {
4099 pkt->cmd3.entry_type = IOCB_CMD_TYPE_3;
4100 pkt->cmd3.entry_count = 1;
4101 if (CFG_IST(ha, CFG_EXT_FW_INTERFACE)) {
4102 pkt->cmd3.target_l = LSB(tq->loop_id);
4103 pkt->cmd3.target_h = MSB(tq->loop_id);
4104 } else {
4105 pkt->cmd3.target_h = LSB(tq->loop_id);
4106 }
4107 pkt->cmd3.control_flags_l = CF_DATA_IN | CF_STAG;
4108 pkt->cmd3.timeout = LE_16(15);
4109 pkt->cmd3.dseg_count = LE_16(1);
4110 pkt->cmd3.scsi_cdb[0] = SCMD_REPORT_LUNS;
4111 pkt->cmd3.scsi_cdb[6] =
4112 MSB(MSW(sizeof (ql_rpt_lun_lst_t)));
4113 pkt->cmd3.scsi_cdb[7] =
4114 LSB(MSW(sizeof (ql_rpt_lun_lst_t)));
4115 pkt->cmd3.scsi_cdb[8] =
4116 MSB(LSW(sizeof (ql_rpt_lun_lst_t)));
4117 pkt->cmd3.scsi_cdb[9] =
4118 LSB(LSW(sizeof (ql_rpt_lun_lst_t)));
4119 pkt->cmd3.byte_count =
4120 LE_32(sizeof (ql_rpt_lun_lst_t));
4121 pkt->cmd3.dseg_0_address[0] = (uint32_t)
4122 LE_32(LSD(dma_mem.cookie.dmac_laddress));
4123 pkt->cmd3.dseg_0_address[1] = (uint32_t)
4124 LE_32(MSD(dma_mem.cookie.dmac_laddress));
4125 pkt->cmd3.dseg_0_length =
4126 LE_32(sizeof (ql_rpt_lun_lst_t));
4127 } else {
4128 pkt->cmd.entry_type = IOCB_CMD_TYPE_2;
4129 pkt->cmd.entry_count = 1;
4130 if (CFG_IST(ha, CFG_EXT_FW_INTERFACE)) {
4131 pkt->cmd.target_l = LSB(tq->loop_id);
4132 pkt->cmd.target_h = MSB(tq->loop_id);
4133 } else {
4134 pkt->cmd.target_h = LSB(tq->loop_id);
4135 }
4136 pkt->cmd.control_flags_l = CF_DATA_IN | CF_STAG;
4137 pkt->cmd.timeout = LE_16(15);
4138 pkt->cmd.dseg_count = LE_16(1);
4139 pkt->cmd.scsi_cdb[0] = SCMD_REPORT_LUNS;
4140 pkt->cmd.scsi_cdb[6] =
4141 MSB(MSW(sizeof (ql_rpt_lun_lst_t)));
4142 pkt->cmd.scsi_cdb[7] =
4143 LSB(MSW(sizeof (ql_rpt_lun_lst_t)));
4144 pkt->cmd.scsi_cdb[8] =
4145 MSB(LSW(sizeof (ql_rpt_lun_lst_t)));
4146 pkt->cmd.scsi_cdb[9] =
4147 LSB(LSW(sizeof (ql_rpt_lun_lst_t)));
4148 pkt->cmd.byte_count =
4149 LE_32(sizeof (ql_rpt_lun_lst_t));
4150 pkt->cmd.dseg_0_address = (uint32_t)
4151 LE_32(LSD(dma_mem.cookie.dmac_laddress));
4152 pkt->cmd.dseg_0_length =
4153 LE_32(sizeof (ql_rpt_lun_lst_t));
4154 }
4155
4156 rval = ql_issue_mbx_iocb(ha, (caddr_t)pkt,
4157 sizeof (ql_mbx_iocb_t));
4158
4159 /* Sync in coming DMA buffer. */
4160 (void) ddi_dma_sync(dma_mem.dma_handle, 0, dma_mem.size,
4161 DDI_DMA_SYNC_FORKERNEL);
4162 /* Copy in coming DMA data. */
4163 ddi_rep_get8(dma_mem.acc_handle, (uint8_t *)rpt,
4164 (uint8_t *)dma_mem.bp, dma_mem.size, DDI_DEV_AUTOINCR);
4165
4166 if (CFG_IST(ha, CFG_CTRL_24258081)) {
4167 pkt->sts24.entry_status = (uint8_t)
4168 (pkt->sts24.entry_status & 0x3c);
4169 comp_status = (uint16_t)LE_16(pkt->sts24.comp_status);
4170 scsi_status_h = pkt->sts24.scsi_status_h;
4171 scsi_status_l = pkt->sts24.scsi_status_l;
4172 cnt = scsi_status_h & FCP_RSP_LEN_VALID ?
4173 LE_32(pkt->sts24.fcp_rsp_data_length) : 0;
4174 reqs = &pkt->sts24.rsp_sense_data[cnt];
4175 } else {
4176 pkt->sts.entry_status = (uint8_t)
4177 (pkt->sts.entry_status & 0x7e);
4178 comp_status = (uint16_t)LE_16(pkt->sts.comp_status);
4179 scsi_status_h = pkt->sts.scsi_status_h;
4180 scsi_status_l = pkt->sts.scsi_status_l;
4181 reqs = &pkt->sts.req_sense_data[0];
4182 }
4183 if (rval == QL_SUCCESS && pkt->sts.entry_status != 0) {
4184 EL(ha, "failed, entry_status=%xh, d_id=%xh\n",
4185 pkt->sts.entry_status, tq->d_id.b24);
4186 rval = QL_FUNCTION_PARAMETER_ERROR;
4187 }
4188
4189 if (rval != QL_SUCCESS || comp_status != CS_COMPLETE ||
4190 scsi_status_l & STATUS_CHECK) {
4191 /* Device underrun, treat as OK. */
4192 if (rval == QL_SUCCESS &&
4193 comp_status == CS_DATA_UNDERRUN &&
4194 scsi_status_h & FCP_RESID_UNDER) {
4195 break;
4196 }
4197
4198 EL(ha, "failed, issue_iocb=%xh, d_id=%xh, cs=%xh, "
4199 "ss_h=%xh, ss_l=%xh\n", rval, tq->d_id.b24,
4200 comp_status, scsi_status_h, scsi_status_l);
4201
4202 if (rval == QL_SUCCESS) {
4203 if ((comp_status == CS_TIMEOUT) ||
4204 (comp_status == CS_PORT_UNAVAILABLE) ||
4205 (comp_status == CS_PORT_LOGGED_OUT)) {
4206 rval = QL_FUNCTION_TIMEOUT;
4207 break;
4208 }
4209 rval = QL_FUNCTION_FAILED;
4210 } else if (rval == QL_ABORTED) {
4211 break;
4212 }
4213
4214 if (scsi_status_l & STATUS_CHECK) {
4215 EL(ha, "STATUS_CHECK Sense Data\n%2xh%3xh"
4216 "%3xh%3xh%3xh%3xh%3xh%3xh%3xh%3xh%3xh"
4217 "%3xh%3xh%3xh%3xh%3xh%3xh%3xh\n", reqs[0],
4218 reqs[1], reqs[2], reqs[3], reqs[4],
4219 reqs[5], reqs[6], reqs[7], reqs[8],
4220 reqs[9], reqs[10], reqs[11], reqs[12],
4221 reqs[13], reqs[14], reqs[15], reqs[16],
4222 reqs[17]);
4223 }
4224 } else {
4225 break;
4226 }
4227 bzero((caddr_t)pkt, pkt_size);
4228 }
4229
4230 if (rval != QL_SUCCESS) {
4231 EL(ha, "failed=%xh\n", rval);
4232 rval = 0;
4233 } else {
4234 QL_PRINT_9(CE_CONT, "(%d): LUN list\n", ha->instance);
4235 QL_DUMP_9(rpt, 8, rpt->hdr.len + 8);
4236 rval = (int)(BE_32(rpt->hdr.len) / 8);
4237 }
4238
4239 kmem_free(pkt, pkt_size);
4240 ql_free_dma_resource(ha, &dma_mem);
4241
4242 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
4243
4244 return (rval);
4245 }
4246
4247 /*
4248 * ql_inq_scan
4249 * Get numbers of LUNS using inquiry command.
4250 *
4251 * Input:
4252 * ha: adapter state pointer.
4253 * tq: target queue pointer.
4254 * count: scan for the number of existing LUNs.
4255 *
4256 * Returns:
4257 * Number of LUNs.
4258 *
4259 * Context:
4260 * Kernel context.
4261 */
4262 static int
ql_inq_scan(ql_adapter_state_t * ha,ql_tgt_t * tq,int count)4263 ql_inq_scan(ql_adapter_state_t *ha, ql_tgt_t *tq, int count)
4264 {
4265 int lun, cnt, rval;
4266 ql_mbx_iocb_t *pkt;
4267 uint8_t *inq;
4268 uint32_t pkt_size;
4269
4270 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
4271
4272 pkt_size = sizeof (ql_mbx_iocb_t) + INQ_DATA_SIZE;
4273 pkt = kmem_zalloc(pkt_size, KM_SLEEP);
4274 if (pkt == NULL) {
4275 EL(ha, "failed, kmem_zalloc\n");
4276 return (0);
4277 }
4278 inq = (uint8_t *)((caddr_t)pkt + sizeof (ql_mbx_iocb_t));
4279
4280 cnt = 0;
4281 for (lun = 0; lun < MAX_LUNS; lun++) {
4282
4283 if (DRIVER_SUSPENDED(ha)) {
4284 rval = QL_LOOP_DOWN;
4285 cnt = 0;
4286 break;
4287 }
4288
4289 rval = ql_inq(ha, tq, lun, pkt, INQ_DATA_SIZE);
4290 if (rval == QL_SUCCESS) {
4291 switch (*inq) {
4292 case DTYPE_DIRECT:
4293 case DTYPE_PROCESSOR: /* Appliance. */
4294 case DTYPE_WORM:
4295 case DTYPE_RODIRECT:
4296 case DTYPE_SCANNER:
4297 case DTYPE_OPTICAL:
4298 case DTYPE_CHANGER:
4299 case DTYPE_ESI:
4300 cnt++;
4301 break;
4302 case DTYPE_SEQUENTIAL:
4303 cnt++;
4304 tq->flags |= TQF_TAPE_DEVICE;
4305 break;
4306 default:
4307 QL_PRINT_9(CE_CONT, "(%d): failed, "
4308 "unsupported device id=%xh, lun=%d, "
4309 "type=%xh\n", ha->instance, tq->loop_id,
4310 lun, *inq);
4311 break;
4312 }
4313
4314 if (*inq == DTYPE_ESI || cnt >= count) {
4315 break;
4316 }
4317 } else if (rval == QL_ABORTED || rval == QL_FUNCTION_TIMEOUT) {
4318 cnt = 0;
4319 break;
4320 }
4321 }
4322
4323 kmem_free(pkt, pkt_size);
4324
4325 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
4326
4327 return (cnt);
4328 }
4329
4330 /*
4331 * ql_inq
4332 * Issue inquiry command.
4333 *
4334 * Input:
4335 * ha: adapter state pointer.
4336 * tq: target queue pointer.
4337 * lun: LUN number.
4338 * pkt: command and buffer pointer.
4339 * inq_len: amount of inquiry data.
4340 *
4341 * Returns:
4342 * ql local function return status code.
4343 *
4344 * Context:
4345 * Kernel context.
4346 */
4347 static int
ql_inq(ql_adapter_state_t * ha,ql_tgt_t * tq,int lun,ql_mbx_iocb_t * pkt,uint8_t inq_len)4348 ql_inq(ql_adapter_state_t *ha, ql_tgt_t *tq, int lun, ql_mbx_iocb_t *pkt,
4349 uint8_t inq_len)
4350 {
4351 dma_mem_t dma_mem;
4352 int rval, retries;
4353 uint32_t pkt_size, cnt;
4354 uint16_t comp_status;
4355 uint8_t scsi_status_h, scsi_status_l, *reqs;
4356 caddr_t inq_data;
4357
4358 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
4359
4360 if (DRIVER_SUSPENDED(ha)) {
4361 EL(ha, "failed, loop down\n");
4362 return (QL_FUNCTION_TIMEOUT);
4363 }
4364
4365 pkt_size = (uint32_t)(sizeof (ql_mbx_iocb_t) + inq_len);
4366 bzero((caddr_t)pkt, pkt_size);
4367
4368 inq_data = (caddr_t)pkt + sizeof (ql_mbx_iocb_t);
4369
4370 /* Get DMA memory for the IOCB */
4371 if (ql_get_dma_mem(ha, &dma_mem, inq_len,
4372 LITTLE_ENDIAN_DMA, QL_DMA_RING_ALIGN) != QL_SUCCESS) {
4373 cmn_err(CE_WARN, "%s(%d): DMA memory "
4374 "alloc failed", QL_NAME, ha->instance);
4375 return (0);
4376 }
4377
4378 for (retries = 0; retries < 4; retries++) {
4379 if (CFG_IST(ha, CFG_CTRL_24258081)) {
4380 pkt->cmd24.entry_type = IOCB_CMD_TYPE_7;
4381 pkt->cmd24.entry_count = 1;
4382
4383 /* Set LUN number */
4384 pkt->cmd24.fcp_lun[2] = LSB(lun);
4385 pkt->cmd24.fcp_lun[3] = MSB(lun);
4386
4387 /* Set N_port handle */
4388 pkt->cmd24.n_port_hdl = (uint16_t)LE_16(tq->loop_id);
4389
4390 /* Set target ID */
4391 pkt->cmd24.target_id[0] = tq->d_id.b.al_pa;
4392 pkt->cmd24.target_id[1] = tq->d_id.b.area;
4393 pkt->cmd24.target_id[2] = tq->d_id.b.domain;
4394
4395 /* Set Virtual Port ID */
4396 pkt->cmd24.vp_index = ha->vp_index;
4397
4398 /* Set ISP command timeout. */
4399 pkt->cmd24.timeout = LE_16(15);
4400
4401 /* Load SCSI CDB */
4402 pkt->cmd24.scsi_cdb[0] = SCMD_INQUIRY;
4403 pkt->cmd24.scsi_cdb[4] = inq_len;
4404 for (cnt = 0; cnt < MAX_CMDSZ; cnt += 4) {
4405 ql_chg_endian((uint8_t *)&pkt->cmd24.scsi_cdb
4406 + cnt, 4);
4407 }
4408
4409 /* Set tag queue control flags */
4410 pkt->cmd24.task = TA_STAG;
4411
4412 /* Set transfer direction. */
4413 pkt->cmd24.control_flags = CF_RD;
4414
4415 /* Set data segment count. */
4416 pkt->cmd24.dseg_count = LE_16(1);
4417
4418 /* Load total byte count. */
4419 pkt->cmd24.total_byte_count = LE_32(inq_len);
4420
4421 /* Load data descriptor. */
4422 pkt->cmd24.dseg_0_address[0] = (uint32_t)
4423 LE_32(LSD(dma_mem.cookie.dmac_laddress));
4424 pkt->cmd24.dseg_0_address[1] = (uint32_t)
4425 LE_32(MSD(dma_mem.cookie.dmac_laddress));
4426 pkt->cmd24.dseg_0_length = LE_32(inq_len);
4427 } else if (CFG_IST(ha, CFG_ENABLE_64BIT_ADDRESSING)) {
4428 pkt->cmd3.entry_type = IOCB_CMD_TYPE_3;
4429 cnt = CMD_TYPE_3_DATA_SEGMENTS;
4430
4431 pkt->cmd3.entry_count = 1;
4432 if (CFG_IST(ha, CFG_EXT_FW_INTERFACE)) {
4433 pkt->cmd3.target_l = LSB(tq->loop_id);
4434 pkt->cmd3.target_h = MSB(tq->loop_id);
4435 } else {
4436 pkt->cmd3.target_h = LSB(tq->loop_id);
4437 }
4438 pkt->cmd3.lun_l = LSB(lun);
4439 pkt->cmd3.lun_h = MSB(lun);
4440 pkt->cmd3.control_flags_l = CF_DATA_IN | CF_STAG;
4441 pkt->cmd3.timeout = LE_16(15);
4442 pkt->cmd3.scsi_cdb[0] = SCMD_INQUIRY;
4443 pkt->cmd3.scsi_cdb[4] = inq_len;
4444 pkt->cmd3.dseg_count = LE_16(1);
4445 pkt->cmd3.byte_count = LE_32(inq_len);
4446 pkt->cmd3.dseg_0_address[0] = (uint32_t)
4447 LE_32(LSD(dma_mem.cookie.dmac_laddress));
4448 pkt->cmd3.dseg_0_address[1] = (uint32_t)
4449 LE_32(MSD(dma_mem.cookie.dmac_laddress));
4450 pkt->cmd3.dseg_0_length = LE_32(inq_len);
4451 } else {
4452 pkt->cmd.entry_type = IOCB_CMD_TYPE_2;
4453 cnt = CMD_TYPE_2_DATA_SEGMENTS;
4454
4455 pkt->cmd.entry_count = 1;
4456 if (CFG_IST(ha, CFG_EXT_FW_INTERFACE)) {
4457 pkt->cmd.target_l = LSB(tq->loop_id);
4458 pkt->cmd.target_h = MSB(tq->loop_id);
4459 } else {
4460 pkt->cmd.target_h = LSB(tq->loop_id);
4461 }
4462 pkt->cmd.lun_l = LSB(lun);
4463 pkt->cmd.lun_h = MSB(lun);
4464 pkt->cmd.control_flags_l = CF_DATA_IN | CF_STAG;
4465 pkt->cmd.timeout = LE_16(15);
4466 pkt->cmd.scsi_cdb[0] = SCMD_INQUIRY;
4467 pkt->cmd.scsi_cdb[4] = inq_len;
4468 pkt->cmd.dseg_count = LE_16(1);
4469 pkt->cmd.byte_count = LE_32(inq_len);
4470 pkt->cmd.dseg_0_address = (uint32_t)
4471 LE_32(LSD(dma_mem.cookie.dmac_laddress));
4472 pkt->cmd.dseg_0_length = LE_32(inq_len);
4473 }
4474
4475 /* rval = ql_issue_mbx_iocb(ha, (caddr_t)pkt, pkt_size); */
4476 rval = ql_issue_mbx_iocb(ha, (caddr_t)pkt,
4477 sizeof (ql_mbx_iocb_t));
4478
4479 /* Sync in coming IOCB DMA buffer. */
4480 (void) ddi_dma_sync(dma_mem.dma_handle, 0, dma_mem.size,
4481 DDI_DMA_SYNC_FORKERNEL);
4482 /* Copy in coming DMA data. */
4483 ddi_rep_get8(dma_mem.acc_handle, (uint8_t *)inq_data,
4484 (uint8_t *)dma_mem.bp, dma_mem.size, DDI_DEV_AUTOINCR);
4485
4486 if (CFG_IST(ha, CFG_CTRL_24258081)) {
4487 pkt->sts24.entry_status = (uint8_t)
4488 (pkt->sts24.entry_status & 0x3c);
4489 comp_status = (uint16_t)LE_16(pkt->sts24.comp_status);
4490 scsi_status_h = pkt->sts24.scsi_status_h;
4491 scsi_status_l = pkt->sts24.scsi_status_l;
4492 cnt = scsi_status_h & FCP_RSP_LEN_VALID ?
4493 LE_32(pkt->sts24.fcp_rsp_data_length) : 0;
4494 reqs = &pkt->sts24.rsp_sense_data[cnt];
4495 } else {
4496 pkt->sts.entry_status = (uint8_t)
4497 (pkt->sts.entry_status & 0x7e);
4498 comp_status = (uint16_t)LE_16(pkt->sts.comp_status);
4499 scsi_status_h = pkt->sts.scsi_status_h;
4500 scsi_status_l = pkt->sts.scsi_status_l;
4501 reqs = &pkt->sts.req_sense_data[0];
4502 }
4503 if (rval == QL_SUCCESS && pkt->sts.entry_status != 0) {
4504 EL(ha, "failed, entry_status=%xh, d_id=%xh\n",
4505 pkt->sts.entry_status, tq->d_id.b24);
4506 rval = QL_FUNCTION_PARAMETER_ERROR;
4507 }
4508
4509 if (rval != QL_SUCCESS || comp_status != CS_COMPLETE ||
4510 scsi_status_l & STATUS_CHECK) {
4511 EL(ha, "failed, issue_iocb=%xh, d_id=%xh, cs=%xh, "
4512 "ss_h=%xh, ss_l=%xh\n", rval, tq->d_id.b24,
4513 comp_status, scsi_status_h, scsi_status_l);
4514
4515 if (rval == QL_SUCCESS) {
4516 if ((comp_status == CS_TIMEOUT) ||
4517 (comp_status == CS_PORT_UNAVAILABLE) ||
4518 (comp_status == CS_PORT_LOGGED_OUT)) {
4519 rval = QL_FUNCTION_TIMEOUT;
4520 break;
4521 }
4522 rval = QL_FUNCTION_FAILED;
4523 }
4524
4525 if (scsi_status_l & STATUS_CHECK) {
4526 EL(ha, "STATUS_CHECK Sense Data\n%2xh%3xh"
4527 "%3xh%3xh%3xh%3xh%3xh%3xh%3xh%3xh%3xh"
4528 "%3xh%3xh%3xh%3xh%3xh%3xh%3xh\n", reqs[0],
4529 reqs[1], reqs[2], reqs[3], reqs[4],
4530 reqs[5], reqs[6], reqs[7], reqs[8],
4531 reqs[9], reqs[10], reqs[11], reqs[12],
4532 reqs[13], reqs[14], reqs[15], reqs[16],
4533 reqs[17]);
4534 }
4535 } else {
4536 break;
4537 }
4538 }
4539 ql_free_dma_resource(ha, &dma_mem);
4540
4541 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
4542
4543 return (rval);
4544 }
4545
4546 /*
4547 * ql_get_buffer_data
4548 * Copies data from user space to kernal buffer.
4549 *
4550 * Input:
4551 * src: User source buffer address.
4552 * dst: Kernal destination buffer address.
4553 * size: Amount of data.
4554 * mode: flags.
4555 *
4556 * Returns:
4557 * Returns number of bytes transferred.
4558 *
4559 * Context:
4560 * Kernel context.
4561 */
4562 static uint32_t
ql_get_buffer_data(caddr_t src,caddr_t dst,uint32_t size,int mode)4563 ql_get_buffer_data(caddr_t src, caddr_t dst, uint32_t size, int mode)
4564 {
4565 uint32_t cnt;
4566
4567 for (cnt = 0; cnt < size; cnt++) {
4568 if (ddi_copyin(src++, dst++, 1, mode) != 0) {
4569 QL_PRINT_2(CE_CONT, "failed, ddi_copyin\n");
4570 break;
4571 }
4572 }
4573
4574 return (cnt);
4575 }
4576
4577 /*
4578 * ql_send_buffer_data
4579 * Copies data from kernal buffer to user space.
4580 *
4581 * Input:
4582 * src: Kernal source buffer address.
4583 * dst: User destination buffer address.
4584 * size: Amount of data.
4585 * mode: flags.
4586 *
4587 * Returns:
4588 * Returns number of bytes transferred.
4589 *
4590 * Context:
4591 * Kernel context.
4592 */
4593 static uint32_t
ql_send_buffer_data(caddr_t src,caddr_t dst,uint32_t size,int mode)4594 ql_send_buffer_data(caddr_t src, caddr_t dst, uint32_t size, int mode)
4595 {
4596 uint32_t cnt;
4597
4598 for (cnt = 0; cnt < size; cnt++) {
4599 if (ddi_copyout(src++, dst++, 1, mode) != 0) {
4600 QL_PRINT_2(CE_CONT, "failed, ddi_copyin\n");
4601 break;
4602 }
4603 }
4604
4605 return (cnt);
4606 }
4607
4608 /*
4609 * ql_find_port
4610 * Locates device queue.
4611 *
4612 * Input:
4613 * ha: adapter state pointer.
4614 * name: device port name.
4615 *
4616 * Returns:
4617 * Returns target queue pointer.
4618 *
4619 * Context:
4620 * Kernel context.
4621 */
4622 static ql_tgt_t *
ql_find_port(ql_adapter_state_t * ha,uint8_t * name,uint16_t type)4623 ql_find_port(ql_adapter_state_t *ha, uint8_t *name, uint16_t type)
4624 {
4625 ql_link_t *link;
4626 ql_tgt_t *tq;
4627 uint16_t index;
4628
4629 /* Scan port list for requested target */
4630 for (index = 0; index < DEVICE_HEAD_LIST_SIZE; index++) {
4631 for (link = ha->dev[index].first; link != NULL;
4632 link = link->next) {
4633 tq = link->base_address;
4634
4635 switch (type) {
4636 case QLNT_LOOP_ID:
4637 if (bcmp(name, &tq->loop_id,
4638 sizeof (uint16_t)) == 0) {
4639 return (tq);
4640 }
4641 break;
4642 case QLNT_PORT:
4643 if (bcmp(name, tq->port_name, 8) == 0) {
4644 return (tq);
4645 }
4646 break;
4647 case QLNT_NODE:
4648 if (bcmp(name, tq->node_name, 8) == 0) {
4649 return (tq);
4650 }
4651 break;
4652 case QLNT_PID:
4653 if (bcmp(name, tq->d_id.r.d_id,
4654 sizeof (tq->d_id.r.d_id)) == 0) {
4655 return (tq);
4656 }
4657 break;
4658 default:
4659 EL(ha, "failed, invalid type=%d\n", type);
4660 return (NULL);
4661 }
4662 }
4663 }
4664
4665 return (NULL);
4666 }
4667
4668 /*
4669 * ql_24xx_flash_desc
4670 * Get flash descriptor table.
4671 *
4672 * Input:
4673 * ha: adapter state pointer.
4674 *
4675 * Returns:
4676 * ql local function return status code.
4677 *
4678 * Context:
4679 * Kernel context.
4680 */
4681 static int
ql_24xx_flash_desc(ql_adapter_state_t * ha)4682 ql_24xx_flash_desc(ql_adapter_state_t *ha)
4683 {
4684 uint32_t cnt;
4685 uint16_t chksum, *bp, data;
4686 int rval;
4687 flash_desc_t *fdesc;
4688 ql_xioctl_t *xp = ha->xioctl;
4689
4690 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
4691
4692 if (ha->flash_desc_addr == 0) {
4693 QL_PRINT_9(CE_CONT, "(%d): desc ptr=0\n", ha->instance);
4694 return (QL_FUNCTION_FAILED);
4695 }
4696
4697 if ((fdesc = kmem_zalloc(sizeof (flash_desc_t), KM_SLEEP)) == NULL) {
4698 EL(ha, "kmem_zalloc=null\n");
4699 return (QL_MEMORY_ALLOC_FAILED);
4700 }
4701 rval = ql_dump_fcode(ha, (uint8_t *)fdesc, sizeof (flash_desc_t),
4702 ha->flash_desc_addr << 2);
4703 if (rval != QL_SUCCESS) {
4704 EL(ha, "read status=%xh\n", rval);
4705 kmem_free(fdesc, sizeof (flash_desc_t));
4706 return (rval);
4707 }
4708
4709 chksum = 0;
4710 bp = (uint16_t *)fdesc;
4711 for (cnt = 0; cnt < (sizeof (flash_desc_t)) / 2; cnt++) {
4712 data = *bp++;
4713 LITTLE_ENDIAN_16(&data);
4714 chksum += data;
4715 }
4716
4717 LITTLE_ENDIAN_32(&fdesc->flash_valid);
4718 LITTLE_ENDIAN_16(&fdesc->flash_version);
4719 LITTLE_ENDIAN_16(&fdesc->flash_len);
4720 LITTLE_ENDIAN_16(&fdesc->flash_checksum);
4721 LITTLE_ENDIAN_16(&fdesc->flash_manuf);
4722 LITTLE_ENDIAN_16(&fdesc->flash_id);
4723 LITTLE_ENDIAN_32(&fdesc->block_size);
4724 LITTLE_ENDIAN_32(&fdesc->alt_block_size);
4725 LITTLE_ENDIAN_32(&fdesc->flash_size);
4726 LITTLE_ENDIAN_32(&fdesc->write_enable_data);
4727 LITTLE_ENDIAN_32(&fdesc->read_timeout);
4728
4729 /* flash size in desc table is in 1024 bytes */
4730 fdesc->flash_size = fdesc->flash_size * 0x400;
4731
4732 if (chksum != 0 || fdesc->flash_valid != FLASH_DESC_VAILD ||
4733 fdesc->flash_version != FLASH_DESC_VERSION) {
4734 EL(ha, "invalid descriptor table\n");
4735 kmem_free(fdesc, sizeof (flash_desc_t));
4736 return (QL_FUNCTION_FAILED);
4737 }
4738
4739 bcopy(fdesc, &xp->fdesc, sizeof (flash_desc_t));
4740 kmem_free(fdesc, sizeof (flash_desc_t));
4741
4742 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
4743
4744 return (QL_SUCCESS);
4745 }
4746
4747 /*
4748 * ql_setup_flash
4749 * Gets the manufacturer and id number of the flash chip, and
4750 * sets up the size parameter.
4751 *
4752 * Input:
4753 * ha: adapter state pointer.
4754 *
4755 * Returns:
4756 * int: ql local function return status code.
4757 *
4758 * Context:
4759 * Kernel context.
4760 */
4761 static int
ql_setup_flash(ql_adapter_state_t * ha)4762 ql_setup_flash(ql_adapter_state_t *ha)
4763 {
4764 ql_xioctl_t *xp = ha->xioctl;
4765 int rval = QL_SUCCESS;
4766
4767 if (xp->fdesc.flash_size != 0) {
4768 return (rval);
4769 }
4770
4771 if (CFG_IST(ha, CFG_CTRL_2200) && !ha->subven_id) {
4772 return (QL_FUNCTION_FAILED);
4773 }
4774
4775 if (CFG_IST(ha, CFG_CTRL_258081)) {
4776 /*
4777 * Temporarily set the ha->xioctl->fdesc.flash_size to
4778 * 25xx flash size to avoid failing of ql_dump_focde.
4779 */
4780 if (CFG_IST(ha, CFG_CTRL_8021)) {
4781 ha->xioctl->fdesc.flash_size = 0x800000;
4782 } else if (CFG_IST(ha, CFG_CTRL_25XX)) {
4783 ha->xioctl->fdesc.flash_size = 0x200000;
4784 } else {
4785 ha->xioctl->fdesc.flash_size = 0x400000;
4786 }
4787
4788 if (ql_24xx_flash_desc(ha) == QL_SUCCESS) {
4789 EL(ha, "flash desc table ok, exit\n");
4790 return (rval);
4791 }
4792 if (CFG_IST(ha, CFG_CTRL_8021)) {
4793 xp->fdesc.flash_manuf = WINBOND_FLASH;
4794 xp->fdesc.flash_id = WINBOND_FLASHID;
4795 xp->fdesc.flash_len = 0x17;
4796 } else {
4797 (void) ql_24xx_flash_id(ha);
4798 }
4799
4800 } else if (CFG_IST(ha, CFG_CTRL_2422)) {
4801 (void) ql_24xx_flash_id(ha);
4802 } else {
4803 ql_flash_enable(ha);
4804
4805 ql_write_flash_byte(ha, 0x5555, 0xaa);
4806 ql_write_flash_byte(ha, 0x2aaa, 0x55);
4807 ql_write_flash_byte(ha, 0x5555, 0x90);
4808 xp->fdesc.flash_manuf = (uint8_t)ql_read_flash_byte(ha, 0x0000);
4809
4810 if (CFG_IST(ha, CFG_SBUS_CARD)) {
4811 ql_write_flash_byte(ha, 0xaaaa, 0xaa);
4812 ql_write_flash_byte(ha, 0x5555, 0x55);
4813 ql_write_flash_byte(ha, 0xaaaa, 0x90);
4814 xp->fdesc.flash_id = (uint16_t)
4815 ql_read_flash_byte(ha, 0x0002);
4816 } else {
4817 ql_write_flash_byte(ha, 0x5555, 0xaa);
4818 ql_write_flash_byte(ha, 0x2aaa, 0x55);
4819 ql_write_flash_byte(ha, 0x5555, 0x90);
4820 xp->fdesc.flash_id = (uint16_t)
4821 ql_read_flash_byte(ha, 0x0001);
4822 }
4823
4824 ql_write_flash_byte(ha, 0x5555, 0xaa);
4825 ql_write_flash_byte(ha, 0x2aaa, 0x55);
4826 ql_write_flash_byte(ha, 0x5555, 0xf0);
4827
4828 ql_flash_disable(ha);
4829 }
4830
4831 /* Default flash descriptor table. */
4832 xp->fdesc.write_statusreg_cmd = 1;
4833 xp->fdesc.write_enable_bits = 0;
4834 xp->fdesc.unprotect_sector_cmd = 0;
4835 xp->fdesc.protect_sector_cmd = 0;
4836 xp->fdesc.write_disable_bits = 0x9c;
4837 xp->fdesc.block_size = 0x10000;
4838 xp->fdesc.erase_cmd = 0xd8;
4839
4840 switch (xp->fdesc.flash_manuf) {
4841 case AMD_FLASH:
4842 switch (xp->fdesc.flash_id) {
4843 case SPAN_FLASHID_2048K:
4844 xp->fdesc.flash_size = 0x200000;
4845 break;
4846 case AMD_FLASHID_1024K:
4847 xp->fdesc.flash_size = 0x100000;
4848 break;
4849 case AMD_FLASHID_512K:
4850 case AMD_FLASHID_512Kt:
4851 case AMD_FLASHID_512Kb:
4852 if (CFG_IST(ha, CFG_SBUS_CARD)) {
4853 xp->fdesc.flash_size = QL_SBUS_FCODE_SIZE;
4854 } else {
4855 xp->fdesc.flash_size = 0x80000;
4856 }
4857 break;
4858 case AMD_FLASHID_128K:
4859 xp->fdesc.flash_size = 0x20000;
4860 break;
4861 default:
4862 rval = QL_FUNCTION_FAILED;
4863 break;
4864 }
4865 break;
4866 case ST_FLASH:
4867 switch (xp->fdesc.flash_id) {
4868 case ST_FLASHID_128K:
4869 xp->fdesc.flash_size = 0x20000;
4870 break;
4871 case ST_FLASHID_512K:
4872 xp->fdesc.flash_size = 0x80000;
4873 break;
4874 case ST_FLASHID_M25PXX:
4875 if (xp->fdesc.flash_len == 0x14) {
4876 xp->fdesc.flash_size = 0x100000;
4877 } else if (xp->fdesc.flash_len == 0x15) {
4878 xp->fdesc.flash_size = 0x200000;
4879 } else {
4880 rval = QL_FUNCTION_FAILED;
4881 }
4882 break;
4883 default:
4884 rval = QL_FUNCTION_FAILED;
4885 break;
4886 }
4887 break;
4888 case SST_FLASH:
4889 switch (xp->fdesc.flash_id) {
4890 case SST_FLASHID_128K:
4891 xp->fdesc.flash_size = 0x20000;
4892 break;
4893 case SST_FLASHID_1024K_A:
4894 xp->fdesc.flash_size = 0x100000;
4895 xp->fdesc.block_size = 0x8000;
4896 xp->fdesc.erase_cmd = 0x52;
4897 break;
4898 case SST_FLASHID_1024K:
4899 case SST_FLASHID_1024K_B:
4900 xp->fdesc.flash_size = 0x100000;
4901 break;
4902 case SST_FLASHID_2048K:
4903 xp->fdesc.flash_size = 0x200000;
4904 break;
4905 default:
4906 rval = QL_FUNCTION_FAILED;
4907 break;
4908 }
4909 break;
4910 case MXIC_FLASH:
4911 switch (xp->fdesc.flash_id) {
4912 case MXIC_FLASHID_512K:
4913 xp->fdesc.flash_size = 0x80000;
4914 break;
4915 case MXIC_FLASHID_1024K:
4916 xp->fdesc.flash_size = 0x100000;
4917 break;
4918 case MXIC_FLASHID_25LXX:
4919 if (xp->fdesc.flash_len == 0x14) {
4920 xp->fdesc.flash_size = 0x100000;
4921 } else if (xp->fdesc.flash_len == 0x15) {
4922 xp->fdesc.flash_size = 0x200000;
4923 } else {
4924 rval = QL_FUNCTION_FAILED;
4925 }
4926 break;
4927 default:
4928 rval = QL_FUNCTION_FAILED;
4929 break;
4930 }
4931 break;
4932 case ATMEL_FLASH:
4933 switch (xp->fdesc.flash_id) {
4934 case ATMEL_FLASHID_1024K:
4935 xp->fdesc.flash_size = 0x100000;
4936 xp->fdesc.write_disable_bits = 0xbc;
4937 xp->fdesc.unprotect_sector_cmd = 0x39;
4938 xp->fdesc.protect_sector_cmd = 0x36;
4939 break;
4940 default:
4941 rval = QL_FUNCTION_FAILED;
4942 break;
4943 }
4944 break;
4945 case WINBOND_FLASH:
4946 switch (xp->fdesc.flash_id) {
4947 case WINBOND_FLASHID:
4948 if (xp->fdesc.flash_len == 0x15) {
4949 xp->fdesc.flash_size = 0x200000;
4950 } else if (xp->fdesc.flash_len == 0x16) {
4951 xp->fdesc.flash_size = 0x400000;
4952 } else if (xp->fdesc.flash_len == 0x17) {
4953 xp->fdesc.flash_size = 0x800000;
4954 } else {
4955 rval = QL_FUNCTION_FAILED;
4956 }
4957 break;
4958 default:
4959 rval = QL_FUNCTION_FAILED;
4960 break;
4961 }
4962 break;
4963 case INTEL_FLASH:
4964 switch (xp->fdesc.flash_id) {
4965 case INTEL_FLASHID:
4966 if (xp->fdesc.flash_len == 0x11) {
4967 xp->fdesc.flash_size = 0x200000;
4968 } else if (xp->fdesc.flash_len == 0x12) {
4969 xp->fdesc.flash_size = 0x400000;
4970 } else if (xp->fdesc.flash_len == 0x13) {
4971 xp->fdesc.flash_size = 0x800000;
4972 } else {
4973 rval = QL_FUNCTION_FAILED;
4974 }
4975 break;
4976 default:
4977 rval = QL_FUNCTION_FAILED;
4978 break;
4979 }
4980 break;
4981 default:
4982 rval = QL_FUNCTION_FAILED;
4983 break;
4984 }
4985
4986 /* Try flash table later. */
4987 if (rval != QL_SUCCESS && CFG_IST(ha, CFG_CTRL_24258081)) {
4988 EL(ha, "no default id\n");
4989 return (QL_SUCCESS);
4990 }
4991
4992 /*
4993 * hack for non std 2312 and 6312 boards. hardware people need to
4994 * use either the 128k flash chip (original), or something larger.
4995 * For driver purposes, we'll treat it as a 128k flash chip.
4996 */
4997 if ((ha->device_id == 0x2312 || ha->device_id == 0x6312 ||
4998 ha->device_id == 0x6322) && (xp->fdesc.flash_size > 0x20000) &&
4999 (CFG_IST(ha, CFG_SBUS_CARD) == 0)) {
5000 EL(ha, "chip exceeds max size: %xh, using 128k\n",
5001 xp->fdesc.flash_size);
5002 xp->fdesc.flash_size = 0x20000;
5003 }
5004
5005 if (rval == QL_SUCCESS) {
5006 EL(ha, "man_id=%xh, flash_id=%xh, size=%xh\n",
5007 xp->fdesc.flash_manuf, xp->fdesc.flash_id,
5008 xp->fdesc.flash_size);
5009 } else {
5010 EL(ha, "unsupported mfr / type: man_id=%xh, flash_id=%xh\n",
5011 xp->fdesc.flash_manuf, xp->fdesc.flash_id);
5012 }
5013
5014 return (rval);
5015 }
5016
5017 /*
5018 * ql_flash_fcode_load
5019 * Loads fcode data into flash from application.
5020 *
5021 * Input:
5022 * ha: adapter state pointer.
5023 * bp: user buffer address.
5024 * size: user buffer size.
5025 * mode: flags
5026 *
5027 * Returns:
5028 *
5029 * Context:
5030 * Kernel context.
5031 */
5032 static int
ql_flash_fcode_load(ql_adapter_state_t * ha,void * bp,uint32_t bsize,int mode)5033 ql_flash_fcode_load(ql_adapter_state_t *ha, void *bp, uint32_t bsize,
5034 int mode)
5035 {
5036 uint8_t *bfp;
5037 ql_xioctl_t *xp = ha->xioctl;
5038 int rval = 0;
5039
5040 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
5041
5042 if (bsize > xp->fdesc.flash_size) {
5043 EL(ha, "failed, bufsize: %xh, flash size: %xh\n", bsize,
5044 xp->fdesc.flash_size);
5045 return (ENOMEM);
5046 }
5047
5048 if ((bfp = (uint8_t *)kmem_zalloc(bsize, KM_SLEEP)) == NULL) {
5049 EL(ha, "failed, kmem_zalloc\n");
5050 rval = ENOMEM;
5051 } else {
5052 if (ddi_copyin(bp, bfp, bsize, mode) != 0) {
5053 EL(ha, "failed, ddi_copyin\n");
5054 rval = EFAULT;
5055 } else if (ql_load_fcode(ha, bfp, bsize, 0) != QL_SUCCESS) {
5056 EL(ha, "failed, load_fcode\n");
5057 rval = EFAULT;
5058 } else {
5059 /* Reset caches on all adapter instances. */
5060 ql_update_flash_caches(ha);
5061 rval = 0;
5062 }
5063 kmem_free(bfp, bsize);
5064 }
5065
5066 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
5067
5068 return (rval);
5069 }
5070
5071 /*
5072 * ql_load_fcode
5073 * Loads fcode in to flash.
5074 *
5075 * Input:
5076 * ha: adapter state pointer.
5077 * dp: data pointer.
5078 * size: data length.
5079 * addr: flash byte address.
5080 *
5081 * Returns:
5082 * ql local function return status code.
5083 *
5084 * Context:
5085 * Kernel context.
5086 */
5087 int
ql_load_fcode(ql_adapter_state_t * ha,uint8_t * dp,uint32_t size,uint32_t addr)5088 ql_load_fcode(ql_adapter_state_t *ha, uint8_t *dp, uint32_t size, uint32_t addr)
5089 {
5090 uint32_t cnt;
5091 int rval;
5092
5093 if (CFG_IST(ha, CFG_CTRL_24258081)) {
5094 return (ql_24xx_load_flash(ha, dp, size, addr));
5095 }
5096
5097 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
5098
5099 if (CFG_IST(ha, CFG_SBUS_CARD)) {
5100 /*
5101 * sbus has an additional check to make
5102 * sure they don't brick the HBA.
5103 */
5104 if (dp[0] != 0xf1) {
5105 EL(ha, "failed, incorrect fcode for sbus\n");
5106 return (QL_FUNCTION_PARAMETER_ERROR);
5107 }
5108 }
5109
5110 GLOBAL_HW_LOCK();
5111
5112 /* Enable Flash Read/Write. */
5113 ql_flash_enable(ha);
5114
5115 /* Erase flash prior to write. */
5116 rval = ql_erase_flash(ha, 0);
5117
5118 if (rval == QL_SUCCESS) {
5119 /* Write fcode data to flash. */
5120 for (cnt = 0; cnt < (uint32_t)size; cnt++) {
5121 /* Allow other system activity. */
5122 if (cnt % 0x1000 == 0) {
5123 drv_usecwait(1);
5124 }
5125 rval = ql_program_flash_address(ha, addr++, *dp++);
5126 if (rval != QL_SUCCESS)
5127 break;
5128 }
5129 }
5130
5131 ql_flash_disable(ha);
5132
5133 GLOBAL_HW_UNLOCK();
5134
5135 if (rval != QL_SUCCESS) {
5136 EL(ha, "failed, rval=%xh\n", rval);
5137 } else {
5138 /*EMPTY*/
5139 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
5140 }
5141 return (rval);
5142 }
5143
5144 /*
5145 * ql_flash_fcode_dump
5146 * Dumps FLASH to application.
5147 *
5148 * Input:
5149 * ha: adapter state pointer.
5150 * bp: user buffer address.
5151 * bsize: user buffer size
5152 * faddr: flash byte address
5153 * mode: flags
5154 *
5155 * Returns:
5156 *
5157 * Context:
5158 * Kernel context.
5159 */
5160 static int
ql_flash_fcode_dump(ql_adapter_state_t * ha,void * bp,uint32_t bsize,uint32_t faddr,int mode)5161 ql_flash_fcode_dump(ql_adapter_state_t *ha, void *bp, uint32_t bsize,
5162 uint32_t faddr, int mode)
5163 {
5164 uint8_t *bfp;
5165 int rval;
5166 ql_xioctl_t *xp = ha->xioctl;
5167
5168 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
5169
5170 /* adjust max read size to flash size */
5171 if (bsize > xp->fdesc.flash_size) {
5172 EL(ha, "adjusting req=%xh, max=%xh\n", bsize,
5173 xp->fdesc.flash_size);
5174 bsize = xp->fdesc.flash_size;
5175 }
5176
5177 if ((bfp = (uint8_t *)kmem_zalloc(bsize, KM_SLEEP)) == NULL) {
5178 EL(ha, "failed, kmem_zalloc\n");
5179 rval = ENOMEM;
5180 } else {
5181 /* Dump Flash fcode. */
5182 rval = ql_dump_fcode(ha, bfp, bsize, faddr);
5183
5184 if (rval != QL_SUCCESS) {
5185 EL(ha, "failed, dump_fcode = %x\n", rval);
5186 rval = EFAULT;
5187 } else if (ddi_copyout(bfp, bp, bsize, mode) != 0) {
5188 EL(ha, "failed, ddi_copyout\n");
5189 rval = EFAULT;
5190 } else {
5191 rval = 0;
5192 }
5193 kmem_free(bfp, bsize);
5194 }
5195
5196 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
5197
5198 return (rval);
5199 }
5200
5201 /*
5202 * ql_dump_fcode
5203 * Dumps fcode from flash.
5204 *
5205 * Input:
5206 * ha: adapter state pointer.
5207 * dp: data pointer.
5208 * size: data length in bytes.
5209 * startpos: starting position in flash (byte address).
5210 *
5211 * Returns:
5212 * ql local function return status code.
5213 *
5214 * Context:
5215 * Kernel context.
5216 *
5217 */
5218 int
ql_dump_fcode(ql_adapter_state_t * ha,uint8_t * dp,uint32_t size,uint32_t startpos)5219 ql_dump_fcode(ql_adapter_state_t *ha, uint8_t *dp, uint32_t size,
5220 uint32_t startpos)
5221 {
5222 uint32_t cnt, data, addr;
5223 uint8_t bp[4], *src;
5224 int fp_rval, rval = QL_SUCCESS;
5225 dma_mem_t mem;
5226
5227 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
5228
5229 /* make sure startpos+size doesn't exceed flash */
5230 if (size + startpos > ha->xioctl->fdesc.flash_size) {
5231 EL(ha, "exceeded flash range, sz=%xh, stp=%xh, flsz=%xh\n",
5232 size, startpos, ha->xioctl->fdesc.flash_size);
5233 return (QL_FUNCTION_PARAMETER_ERROR);
5234 }
5235
5236 if (CFG_IST(ha, CFG_CTRL_24258081)) {
5237 /* check start addr is 32 bit aligned for 24xx */
5238 if ((startpos & 0x3) != 0) {
5239 rval = ql_24xx_read_flash(ha,
5240 ha->flash_data_addr | startpos >> 2, &data);
5241 if (rval != QL_SUCCESS) {
5242 EL(ha, "failed2, rval = %xh\n", rval);
5243 return (rval);
5244 }
5245 bp[0] = LSB(LSW(data));
5246 bp[1] = MSB(LSW(data));
5247 bp[2] = LSB(MSW(data));
5248 bp[3] = MSB(MSW(data));
5249 while (size && startpos & 0x3) {
5250 *dp++ = bp[startpos & 0x3];
5251 startpos++;
5252 size--;
5253 }
5254 if (size == 0) {
5255 QL_PRINT_9(CE_CONT, "(%d): done2\n",
5256 ha->instance);
5257 return (rval);
5258 }
5259 }
5260
5261 /* adjust 24xx start addr for 32 bit words */
5262 addr = startpos / 4 | ha->flash_data_addr;
5263 }
5264
5265 bzero(&mem, sizeof (dma_mem_t));
5266 /* Check for Fast page is supported */
5267 if ((ha->pha->task_daemon_flags & FIRMWARE_UP) &&
5268 (CFG_IST(ha, CFG_CTRL_2581))) {
5269 fp_rval = QL_SUCCESS;
5270 /* Setup DMA buffer. */
5271 rval = ql_get_dma_mem(ha, &mem, size,
5272 LITTLE_ENDIAN_DMA, QL_DMA_DATA_ALIGN);
5273 if (rval != QL_SUCCESS) {
5274 EL(ha, "failed, ql_get_dma_mem=%xh\n",
5275 rval);
5276 return (ENOMEM);
5277 }
5278 } else {
5279 fp_rval = QL_NOT_SUPPORTED;
5280 }
5281
5282 GLOBAL_HW_LOCK();
5283
5284 /* Enable Flash Read/Write. */
5285 if (CFG_IST(ha, CFG_CTRL_24258081) == 0) {
5286 ql_flash_enable(ha);
5287 }
5288
5289 /* Read fcode data from flash. */
5290 while (size) {
5291 /* Allow other system activity. */
5292 if (size % 0x1000 == 0) {
5293 ql_delay(ha, 100000);
5294 }
5295 if (CFG_IST(ha, CFG_CTRL_24258081)) {
5296 if (fp_rval == QL_SUCCESS && (addr & 0x3f) == 0) {
5297 cnt = (size + 3) >> 2;
5298 fp_rval = ql_rd_risc_ram(ha, addr,
5299 mem.cookie.dmac_laddress, cnt);
5300 if (fp_rval == QL_SUCCESS) {
5301 for (src = mem.bp; size; size--) {
5302 *dp++ = *src++;
5303 }
5304 addr += cnt;
5305 continue;
5306 }
5307 }
5308 rval = ql_24xx_read_flash(ha, addr++,
5309 &data);
5310 if (rval != QL_SUCCESS) {
5311 break;
5312 }
5313 bp[0] = LSB(LSW(data));
5314 bp[1] = MSB(LSW(data));
5315 bp[2] = LSB(MSW(data));
5316 bp[3] = MSB(MSW(data));
5317 for (cnt = 0; size && cnt < 4; size--) {
5318 *dp++ = bp[cnt++];
5319 }
5320 } else {
5321 *dp++ = (uint8_t)ql_read_flash_byte(ha, startpos++);
5322 size--;
5323 }
5324 }
5325
5326 if (CFG_IST(ha, CFG_CTRL_24258081) == 0) {
5327 ql_flash_disable(ha);
5328 }
5329
5330 GLOBAL_HW_UNLOCK();
5331
5332 if (mem.dma_handle != NULL) {
5333 ql_free_dma_resource(ha, &mem);
5334 }
5335
5336 if (rval != QL_SUCCESS) {
5337 EL(ha, "failed, rval = %xh\n", rval);
5338 } else {
5339 /*EMPTY*/
5340 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
5341 }
5342 return (rval);
5343 }
5344
5345 /*
5346 * ql_program_flash_address
5347 * Program flash address.
5348 *
5349 * Input:
5350 * ha: adapter state pointer.
5351 * addr: flash byte address.
5352 * data: data to be written to flash.
5353 *
5354 * Returns:
5355 * ql local function return status code.
5356 *
5357 * Context:
5358 * Kernel context.
5359 */
5360 static int
ql_program_flash_address(ql_adapter_state_t * ha,uint32_t addr,uint8_t data)5361 ql_program_flash_address(ql_adapter_state_t *ha, uint32_t addr,
5362 uint8_t data)
5363 {
5364 int rval;
5365
5366 /* Write Program Command Sequence */
5367 if (CFG_IST(ha, CFG_SBUS_CARD)) {
5368 ql_write_flash_byte(ha, 0x5555, 0xa0);
5369 ql_write_flash_byte(ha, addr, data);
5370 } else {
5371 ql_write_flash_byte(ha, 0x5555, 0xaa);
5372 ql_write_flash_byte(ha, 0x2aaa, 0x55);
5373 ql_write_flash_byte(ha, 0x5555, 0xa0);
5374 ql_write_flash_byte(ha, addr, data);
5375 }
5376
5377 /* Wait for write to complete. */
5378 rval = ql_poll_flash(ha, addr, data);
5379
5380 if (rval != QL_SUCCESS) {
5381 EL(ha, "failed, rval=%xh\n", rval);
5382 }
5383 return (rval);
5384 }
5385
5386 /*
5387 * ql_set_rnid_parameters
5388 * Set RNID parameters.
5389 *
5390 * Input:
5391 * ha: adapter state pointer.
5392 * cmd: User space CT arguments pointer.
5393 * mode: flags.
5394 */
5395 static void
ql_set_rnid_parameters(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)5396 ql_set_rnid_parameters(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
5397 {
5398 EXT_SET_RNID_REQ tmp_set;
5399 EXT_RNID_DATA *tmp_buf;
5400 int rval = 0;
5401
5402 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
5403
5404 if (DRIVER_SUSPENDED(ha)) {
5405 EL(ha, "failed, LOOP_NOT_READY\n");
5406 cmd->Status = EXT_STATUS_BUSY;
5407 cmd->ResponseLen = 0;
5408 return;
5409 }
5410
5411 cmd->ResponseLen = 0; /* NO response to caller. */
5412 if (cmd->RequestLen != sizeof (EXT_SET_RNID_REQ)) {
5413 /* parameter error */
5414 EL(ha, "failed, RequestLen < EXT_SET_RNID_REQ, Len=%xh\n",
5415 cmd->RequestLen);
5416 cmd->Status = EXT_STATUS_INVALID_PARAM;
5417 cmd->DetailStatus = EXT_DSTATUS_REQUEST_LEN;
5418 cmd->ResponseLen = 0;
5419 return;
5420 }
5421
5422 rval = ddi_copyin((void*)(uintptr_t)cmd->RequestAdr, &tmp_set,
5423 cmd->RequestLen, mode);
5424 if (rval != 0) {
5425 EL(ha, "failed, ddi_copyin\n");
5426 cmd->Status = EXT_STATUS_COPY_ERR;
5427 cmd->ResponseLen = 0;
5428 return;
5429 }
5430
5431 /* Allocate memory for command. */
5432 tmp_buf = kmem_zalloc(sizeof (EXT_RNID_DATA), KM_SLEEP);
5433 if (tmp_buf == NULL) {
5434 EL(ha, "failed, kmem_zalloc\n");
5435 cmd->Status = EXT_STATUS_NO_MEMORY;
5436 cmd->ResponseLen = 0;
5437 return;
5438 }
5439
5440 rval = ql_get_rnid_params(ha, sizeof (EXT_RNID_DATA),
5441 (caddr_t)tmp_buf);
5442 if (rval != QL_SUCCESS) {
5443 /* error */
5444 EL(ha, "failed, get_rnid_params_mbx=%xh\n", rval);
5445 kmem_free(tmp_buf, sizeof (EXT_RNID_DATA));
5446 cmd->Status = EXT_STATUS_ERR;
5447 cmd->ResponseLen = 0;
5448 return;
5449 }
5450
5451 /* Now set the requested params. */
5452 bcopy(tmp_set.IPVersion, tmp_buf->IPVersion, 2);
5453 bcopy(tmp_set.UDPPortNumber, tmp_buf->UDPPortNumber, 2);
5454 bcopy(tmp_set.IPAddress, tmp_buf->IPAddress, 16);
5455
5456 rval = ql_set_rnid_params(ha, sizeof (EXT_RNID_DATA),
5457 (caddr_t)tmp_buf);
5458 if (rval != QL_SUCCESS) {
5459 /* error */
5460 EL(ha, "failed, set_rnid_params_mbx=%xh\n", rval);
5461 cmd->Status = EXT_STATUS_ERR;
5462 cmd->ResponseLen = 0;
5463 }
5464
5465 kmem_free(tmp_buf, sizeof (EXT_RNID_DATA));
5466
5467 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
5468 }
5469
5470 /*
5471 * ql_get_rnid_parameters
5472 * Get RNID parameters.
5473 *
5474 * Input:
5475 * ha: adapter state pointer.
5476 * cmd: User space CT arguments pointer.
5477 * mode: flags.
5478 */
5479 static void
ql_get_rnid_parameters(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)5480 ql_get_rnid_parameters(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
5481 {
5482 EXT_RNID_DATA *tmp_buf;
5483 uint32_t rval;
5484
5485 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
5486
5487 if (DRIVER_SUSPENDED(ha)) {
5488 EL(ha, "failed, LOOP_NOT_READY\n");
5489 cmd->Status = EXT_STATUS_BUSY;
5490 cmd->ResponseLen = 0;
5491 return;
5492 }
5493
5494 /* Allocate memory for command. */
5495 tmp_buf = kmem_zalloc(sizeof (EXT_RNID_DATA), KM_SLEEP);
5496 if (tmp_buf == NULL) {
5497 EL(ha, "failed, kmem_zalloc\n");
5498 cmd->Status = EXT_STATUS_NO_MEMORY;
5499 cmd->ResponseLen = 0;
5500 return;
5501 }
5502
5503 /* Send command */
5504 rval = ql_get_rnid_params(ha, sizeof (EXT_RNID_DATA),
5505 (caddr_t)tmp_buf);
5506 if (rval != QL_SUCCESS) {
5507 /* error */
5508 EL(ha, "failed, get_rnid_params_mbx=%xh\n", rval);
5509 kmem_free(tmp_buf, sizeof (EXT_RNID_DATA));
5510 cmd->Status = EXT_STATUS_ERR;
5511 cmd->ResponseLen = 0;
5512 return;
5513 }
5514
5515 /* Copy the response */
5516 if (ql_send_buffer_data((caddr_t)tmp_buf,
5517 (caddr_t)(uintptr_t)cmd->ResponseAdr,
5518 sizeof (EXT_RNID_DATA), mode) != sizeof (EXT_RNID_DATA)) {
5519 EL(ha, "failed, ddi_copyout\n");
5520 cmd->Status = EXT_STATUS_COPY_ERR;
5521 cmd->ResponseLen = 0;
5522 } else {
5523 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
5524 cmd->ResponseLen = sizeof (EXT_RNID_DATA);
5525 }
5526
5527 kmem_free(tmp_buf, sizeof (EXT_RNID_DATA));
5528 }
5529
5530 /*
5531 * ql_reset_statistics
5532 * Performs EXT_SC_RST_STATISTICS subcommand. of EXT_CC_SET_DATA.
5533 *
5534 * Input:
5535 * ha: adapter state pointer.
5536 * cmd: Local EXT_IOCTL cmd struct pointer.
5537 *
5538 * Returns:
5539 * None, request status indicated in cmd->Status.
5540 *
5541 * Context:
5542 * Kernel context.
5543 */
5544 static int
ql_reset_statistics(ql_adapter_state_t * ha,EXT_IOCTL * cmd)5545 ql_reset_statistics(ql_adapter_state_t *ha, EXT_IOCTL *cmd)
5546 {
5547 ql_xioctl_t *xp = ha->xioctl;
5548 int rval = 0;
5549
5550 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
5551
5552 if (DRIVER_SUSPENDED(ha)) {
5553 EL(ha, "failed, LOOP_NOT_READY\n");
5554 cmd->Status = EXT_STATUS_BUSY;
5555 cmd->ResponseLen = 0;
5556 return (QL_FUNCTION_SUSPENDED);
5557 }
5558
5559 rval = ql_reset_link_status(ha);
5560 if (rval != QL_SUCCESS) {
5561 EL(ha, "failed, reset_link_status_mbx=%xh\n", rval);
5562 cmd->Status = EXT_STATUS_MAILBOX;
5563 cmd->DetailStatus = rval;
5564 cmd->ResponseLen = 0;
5565 }
5566
5567 TASK_DAEMON_LOCK(ha);
5568 xp->IosRequested = 0;
5569 xp->BytesRequested = 0;
5570 xp->IOInputRequests = 0;
5571 xp->IOOutputRequests = 0;
5572 xp->IOControlRequests = 0;
5573 xp->IOInputMByteCnt = 0;
5574 xp->IOOutputMByteCnt = 0;
5575 xp->IOOutputByteCnt = 0;
5576 xp->IOInputByteCnt = 0;
5577 TASK_DAEMON_UNLOCK(ha);
5578
5579 INTR_LOCK(ha);
5580 xp->ControllerErrorCount = 0;
5581 xp->DeviceErrorCount = 0;
5582 xp->TotalLipResets = 0;
5583 xp->TotalInterrupts = 0;
5584 INTR_UNLOCK(ha);
5585
5586 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
5587
5588 return (rval);
5589 }
5590
5591 /*
5592 * ql_get_statistics
5593 * Performs EXT_SC_GET_STATISTICS subcommand. of EXT_CC_GET_DATA.
5594 *
5595 * Input:
5596 * ha: adapter state pointer.
5597 * cmd: Local EXT_IOCTL cmd struct pointer.
5598 * mode: flags.
5599 *
5600 * Returns:
5601 * None, request status indicated in cmd->Status.
5602 *
5603 * Context:
5604 * Kernel context.
5605 */
5606 static void
ql_get_statistics(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)5607 ql_get_statistics(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
5608 {
5609 EXT_HBA_PORT_STAT ps = {0};
5610 ql_link_stats_t *ls;
5611 int rval;
5612 ql_xioctl_t *xp = ha->xioctl;
5613 int retry = 10;
5614
5615 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
5616
5617 while (ha->task_daemon_flags &
5618 (ABORT_ISP_ACTIVE | LOOP_RESYNC_ACTIVE | DRIVER_STALL)) {
5619 ql_delay(ha, 10000000); /* 10 second delay */
5620
5621 retry--;
5622
5623 if (retry == 0) { /* effectively 100 seconds */
5624 EL(ha, "failed, LOOP_NOT_READY\n");
5625 cmd->Status = EXT_STATUS_BUSY;
5626 cmd->ResponseLen = 0;
5627 return;
5628 }
5629 }
5630
5631 /* Allocate memory for command. */
5632 ls = kmem_zalloc(sizeof (ql_link_stats_t), KM_SLEEP);
5633 if (ls == NULL) {
5634 EL(ha, "failed, kmem_zalloc\n");
5635 cmd->Status = EXT_STATUS_NO_MEMORY;
5636 cmd->ResponseLen = 0;
5637 return;
5638 }
5639
5640 /*
5641 * I think these are supposed to be port statistics
5642 * the loop ID or port ID should be in cmd->Instance.
5643 */
5644 rval = ql_get_status_counts(ha, (uint16_t)
5645 (ha->task_daemon_flags & LOOP_DOWN ? 0xFF : ha->loop_id),
5646 sizeof (ql_link_stats_t), (caddr_t)ls, 0);
5647 if (rval != QL_SUCCESS) {
5648 EL(ha, "failed, get_link_status=%xh, id=%xh\n", rval,
5649 ha->loop_id);
5650 cmd->Status = EXT_STATUS_MAILBOX;
5651 cmd->DetailStatus = rval;
5652 cmd->ResponseLen = 0;
5653 } else {
5654 ps.ControllerErrorCount = xp->ControllerErrorCount;
5655 ps.DeviceErrorCount = xp->DeviceErrorCount;
5656 ps.IoCount = (uint32_t)(xp->IOInputRequests +
5657 xp->IOOutputRequests + xp->IOControlRequests);
5658 ps.MBytesCount = (uint32_t)(xp->IOInputMByteCnt +
5659 xp->IOOutputMByteCnt);
5660 ps.LipResetCount = xp->TotalLipResets;
5661 ps.InterruptCount = xp->TotalInterrupts;
5662 ps.LinkFailureCount = LE_32(ls->link_fail_cnt);
5663 ps.LossOfSyncCount = LE_32(ls->sync_loss_cnt);
5664 ps.LossOfSignalsCount = LE_32(ls->signal_loss_cnt);
5665 ps.PrimitiveSeqProtocolErrorCount = LE_32(ls->prot_err_cnt);
5666 ps.InvalidTransmissionWordCount = LE_32(ls->inv_xmit_cnt);
5667 ps.InvalidCRCCount = LE_32(ls->inv_crc_cnt);
5668
5669 rval = ddi_copyout((void *)&ps,
5670 (void *)(uintptr_t)cmd->ResponseAdr,
5671 sizeof (EXT_HBA_PORT_STAT), mode);
5672 if (rval != 0) {
5673 EL(ha, "failed, ddi_copyout\n");
5674 cmd->Status = EXT_STATUS_COPY_ERR;
5675 cmd->ResponseLen = 0;
5676 } else {
5677 cmd->ResponseLen = sizeof (EXT_HBA_PORT_STAT);
5678 }
5679 }
5680
5681 kmem_free(ls, sizeof (ql_link_stats_t));
5682
5683 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
5684 }
5685
5686 /*
5687 * ql_get_statistics_fc
5688 * Performs EXT_SC_GET_FC_STATISTICS subcommand. of EXT_CC_GET_DATA.
5689 *
5690 * Input:
5691 * ha: adapter state pointer.
5692 * cmd: Local EXT_IOCTL cmd struct pointer.
5693 * mode: flags.
5694 *
5695 * Returns:
5696 * None, request status indicated in cmd->Status.
5697 *
5698 * Context:
5699 * Kernel context.
5700 */
5701 static void
ql_get_statistics_fc(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)5702 ql_get_statistics_fc(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
5703 {
5704 EXT_HBA_PORT_STAT ps = {0};
5705 ql_link_stats_t *ls;
5706 int rval;
5707 uint16_t qlnt;
5708 EXT_DEST_ADDR pextdestaddr;
5709 uint8_t *name;
5710 ql_tgt_t *tq = NULL;
5711 int retry = 10;
5712
5713 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
5714
5715 if (ddi_copyin((void *)(uintptr_t)cmd->RequestAdr,
5716 (void *)&pextdestaddr, sizeof (EXT_DEST_ADDR), mode) != 0) {
5717 EL(ha, "failed, ddi_copyin\n");
5718 cmd->Status = EXT_STATUS_COPY_ERR;
5719 cmd->ResponseLen = 0;
5720 return;
5721 }
5722
5723 qlnt = QLNT_PORT;
5724 name = pextdestaddr.DestAddr.WWPN;
5725
5726 QL_PRINT_9(CE_CONT, "(%d): wwpn=%02x%02x%02x%02x%02x%02x%02x%02x\n",
5727 ha->instance, name[0], name[1], name[2], name[3], name[4],
5728 name[5], name[6], name[7]);
5729
5730 tq = ql_find_port(ha, name, qlnt);
5731
5732 if (tq == NULL || !VALID_TARGET_ID(ha, tq->loop_id)) {
5733 EL(ha, "failed, fc_port not found\n");
5734 cmd->Status = EXT_STATUS_DEV_NOT_FOUND;
5735 cmd->ResponseLen = 0;
5736 return;
5737 }
5738
5739 while (ha->task_daemon_flags &
5740 (ABORT_ISP_ACTIVE | LOOP_RESYNC_ACTIVE | DRIVER_STALL)) {
5741 ql_delay(ha, 10000000); /* 10 second delay */
5742
5743 retry--;
5744
5745 if (retry == 0) { /* effectively 100 seconds */
5746 EL(ha, "failed, LOOP_NOT_READY\n");
5747 cmd->Status = EXT_STATUS_BUSY;
5748 cmd->ResponseLen = 0;
5749 return;
5750 }
5751 }
5752
5753 /* Allocate memory for command. */
5754 ls = kmem_zalloc(sizeof (ql_link_stats_t), KM_SLEEP);
5755 if (ls == NULL) {
5756 EL(ha, "failed, kmem_zalloc\n");
5757 cmd->Status = EXT_STATUS_NO_MEMORY;
5758 cmd->ResponseLen = 0;
5759 return;
5760 }
5761
5762 rval = ql_get_link_status(ha, tq->loop_id, sizeof (ql_link_stats_t),
5763 (caddr_t)ls, 0);
5764 if (rval != QL_SUCCESS) {
5765 EL(ha, "failed, get_link_status=%xh, d_id=%xh\n", rval,
5766 tq->d_id.b24);
5767 cmd->Status = EXT_STATUS_MAILBOX;
5768 cmd->DetailStatus = rval;
5769 cmd->ResponseLen = 0;
5770 } else {
5771 ps.LinkFailureCount = LE_32(ls->link_fail_cnt);
5772 ps.LossOfSyncCount = LE_32(ls->sync_loss_cnt);
5773 ps.LossOfSignalsCount = LE_32(ls->signal_loss_cnt);
5774 ps.PrimitiveSeqProtocolErrorCount = LE_32(ls->prot_err_cnt);
5775 ps.InvalidTransmissionWordCount = LE_32(ls->inv_xmit_cnt);
5776 ps.InvalidCRCCount = LE_32(ls->inv_crc_cnt);
5777
5778 rval = ddi_copyout((void *)&ps,
5779 (void *)(uintptr_t)cmd->ResponseAdr,
5780 sizeof (EXT_HBA_PORT_STAT), mode);
5781
5782 if (rval != 0) {
5783 EL(ha, "failed, ddi_copyout\n");
5784 cmd->Status = EXT_STATUS_COPY_ERR;
5785 cmd->ResponseLen = 0;
5786 } else {
5787 cmd->ResponseLen = sizeof (EXT_HBA_PORT_STAT);
5788 }
5789 }
5790
5791 kmem_free(ls, sizeof (ql_link_stats_t));
5792
5793 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
5794 }
5795
5796 /*
5797 * ql_get_statistics_fc4
5798 * Performs EXT_SC_GET_FC_STATISTICS subcommand. of EXT_CC_GET_DATA.
5799 *
5800 * Input:
5801 * ha: adapter state pointer.
5802 * cmd: Local EXT_IOCTL cmd struct pointer.
5803 * mode: flags.
5804 *
5805 * Returns:
5806 * None, request status indicated in cmd->Status.
5807 *
5808 * Context:
5809 * Kernel context.
5810 */
5811 static void
ql_get_statistics_fc4(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)5812 ql_get_statistics_fc4(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
5813 {
5814 uint32_t rval;
5815 EXT_HBA_FC4STATISTICS fc4stats = {0};
5816 ql_xioctl_t *xp = ha->xioctl;
5817
5818 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
5819
5820 fc4stats.InputRequests = xp->IOInputRequests;
5821 fc4stats.OutputRequests = xp->IOOutputRequests;
5822 fc4stats.ControlRequests = xp->IOControlRequests;
5823 fc4stats.InputMegabytes = xp->IOInputMByteCnt;
5824 fc4stats.OutputMegabytes = xp->IOOutputMByteCnt;
5825
5826 rval = ddi_copyout((void *)&fc4stats,
5827 (void *)(uintptr_t)cmd->ResponseAdr,
5828 sizeof (EXT_HBA_FC4STATISTICS), mode);
5829
5830 if (rval != 0) {
5831 EL(ha, "failed, ddi_copyout\n");
5832 cmd->Status = EXT_STATUS_COPY_ERR;
5833 cmd->ResponseLen = 0;
5834 } else {
5835 cmd->ResponseLen = sizeof (EXT_HBA_FC4STATISTICS);
5836 }
5837
5838 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
5839 }
5840
5841 /*
5842 * ql_set_led_state
5843 * Performs EXT_SET_BEACON_STATE subcommand of EXT_CC_SET_DATA.
5844 *
5845 * Input:
5846 * ha: adapter state pointer.
5847 * cmd: Local EXT_IOCTL cmd struct pointer.
5848 * mode: flags.
5849 *
5850 * Returns:
5851 * None, request status indicated in cmd->Status.
5852 *
5853 * Context:
5854 * Kernel context.
5855 */
5856 static void
ql_set_led_state(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)5857 ql_set_led_state(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
5858 {
5859 EXT_BEACON_CONTROL bstate;
5860 uint32_t rval;
5861 ql_xioctl_t *xp = ha->xioctl;
5862
5863 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
5864
5865 if (cmd->RequestLen < sizeof (EXT_BEACON_CONTROL)) {
5866 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
5867 cmd->DetailStatus = sizeof (EXT_BEACON_CONTROL);
5868 EL(ha, "done - failed, RequestLen < EXT_BEACON_CONTROL,"
5869 " Len=%xh\n", cmd->RequestLen);
5870 cmd->ResponseLen = 0;
5871 return;
5872 }
5873
5874 if (ha->device_id < 0x2300) {
5875 cmd->Status = EXT_STATUS_UNSUPPORTED_SUBCODE;
5876 cmd->DetailStatus = 0;
5877 EL(ha, "done - failed, Invalid function for HBA model\n");
5878 cmd->ResponseLen = 0;
5879 return;
5880 }
5881
5882 rval = ddi_copyin((void*)(uintptr_t)cmd->RequestAdr, &bstate,
5883 cmd->RequestLen, mode);
5884
5885 if (rval != 0) {
5886 cmd->Status = EXT_STATUS_COPY_ERR;
5887 EL(ha, "done - failed, ddi_copyin\n");
5888 return;
5889 }
5890
5891 switch (bstate.State) {
5892 case EXT_DEF_GRN_BLINK_OFF: /* turn beacon off */
5893 if (xp->ledstate.BeaconState == BEACON_OFF) {
5894 /* not quite an error -- LED state is already off */
5895 cmd->Status = EXT_STATUS_OK;
5896 EL(ha, "LED off request -- LED is already off\n");
5897 break;
5898 }
5899
5900 xp->ledstate.BeaconState = BEACON_OFF;
5901 xp->ledstate.LEDflags = LED_ALL_OFF;
5902
5903 if ((rval = ql_wrapup_led(ha)) != QL_SUCCESS) {
5904 cmd->Status = EXT_STATUS_MAILBOX;
5905 } else {
5906 cmd->Status = EXT_STATUS_OK;
5907 }
5908 break;
5909
5910 case EXT_DEF_GRN_BLINK_ON: /* turn beacon on */
5911 if (xp->ledstate.BeaconState == BEACON_ON) {
5912 /* not quite an error -- LED state is already on */
5913 cmd->Status = EXT_STATUS_OK;
5914 EL(ha, "LED on request - LED is already on\n");
5915 break;
5916 }
5917
5918 if ((rval = ql_setup_led(ha)) != QL_SUCCESS) {
5919 cmd->Status = EXT_STATUS_MAILBOX;
5920 break;
5921 }
5922
5923 if (CFG_IST(ha, CFG_CTRL_24258081)) {
5924 xp->ledstate.LEDflags = LED_YELLOW_24 | LED_AMBER_24;
5925 } else {
5926 xp->ledstate.LEDflags = LED_GREEN;
5927 }
5928 xp->ledstate.BeaconState = BEACON_ON;
5929
5930 cmd->Status = EXT_STATUS_OK;
5931 break;
5932 default:
5933 cmd->Status = EXT_STATUS_ERR;
5934 EL(ha, "failed, unknown state request %xh\n", bstate.State);
5935 break;
5936 }
5937
5938 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
5939 }
5940
5941 /*
5942 * ql_get_led_state
5943 * Performs EXT_GET_BEACON_STATE subcommand of EXT_CC_GET_DATA.
5944 *
5945 * Input:
5946 * ha: adapter state pointer.
5947 * cmd: Local EXT_IOCTL cmd struct pointer.
5948 * mode: flags.
5949 *
5950 * Returns:
5951 * None, request status indicated in cmd->Status.
5952 *
5953 * Context:
5954 * Kernel context.
5955 */
5956 static void
ql_get_led_state(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)5957 ql_get_led_state(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
5958 {
5959 EXT_BEACON_CONTROL bstate = {0};
5960 uint32_t rval;
5961 ql_xioctl_t *xp = ha->xioctl;
5962
5963 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
5964
5965 if (cmd->ResponseLen < sizeof (EXT_BEACON_CONTROL)) {
5966 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
5967 cmd->DetailStatus = sizeof (EXT_BEACON_CONTROL);
5968 EL(ha, "done - failed, ResponseLen < EXT_BEACON_CONTROL,"
5969 "Len=%xh\n", cmd->ResponseLen);
5970 cmd->ResponseLen = 0;
5971 return;
5972 }
5973
5974 if (ha->device_id < 0x2300) {
5975 cmd->Status = EXT_STATUS_UNSUPPORTED_SUBCODE;
5976 cmd->DetailStatus = 0;
5977 EL(ha, "done - failed, Invalid function for HBA model\n");
5978 cmd->ResponseLen = 0;
5979 return;
5980 }
5981
5982 if (ha->task_daemon_flags & ABORT_ISP_ACTIVE) {
5983 cmd->Status = EXT_STATUS_BUSY;
5984 EL(ha, "done - failed, isp abort active\n");
5985 cmd->ResponseLen = 0;
5986 return;
5987 }
5988
5989 /* inform the user of the current beacon state (off or on) */
5990 bstate.State = xp->ledstate.BeaconState;
5991
5992 rval = ddi_copyout((void *)&bstate,
5993 (void *)(uintptr_t)cmd->ResponseAdr,
5994 sizeof (EXT_BEACON_CONTROL), mode);
5995
5996 if (rval != 0) {
5997 EL(ha, "failed, ddi_copyout\n");
5998 cmd->Status = EXT_STATUS_COPY_ERR;
5999 cmd->ResponseLen = 0;
6000 } else {
6001 cmd->Status = EXT_STATUS_OK;
6002 cmd->ResponseLen = sizeof (EXT_BEACON_CONTROL);
6003 }
6004
6005 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
6006 }
6007
6008 /*
6009 * ql_blink_led
6010 * Determine the next state of the LED and drive it
6011 *
6012 * Input:
6013 * ha: adapter state pointer.
6014 *
6015 * Context:
6016 * Interrupt context.
6017 */
6018 void
ql_blink_led(ql_adapter_state_t * ha)6019 ql_blink_led(ql_adapter_state_t *ha)
6020 {
6021 uint32_t nextstate;
6022 ql_xioctl_t *xp = ha->xioctl;
6023
6024 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
6025
6026 if (xp->ledstate.BeaconState == BEACON_ON) {
6027 /* determine the next led state */
6028 if (CFG_IST(ha, CFG_CTRL_24258081)) {
6029 nextstate = (xp->ledstate.LEDflags) &
6030 (~(RD32_IO_REG(ha, gpiod)));
6031 } else {
6032 nextstate = (xp->ledstate.LEDflags) &
6033 (~(RD16_IO_REG(ha, gpiod)));
6034 }
6035
6036 /* turn the led on or off */
6037 ql_drive_led(ha, nextstate);
6038 }
6039
6040 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
6041 }
6042
6043 /*
6044 * ql_drive_led
6045 * drive the led's as determined by LEDflags
6046 *
6047 * Input:
6048 * ha: adapter state pointer.
6049 * LEDflags: LED flags
6050 *
6051 * Context:
6052 * Kernel/Interrupt context.
6053 */
6054 static void
ql_drive_led(ql_adapter_state_t * ha,uint32_t LEDflags)6055 ql_drive_led(ql_adapter_state_t *ha, uint32_t LEDflags)
6056 {
6057
6058 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
6059
6060 if (CFG_IST(ha, (CFG_CTRL_2300 | CFG_CTRL_6322))) {
6061
6062 uint16_t gpio_enable, gpio_data;
6063
6064 /* setup to send new data */
6065 gpio_enable = (uint16_t)RD16_IO_REG(ha, gpioe);
6066 gpio_enable = (uint16_t)(gpio_enable | LED_MASK);
6067 WRT16_IO_REG(ha, gpioe, gpio_enable);
6068
6069 /* read current data and clear out old led data */
6070 gpio_data = (uint16_t)RD16_IO_REG(ha, gpiod);
6071 gpio_data = (uint16_t)(gpio_data & ~LED_MASK);
6072
6073 /* set in the new led data. */
6074 gpio_data = (uint16_t)(gpio_data | LEDflags);
6075
6076 /* write out the new led data */
6077 WRT16_IO_REG(ha, gpiod, gpio_data);
6078
6079 } else if (CFG_IST(ha, CFG_CTRL_24258081)) {
6080
6081 uint32_t gpio_data;
6082
6083 /* setup to send new data */
6084 gpio_data = RD32_IO_REG(ha, gpiod);
6085 gpio_data |= LED_MASK_UPDATE_24;
6086 WRT32_IO_REG(ha, gpiod, gpio_data);
6087
6088 /* read current data and clear out old led data */
6089 gpio_data = RD32_IO_REG(ha, gpiod);
6090 gpio_data &= ~LED_MASK_COLORS_24;
6091
6092 /* set in the new led data */
6093 gpio_data |= LEDflags;
6094
6095 /* write out the new led data */
6096 WRT32_IO_REG(ha, gpiod, gpio_data);
6097
6098 } else {
6099 EL(ha, "unsupported HBA: %xh", ha->device_id);
6100 }
6101
6102 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
6103 }
6104
6105 /*
6106 * ql_setup_led
6107 * Setup LED for driver control
6108 *
6109 * Input:
6110 * ha: adapter state pointer.
6111 *
6112 * Context:
6113 * Kernel/Interrupt context.
6114 */
6115 static uint32_t
ql_setup_led(ql_adapter_state_t * ha)6116 ql_setup_led(ql_adapter_state_t *ha)
6117 {
6118 uint32_t rval;
6119 ql_mbx_data_t mr;
6120
6121 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
6122
6123 /* decouple the LED control from the fw */
6124 rval = ql_get_firmware_option(ha, &mr);
6125 if (rval != QL_SUCCESS) {
6126 EL(ha, "failed, get_firmware_option=%xh\n", rval);
6127 return (rval);
6128 }
6129
6130 /* set the appropriate options */
6131 mr.mb[1] = (uint16_t)(mr.mb[1] | FO1_DISABLE_GPIO);
6132
6133 /* send it back to the firmware */
6134 rval = ql_set_firmware_option(ha, &mr);
6135 if (rval != QL_SUCCESS) {
6136 EL(ha, "failed, set_firmware_option=%xh\n", rval);
6137 return (rval);
6138 }
6139
6140 /* initally, turn the LED's off */
6141 ql_drive_led(ha, LED_ALL_OFF);
6142
6143 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
6144
6145 return (rval);
6146 }
6147
6148 /*
6149 * ql_wrapup_led
6150 * Return LED control to the firmware
6151 *
6152 * Input:
6153 * ha: adapter state pointer.
6154 *
6155 * Context:
6156 * Kernel/Interrupt context.
6157 */
6158 static uint32_t
ql_wrapup_led(ql_adapter_state_t * ha)6159 ql_wrapup_led(ql_adapter_state_t *ha)
6160 {
6161 uint32_t rval;
6162 ql_mbx_data_t mr;
6163
6164 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
6165
6166 /* Turn all LED's off */
6167 ql_drive_led(ha, LED_ALL_OFF);
6168
6169 if (CFG_IST(ha, CFG_CTRL_24258081)) {
6170
6171 uint32_t gpio_data;
6172
6173 /* disable the LED update mask */
6174 gpio_data = RD32_IO_REG(ha, gpiod);
6175 gpio_data &= ~LED_MASK_UPDATE_24;
6176
6177 /* write out the data */
6178 WRT32_IO_REG(ha, gpiod, gpio_data);
6179 }
6180
6181 /* give LED control back to the f/w */
6182 rval = ql_get_firmware_option(ha, &mr);
6183 if (rval != QL_SUCCESS) {
6184 EL(ha, "failed, get_firmware_option=%xh\n", rval);
6185 return (rval);
6186 }
6187
6188 mr.mb[1] = (uint16_t)(mr.mb[1] & ~FO1_DISABLE_GPIO);
6189
6190 rval = ql_set_firmware_option(ha, &mr);
6191 if (rval != QL_SUCCESS) {
6192 EL(ha, "failed, set_firmware_option=%xh\n", rval);
6193 return (rval);
6194 }
6195
6196 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
6197
6198 return (rval);
6199 }
6200
6201 /*
6202 * ql_get_port_summary
6203 * Performs EXT_SC_GET_PORT_SUMMARY subcommand. of EXT_CC_GET_DATA.
6204 *
6205 * The EXT_IOCTL->RequestAdr points to a single
6206 * UINT32 which identifies the device type.
6207 *
6208 * Input:
6209 * ha: adapter state pointer.
6210 * cmd: Local EXT_IOCTL cmd struct pointer.
6211 * mode: flags.
6212 *
6213 * Returns:
6214 * None, request status indicated in cmd->Status.
6215 *
6216 * Context:
6217 * Kernel context.
6218 */
6219 static void
ql_get_port_summary(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)6220 ql_get_port_summary(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
6221 {
6222 EXT_DEVICEDATA dd = {0};
6223 EXT_DEVICEDATA *uddp;
6224 ql_link_t *link;
6225 ql_tgt_t *tq;
6226 uint32_t rlen, dev_type, index;
6227 int rval = 0;
6228 EXT_DEVICEDATAENTRY *uddep, *ddep;
6229
6230 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
6231
6232 ddep = &dd.EntryList[0];
6233
6234 /*
6235 * Get the type of device the requestor is looking for.
6236 *
6237 * We ignore this for now.
6238 */
6239 rval = ddi_copyin((void *)(uintptr_t)cmd->RequestAdr,
6240 (void *)&dev_type, sizeof (dev_type), mode);
6241 if (rval != 0) {
6242 cmd->Status = EXT_STATUS_COPY_ERR;
6243 cmd->ResponseLen = 0;
6244 EL(ha, "failed, ddi_copyin\n");
6245 return;
6246 }
6247 /*
6248 * Count the number of entries to be returned. Count devices
6249 * that are offlline, but have been persistently bound.
6250 */
6251 for (index = 0; index < DEVICE_HEAD_LIST_SIZE; index++) {
6252 for (link = ha->dev[index].first; link != NULL;
6253 link = link->next) {
6254 tq = link->base_address;
6255 if (tq->flags & TQF_INITIATOR_DEVICE ||
6256 !VALID_TARGET_ID(ha, tq->loop_id)) {
6257 continue; /* Skip this one */
6258 }
6259 dd.TotalDevices++;
6260 }
6261 }
6262 /*
6263 * Compute the number of entries that can be returned
6264 * based upon the size of caller's response buffer.
6265 */
6266 dd.ReturnListEntryCount = 0;
6267 if (dd.TotalDevices == 0) {
6268 rlen = sizeof (EXT_DEVICEDATA) - sizeof (EXT_DEVICEDATAENTRY);
6269 } else {
6270 rlen = (uint32_t)(sizeof (EXT_DEVICEDATA) +
6271 (sizeof (EXT_DEVICEDATAENTRY) * (dd.TotalDevices - 1)));
6272 }
6273 if (rlen > cmd->ResponseLen) {
6274 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
6275 cmd->DetailStatus = rlen;
6276 EL(ha, "failed, rlen > ResponseLen, rlen=%d, Len=%d\n",
6277 rlen, cmd->ResponseLen);
6278 cmd->ResponseLen = 0;
6279 return;
6280 }
6281 cmd->ResponseLen = 0;
6282 uddp = (EXT_DEVICEDATA *)(uintptr_t)cmd->ResponseAdr;
6283 uddep = &uddp->EntryList[0];
6284 for (index = 0; index < DEVICE_HEAD_LIST_SIZE; index++) {
6285 for (link = ha->dev[index].first; link != NULL;
6286 link = link->next) {
6287 tq = link->base_address;
6288 if (tq->flags & TQF_INITIATOR_DEVICE ||
6289 !VALID_TARGET_ID(ha, tq->loop_id)) {
6290 continue; /* Skip this one */
6291 }
6292
6293 bzero((void *)ddep, sizeof (EXT_DEVICEDATAENTRY));
6294
6295 bcopy(tq->node_name, ddep->NodeWWN, 8);
6296 bcopy(tq->port_name, ddep->PortWWN, 8);
6297
6298 ddep->PortID[0] = tq->d_id.b.domain;
6299 ddep->PortID[1] = tq->d_id.b.area;
6300 ddep->PortID[2] = tq->d_id.b.al_pa;
6301
6302 bcopy(tq->port_name,
6303 (caddr_t)&ddep->TargetAddress.Target, 8);
6304
6305 ddep->DeviceFlags = tq->flags;
6306 ddep->LoopID = tq->loop_id;
6307 QL_PRINT_9(CE_CONT, "(%d): Tgt=%lld, loop=%xh, "
6308 "wwnn=%02x%02x%02x%02x%02x%02x%02x%02x, "
6309 "wwpn=%02x%02x%02x%02x%02x%02x%02x%02x\n",
6310 ha->instance, ddep->TargetAddress.Target,
6311 ddep->LoopID, ddep->NodeWWN[0], ddep->NodeWWN[1],
6312 ddep->NodeWWN[2], ddep->NodeWWN[3],
6313 ddep->NodeWWN[4], ddep->NodeWWN[5],
6314 ddep->NodeWWN[6], ddep->NodeWWN[7],
6315 ddep->PortWWN[0], ddep->PortWWN[1],
6316 ddep->PortWWN[2], ddep->PortWWN[3],
6317 ddep->PortWWN[4], ddep->PortWWN[5],
6318 ddep->PortWWN[6], ddep->PortWWN[7]);
6319 rval = ddi_copyout((void *)ddep, (void *)uddep,
6320 sizeof (EXT_DEVICEDATAENTRY), mode);
6321
6322 if (rval != 0) {
6323 cmd->Status = EXT_STATUS_COPY_ERR;
6324 cmd->ResponseLen = 0;
6325 EL(ha, "failed, ddi_copyout\n");
6326 break;
6327 }
6328 dd.ReturnListEntryCount++;
6329 uddep++;
6330 cmd->ResponseLen += (uint32_t)
6331 sizeof (EXT_DEVICEDATAENTRY);
6332 }
6333 }
6334 rval = ddi_copyout((void *)&dd, (void *)uddp,
6335 sizeof (EXT_DEVICEDATA) - sizeof (EXT_DEVICEDATAENTRY), mode);
6336
6337 if (rval != 0) {
6338 cmd->Status = EXT_STATUS_COPY_ERR;
6339 cmd->ResponseLen = 0;
6340 EL(ha, "failed, ddi_copyout-2\n");
6341 } else {
6342 cmd->ResponseLen += (uint32_t)sizeof (EXT_DEVICEDATAENTRY);
6343 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
6344 }
6345 }
6346
6347 /*
6348 * ql_get_target_id
6349 * Performs EXT_SC_GET_TARGET_ID subcommand. of EXT_CC_GET_DATA.
6350 *
6351 * Input:
6352 * ha: adapter state pointer.
6353 * cmd: Local EXT_IOCTL cmd struct pointer.
6354 * mode: flags.
6355 *
6356 * Returns:
6357 * None, request status indicated in cmd->Status.
6358 *
6359 * Context:
6360 * Kernel context.
6361 */
6362 static void
ql_get_target_id(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)6363 ql_get_target_id(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
6364 {
6365 uint32_t rval;
6366 uint16_t qlnt;
6367 EXT_DEST_ADDR extdestaddr = {0};
6368 uint8_t *name;
6369 uint8_t wwpn[EXT_DEF_WWN_NAME_SIZE];
6370 ql_tgt_t *tq;
6371
6372 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
6373
6374 if (ddi_copyin((void *)(uintptr_t)cmd->RequestAdr,
6375 (void*)wwpn, sizeof (EXT_DEST_ADDR), mode) != 0) {
6376 EL(ha, "failed, ddi_copyin\n");
6377 cmd->Status = EXT_STATUS_COPY_ERR;
6378 cmd->ResponseLen = 0;
6379 return;
6380 }
6381
6382 qlnt = QLNT_PORT;
6383 name = wwpn;
6384 QL_PRINT_9(CE_CONT, "(%d): wwpn=%02x%02x%02x%02x%02x%02x%02x%02x\n",
6385 ha->instance, name[0], name[1], name[2], name[3], name[4],
6386 name[5], name[6], name[7]);
6387
6388 tq = ql_find_port(ha, name, qlnt);
6389 if (tq == NULL || !VALID_TARGET_ID(ha, tq->loop_id)) {
6390 EL(ha, "failed, fc_port not found\n");
6391 cmd->Status = EXT_STATUS_DEV_NOT_FOUND;
6392 cmd->ResponseLen = 0;
6393 return;
6394 }
6395
6396 bcopy(tq->port_name, (caddr_t)&extdestaddr.DestAddr.ScsiAddr.Target, 8);
6397
6398 rval = ddi_copyout((void *)&extdestaddr,
6399 (void *)(uintptr_t)cmd->ResponseAdr, sizeof (EXT_DEST_ADDR), mode);
6400 if (rval != 0) {
6401 EL(ha, "failed, ddi_copyout\n");
6402 cmd->Status = EXT_STATUS_COPY_ERR;
6403 cmd->ResponseLen = 0;
6404 }
6405
6406 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
6407 }
6408
6409 /*
6410 * ql_setup_fcache
6411 * Populates selected flash sections into the cache
6412 *
6413 * Input:
6414 * ha = adapter state pointer.
6415 *
6416 * Returns:
6417 * ql local function return status code.
6418 *
6419 * Context:
6420 * Kernel context.
6421 *
6422 * Note:
6423 * Driver must be in stalled state prior to entering or
6424 * add code to this function prior to calling ql_setup_flash()
6425 */
6426 int
ql_setup_fcache(ql_adapter_state_t * ha)6427 ql_setup_fcache(ql_adapter_state_t *ha)
6428 {
6429 int rval;
6430 uint32_t freadpos = 0;
6431 uint32_t fw_done = 0;
6432 ql_fcache_t *head = NULL;
6433 ql_fcache_t *tail = NULL;
6434 ql_fcache_t *ftmp;
6435
6436 QL_PRINT_3(CE_CONT, "(%d): started\n", ha->instance);
6437
6438 CACHE_LOCK(ha);
6439
6440 /* If we already have populated it, rtn */
6441 if (ha->fcache != NULL) {
6442 CACHE_UNLOCK(ha);
6443 EL(ha, "buffer already populated\n");
6444 return (QL_SUCCESS);
6445 }
6446
6447 ql_flash_nvram_defaults(ha);
6448
6449 if ((rval = ql_setup_flash(ha)) != QL_SUCCESS) {
6450 CACHE_UNLOCK(ha);
6451 EL(ha, "unable to setup flash; rval=%xh\n", rval);
6452 return (rval);
6453 }
6454
6455 while (freadpos != 0xffffffff) {
6456 /* Allocate & populate this node */
6457 if ((ftmp = ql_setup_fnode(ha)) == NULL) {
6458 EL(ha, "node alloc failed\n");
6459 rval = QL_FUNCTION_FAILED;
6460 break;
6461 }
6462
6463 /* link in the new node */
6464 if (head == NULL) {
6465 head = tail = ftmp;
6466 } else {
6467 tail->next = ftmp;
6468 tail = ftmp;
6469 }
6470
6471 /* Do the firmware node first for 24xx/25xx's */
6472 if (fw_done == 0) {
6473 if (CFG_IST(ha, CFG_CTRL_24258081)) {
6474 freadpos = ha->flash_fw_addr << 2;
6475 }
6476 fw_done = 1;
6477 }
6478
6479 if ((rval = ql_dump_fcode(ha, ftmp->buf, FBUFSIZE,
6480 freadpos)) != QL_SUCCESS) {
6481 EL(ha, "failed, 24xx dump_fcode"
6482 " pos=%xh rval=%xh\n", freadpos, rval);
6483 rval = QL_FUNCTION_FAILED;
6484 break;
6485 }
6486
6487 /* checkout the pci data / format */
6488 if (ql_check_pci(ha, ftmp, &freadpos)) {
6489 EL(ha, "flash header incorrect\n");
6490 rval = QL_FUNCTION_FAILED;
6491 break;
6492 }
6493 }
6494
6495 if (rval != QL_SUCCESS) {
6496 /* release all resources we have */
6497 ftmp = head;
6498 while (ftmp != NULL) {
6499 tail = ftmp->next;
6500 kmem_free(ftmp->buf, FBUFSIZE);
6501 kmem_free(ftmp, sizeof (ql_fcache_t));
6502 ftmp = tail;
6503 }
6504
6505 EL(ha, "failed, done\n");
6506 } else {
6507 ha->fcache = head;
6508 QL_PRINT_3(CE_CONT, "(%d): done\n", ha->instance);
6509 }
6510 CACHE_UNLOCK(ha);
6511
6512 return (rval);
6513 }
6514
6515 /*
6516 * ql_update_fcache
6517 * re-populates updated flash into the fcache. If
6518 * fcache does not exist (e.g., flash was empty/invalid on
6519 * boot), this routine will create and the populate it.
6520 *
6521 * Input:
6522 * ha = adapter state pointer.
6523 * *bpf = Pointer to flash buffer.
6524 * bsize = Size of flash buffer.
6525 *
6526 * Returns:
6527 *
6528 * Context:
6529 * Kernel context.
6530 */
6531 void
ql_update_fcache(ql_adapter_state_t * ha,uint8_t * bfp,uint32_t bsize)6532 ql_update_fcache(ql_adapter_state_t *ha, uint8_t *bfp, uint32_t bsize)
6533 {
6534 int rval = QL_SUCCESS;
6535 uint32_t freadpos = 0;
6536 uint32_t fw_done = 0;
6537 ql_fcache_t *head = NULL;
6538 ql_fcache_t *tail = NULL;
6539 ql_fcache_t *ftmp;
6540
6541 QL_PRINT_3(CE_CONT, "(%d): started\n", ha->instance);
6542
6543 while (freadpos != 0xffffffff) {
6544
6545 /* Allocate & populate this node */
6546
6547 if ((ftmp = ql_setup_fnode(ha)) == NULL) {
6548 EL(ha, "node alloc failed\n");
6549 rval = QL_FUNCTION_FAILED;
6550 break;
6551 }
6552
6553 /* link in the new node */
6554 if (head == NULL) {
6555 head = tail = ftmp;
6556 } else {
6557 tail->next = ftmp;
6558 tail = ftmp;
6559 }
6560
6561 /* Do the firmware node first for 24xx's */
6562 if (fw_done == 0) {
6563 if (CFG_IST(ha, CFG_CTRL_24258081)) {
6564 freadpos = ha->flash_fw_addr << 2;
6565 }
6566 fw_done = 1;
6567 }
6568
6569 /* read in first FBUFSIZE bytes of this flash section */
6570 if (freadpos+FBUFSIZE > bsize) {
6571 EL(ha, "passed buffer too small; fr=%xh, bsize=%xh\n",
6572 freadpos, bsize);
6573 rval = QL_FUNCTION_FAILED;
6574 break;
6575 }
6576 bcopy(bfp+freadpos, ftmp->buf, FBUFSIZE);
6577
6578 /* checkout the pci data / format */
6579 if (ql_check_pci(ha, ftmp, &freadpos)) {
6580 EL(ha, "flash header incorrect\n");
6581 rval = QL_FUNCTION_FAILED;
6582 break;
6583 }
6584 }
6585
6586 if (rval != QL_SUCCESS) {
6587 /*
6588 * release all resources we have
6589 */
6590 ql_fcache_rel(head);
6591 EL(ha, "failed, done\n");
6592 } else {
6593 /*
6594 * Release previous fcache resources and update with new
6595 */
6596 CACHE_LOCK(ha);
6597 ql_fcache_rel(ha->fcache);
6598 ha->fcache = head;
6599 CACHE_UNLOCK(ha);
6600
6601 QL_PRINT_3(CE_CONT, "(%d): done\n", ha->instance);
6602 }
6603 }
6604
6605 /*
6606 * ql_setup_fnode
6607 * Allocates fcache node
6608 *
6609 * Input:
6610 * ha = adapter state pointer.
6611 * node = point to allocated fcache node (NULL = failed)
6612 *
6613 * Returns:
6614 *
6615 * Context:
6616 * Kernel context.
6617 *
6618 * Note:
6619 * Driver must be in stalled state prior to entering or
6620 * add code to this function prior to calling ql_setup_flash()
6621 */
6622 static ql_fcache_t *
ql_setup_fnode(ql_adapter_state_t * ha)6623 ql_setup_fnode(ql_adapter_state_t *ha)
6624 {
6625 ql_fcache_t *fnode = NULL;
6626
6627 if ((fnode = (ql_fcache_t *)(kmem_zalloc(sizeof (ql_fcache_t),
6628 KM_SLEEP))) == NULL) {
6629 EL(ha, "fnode alloc failed\n");
6630 fnode = NULL;
6631 } else if ((fnode->buf = (uint8_t *)(kmem_zalloc(FBUFSIZE,
6632 KM_SLEEP))) == NULL) {
6633 EL(ha, "buf alloc failed\n");
6634 kmem_free(fnode, sizeof (ql_fcache_t));
6635 fnode = NULL;
6636 } else {
6637 fnode->buflen = FBUFSIZE;
6638 }
6639
6640 return (fnode);
6641 }
6642
6643 /*
6644 * ql_fcache_rel
6645 * Releases the fcache resources
6646 *
6647 * Input:
6648 * ha = adapter state pointer.
6649 * head = Pointer to fcache linked list
6650 *
6651 * Returns:
6652 *
6653 * Context:
6654 * Kernel context.
6655 *
6656 */
6657 void
ql_fcache_rel(ql_fcache_t * head)6658 ql_fcache_rel(ql_fcache_t *head)
6659 {
6660 ql_fcache_t *ftmp = head;
6661 ql_fcache_t *tail;
6662
6663 /* release all resources we have */
6664 while (ftmp != NULL) {
6665 tail = ftmp->next;
6666 kmem_free(ftmp->buf, FBUFSIZE);
6667 kmem_free(ftmp, sizeof (ql_fcache_t));
6668 ftmp = tail;
6669 }
6670 }
6671
6672 /*
6673 * ql_update_flash_caches
6674 * Updates driver flash caches
6675 *
6676 * Input:
6677 * ha: adapter state pointer.
6678 *
6679 * Context:
6680 * Kernel context.
6681 */
6682 static void
ql_update_flash_caches(ql_adapter_state_t * ha)6683 ql_update_flash_caches(ql_adapter_state_t *ha)
6684 {
6685 uint32_t len;
6686 ql_link_t *link;
6687 ql_adapter_state_t *ha2;
6688
6689 QL_PRINT_3(CE_CONT, "(%d): started\n", ha->instance);
6690
6691 /* Get base path length. */
6692 for (len = (uint32_t)strlen(ha->devpath); len; len--) {
6693 if (ha->devpath[len] == ',' ||
6694 ha->devpath[len] == '@') {
6695 break;
6696 }
6697 }
6698
6699 /* Reset fcache on all adapter instances. */
6700 for (link = ql_hba.first; link != NULL; link = link->next) {
6701 ha2 = link->base_address;
6702
6703 if (strncmp(ha->devpath, ha2->devpath, len) != 0) {
6704 continue;
6705 }
6706
6707 CACHE_LOCK(ha2);
6708 ql_fcache_rel(ha2->fcache);
6709 ha2->fcache = NULL;
6710
6711 if (CFG_IST(ha, CFG_CTRL_24258081)) {
6712 if (ha2->vcache != NULL) {
6713 kmem_free(ha2->vcache, QL_24XX_VPD_SIZE);
6714 ha2->vcache = NULL;
6715 }
6716 }
6717 CACHE_UNLOCK(ha2);
6718
6719 (void) ql_setup_fcache(ha2);
6720 }
6721
6722 QL_PRINT_3(CE_CONT, "(%d): done\n", ha->instance);
6723 }
6724
6725 /*
6726 * ql_get_fbuf
6727 * Search the fcache list for the type specified
6728 *
6729 * Input:
6730 * fptr = Pointer to fcache linked list
6731 * ftype = Type of image to be returned.
6732 *
6733 * Returns:
6734 * Pointer to ql_fcache_t.
6735 * NULL means not found.
6736 *
6737 * Context:
6738 * Kernel context.
6739 *
6740 *
6741 */
6742 ql_fcache_t *
ql_get_fbuf(ql_fcache_t * fptr,uint32_t ftype)6743 ql_get_fbuf(ql_fcache_t *fptr, uint32_t ftype)
6744 {
6745 while (fptr != NULL) {
6746 /* does this image meet criteria? */
6747 if (ftype & fptr->type) {
6748 break;
6749 }
6750 fptr = fptr->next;
6751 }
6752 return (fptr);
6753 }
6754
6755 /*
6756 * ql_check_pci
6757 *
6758 * checks the passed buffer for a valid pci signature and
6759 * expected (and in range) pci length values.
6760 *
6761 * For firmware type, a pci header is added since the image in
6762 * the flash does not have one (!!!).
6763 *
6764 * On successful pci check, nextpos adjusted to next pci header.
6765 *
6766 * Returns:
6767 * -1 --> last pci image
6768 * 0 --> pci header valid
6769 * 1 --> pci header invalid.
6770 *
6771 * Context:
6772 * Kernel context.
6773 */
6774 static int
ql_check_pci(ql_adapter_state_t * ha,ql_fcache_t * fcache,uint32_t * nextpos)6775 ql_check_pci(ql_adapter_state_t *ha, ql_fcache_t *fcache, uint32_t *nextpos)
6776 {
6777 pci_header_t *pcih;
6778 pci_data_t *pcid;
6779 uint32_t doff;
6780 uint8_t *pciinfo;
6781
6782 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
6783
6784 if (fcache != NULL) {
6785 pciinfo = fcache->buf;
6786 } else {
6787 EL(ha, "failed, null fcache ptr passed\n");
6788 return (1);
6789 }
6790
6791 if (pciinfo == NULL) {
6792 EL(ha, "failed, null pciinfo ptr passed\n");
6793 return (1);
6794 }
6795
6796 if (CFG_IST(ha, CFG_SBUS_CARD)) {
6797 caddr_t bufp;
6798 uint_t len;
6799
6800 if (pciinfo[0] != SBUS_CODE_FCODE) {
6801 EL(ha, "failed, unable to detect sbus fcode\n");
6802 return (1);
6803 }
6804 fcache->type = FTYPE_FCODE;
6805
6806 /*LINTED [Solaris DDI_DEV_T_ANY Lint error]*/
6807 if (ddi_getlongprop(DDI_DEV_T_ANY, ha->dip,
6808 PROP_LEN_AND_VAL_ALLOC | DDI_PROP_DONTPASS |
6809 DDI_PROP_CANSLEEP, "version", (caddr_t)&bufp,
6810 (int *)&len) == DDI_PROP_SUCCESS) {
6811
6812 (void) snprintf(fcache->verstr,
6813 FCHBA_OPTION_ROM_VERSION_LEN, "%s", bufp);
6814 kmem_free(bufp, len);
6815 }
6816
6817 *nextpos = 0xffffffff;
6818
6819 QL_PRINT_9(CE_CONT, "(%d): CFG_SBUS_CARD, done\n",
6820 ha->instance);
6821
6822 return (0);
6823 }
6824
6825 if (*nextpos == ha->flash_fw_addr << 2) {
6826
6827 pci_header_t fwh = {0};
6828 pci_data_t fwd = {0};
6829 uint8_t *buf, *bufp;
6830
6831 /*
6832 * Build a pci header for the firmware module
6833 */
6834 if ((buf = (uint8_t *)(kmem_zalloc(FBUFSIZE, KM_SLEEP))) ==
6835 NULL) {
6836 EL(ha, "failed, unable to allocate buffer\n");
6837 return (1);
6838 }
6839
6840 fwh.signature[0] = PCI_HEADER0;
6841 fwh.signature[1] = PCI_HEADER1;
6842 fwh.dataoffset[0] = LSB(sizeof (pci_header_t));
6843 fwh.dataoffset[1] = MSB(sizeof (pci_header_t));
6844
6845 fwd.signature[0] = 'P';
6846 fwd.signature[1] = 'C';
6847 fwd.signature[2] = 'I';
6848 fwd.signature[3] = 'R';
6849 fwd.codetype = PCI_CODE_FW;
6850 fwd.pcidatalen[0] = LSB(sizeof (pci_data_t));
6851 fwd.pcidatalen[1] = MSB(sizeof (pci_data_t));
6852
6853 bufp = buf;
6854 bcopy(&fwh, bufp, sizeof (pci_header_t));
6855 bufp += sizeof (pci_header_t);
6856 bcopy(&fwd, bufp, sizeof (pci_data_t));
6857 bufp += sizeof (pci_data_t);
6858
6859 bcopy(fcache->buf, bufp, (FBUFSIZE - sizeof (pci_header_t) -
6860 sizeof (pci_data_t)));
6861 bcopy(buf, fcache->buf, FBUFSIZE);
6862
6863 fcache->type = FTYPE_FW;
6864
6865 (void) snprintf(fcache->verstr, FCHBA_OPTION_ROM_VERSION_LEN,
6866 "%d.%02d.%02d", fcache->buf[19], fcache->buf[23],
6867 fcache->buf[27]);
6868
6869 if (CFG_IST(ha, CFG_CTRL_81XX)) {
6870 *nextpos = 0x200000;
6871 } else if (CFG_IST(ha, CFG_CTRL_8021)) {
6872 *nextpos = 0x80000;
6873 } else {
6874 *nextpos = 0;
6875 }
6876 kmem_free(buf, FBUFSIZE);
6877
6878 QL_PRINT_9(CE_CONT, "(%d): FTYPE_FW, done\n", ha->instance);
6879
6880 return (0);
6881 }
6882
6883 /* get to the pci header image length */
6884 pcih = (pci_header_t *)pciinfo;
6885
6886 doff = pcih->dataoffset[0] | (pcih->dataoffset[1] << 8);
6887
6888 /* some header section sanity check */
6889 if (pcih->signature[0] != PCI_HEADER0 ||
6890 pcih->signature[1] != PCI_HEADER1 || doff > 50) {
6891 EL(ha, "buffer format error: s0=%xh, s1=%xh, off=%xh\n",
6892 pcih->signature[0], pcih->signature[1], doff);
6893 return (1);
6894 }
6895
6896 pcid = (pci_data_t *)(pciinfo + doff);
6897
6898 /* a slight sanity data section check */
6899 if (pcid->signature[0] != 'P' || pcid->signature[1] != 'C' ||
6900 pcid->signature[2] != 'I' || pcid->signature[3] != 'R') {
6901 EL(ha, "failed, data sig mismatch!\n");
6902 return (1);
6903 }
6904
6905 if (pcid->indicator == PCI_IND_LAST_IMAGE) {
6906 QL_PRINT_9(CE_CONT, "(%d): last image\n", ha->instance);
6907 if (CFG_IST(ha, CFG_CTRL_24258081)) {
6908 ql_flash_layout_table(ha, *nextpos +
6909 (pcid->imagelength[0] | (pcid->imagelength[1] <<
6910 8)) * PCI_SECTOR_SIZE);
6911 (void) ql_24xx_flash_desc(ha);
6912 }
6913 *nextpos = 0xffffffff;
6914 } else {
6915 /* adjust the next flash read start position */
6916 *nextpos += (pcid->imagelength[0] |
6917 (pcid->imagelength[1] << 8)) * PCI_SECTOR_SIZE;
6918 }
6919
6920 switch (pcid->codetype) {
6921 case PCI_CODE_X86PC:
6922 fcache->type = FTYPE_BIOS;
6923 break;
6924 case PCI_CODE_FCODE:
6925 fcache->type = FTYPE_FCODE;
6926 break;
6927 case PCI_CODE_EFI:
6928 fcache->type = FTYPE_EFI;
6929 break;
6930 case PCI_CODE_HPPA:
6931 fcache->type = FTYPE_HPPA;
6932 break;
6933 default:
6934 fcache->type = FTYPE_UNKNOWN;
6935 break;
6936 }
6937
6938 (void) snprintf(fcache->verstr, FCHBA_OPTION_ROM_VERSION_LEN,
6939 "%d.%02d", pcid->revisionlevel[1], pcid->revisionlevel[0]);
6940
6941 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
6942
6943 return (0);
6944 }
6945
6946 /*
6947 * ql_flash_layout_table
6948 * Obtains flash addresses from table
6949 *
6950 * Input:
6951 * ha: adapter state pointer.
6952 * flt_paddr: flash layout pointer address.
6953 *
6954 * Context:
6955 * Kernel context.
6956 */
6957 static void
ql_flash_layout_table(ql_adapter_state_t * ha,uint32_t flt_paddr)6958 ql_flash_layout_table(ql_adapter_state_t *ha, uint32_t flt_paddr)
6959 {
6960 ql_flt_ptr_t *fptr;
6961 uint8_t *bp;
6962 int rval;
6963 uint32_t len, faddr, cnt;
6964 uint16_t chksum, w16;
6965
6966 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
6967
6968 /* Process flash layout table header */
6969 len = sizeof (ql_flt_ptr_t);
6970 if ((bp = kmem_zalloc(len, KM_SLEEP)) == NULL) {
6971 EL(ha, "kmem_zalloc=null\n");
6972 return;
6973 }
6974
6975 /* Process pointer to flash layout table */
6976 if ((rval = ql_dump_fcode(ha, bp, len, flt_paddr)) != QL_SUCCESS) {
6977 EL(ha, "fptr dump_flash pos=%xh, status=%xh\n", flt_paddr,
6978 rval);
6979 kmem_free(bp, len);
6980 return;
6981 }
6982 fptr = (ql_flt_ptr_t *)bp;
6983
6984 /* Verify pointer to flash layout table. */
6985 for (chksum = 0, cnt = 0; cnt < len; cnt += 2) {
6986 w16 = (uint16_t)CHAR_TO_SHORT(bp[cnt], bp[cnt + 1]);
6987 chksum += w16;
6988 }
6989 if (chksum != 0 || fptr->sig[0] != 'Q' || fptr->sig[1] != 'F' ||
6990 fptr->sig[2] != 'L' || fptr->sig[3] != 'T') {
6991 EL(ha, "ptr chksum=%xh, sig=%c%c%c%c\n", chksum, fptr->sig[0],
6992 fptr->sig[1], fptr->sig[2], fptr->sig[3]);
6993 kmem_free(bp, len);
6994 return;
6995 }
6996 faddr = CHAR_TO_LONG(fptr->addr[0], fptr->addr[1], fptr->addr[2],
6997 fptr->addr[3]);
6998
6999 kmem_free(bp, len);
7000
7001 ql_process_flt(ha, faddr);
7002
7003 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
7004 }
7005
7006 /*
7007 * ql_process_flt
7008 * Obtains flash addresses from flash layout table
7009 *
7010 * Input:
7011 * ha: adapter state pointer.
7012 * faddr: flash layout table byte address.
7013 *
7014 * Context:
7015 * Kernel context.
7016 */
7017 static void
ql_process_flt(ql_adapter_state_t * ha,uint32_t faddr)7018 ql_process_flt(ql_adapter_state_t *ha, uint32_t faddr)
7019 {
7020 ql_flt_hdr_t *fhdr;
7021 ql_flt_region_t *frgn;
7022 uint8_t *bp, *eaddr, nv_rg, vpd_rg;
7023 int rval;
7024 uint32_t len, cnt, fe_addr;
7025 uint16_t chksum, w16;
7026
7027 QL_PRINT_9(CE_CONT, "(%d): started faddr=%xh\n", ha->instance, faddr);
7028
7029 /* Process flash layout table header */
7030 if ((bp = kmem_zalloc(FLASH_LAYOUT_TABLE_SIZE, KM_SLEEP)) == NULL) {
7031 EL(ha, "kmem_zalloc=null\n");
7032 return;
7033 }
7034 fhdr = (ql_flt_hdr_t *)bp;
7035
7036 /* Process flash layout table. */
7037 if ((rval = ql_dump_fcode(ha, bp, FLASH_LAYOUT_TABLE_SIZE, faddr)) !=
7038 QL_SUCCESS) {
7039 EL(ha, "fhdr dump_flash pos=%xh, status=%xh\n", faddr, rval);
7040 kmem_free(bp, FLASH_LAYOUT_TABLE_SIZE);
7041 return;
7042 }
7043
7044 /* Verify flash layout table. */
7045 len = (uint32_t)(CHAR_TO_SHORT(fhdr->len[0], fhdr->len[1]) +
7046 sizeof (ql_flt_hdr_t) + sizeof (ql_flt_region_t));
7047 if (len > FLASH_LAYOUT_TABLE_SIZE) {
7048 chksum = 0xffff;
7049 } else {
7050 for (chksum = 0, cnt = 0; cnt < len; cnt += 2) {
7051 w16 = (uint16_t)CHAR_TO_SHORT(bp[cnt], bp[cnt + 1]);
7052 chksum += w16;
7053 }
7054 }
7055 w16 = CHAR_TO_SHORT(fhdr->version[0], fhdr->version[1]);
7056 if (chksum != 0 || w16 != 1) {
7057 EL(ha, "table chksum=%xh, version=%d\n", chksum, w16);
7058 kmem_free(bp, FLASH_LAYOUT_TABLE_SIZE);
7059 return;
7060 }
7061 eaddr = bp + len;
7062
7063 /* Process Function/Port Configuration Map. */
7064 nv_rg = vpd_rg = 0;
7065 if (CFG_IST(ha, CFG_CTRL_8021)) {
7066 uint16_t i;
7067 uint8_t *mbp = eaddr;
7068 ql_fp_cfg_map_t *cmp = (ql_fp_cfg_map_t *)mbp;
7069
7070 len = (uint32_t)(CHAR_TO_SHORT(cmp->hdr.len[0],
7071 cmp->hdr.len[1]));
7072 if (len > FLASH_LAYOUT_TABLE_SIZE) {
7073 chksum = 0xffff;
7074 } else {
7075 for (chksum = 0, cnt = 0; cnt < len; cnt += 2) {
7076 w16 = (uint16_t)CHAR_TO_SHORT(mbp[cnt],
7077 mbp[cnt + 1]);
7078 chksum += w16;
7079 }
7080 }
7081 w16 = CHAR_TO_SHORT(cmp->hdr.version[0], cmp->hdr.version[1]);
7082 if (chksum != 0 || w16 != 1 ||
7083 cmp->hdr.Signature[0] != 'F' ||
7084 cmp->hdr.Signature[1] != 'P' ||
7085 cmp->hdr.Signature[2] != 'C' ||
7086 cmp->hdr.Signature[3] != 'M') {
7087 EL(ha, "cfg_map chksum=%xh, version=%d, "
7088 "sig=%c%c%c%c\n", chksum, w16,
7089 cmp->hdr.Signature[0], cmp->hdr.Signature[1],
7090 cmp->hdr.Signature[2], cmp->hdr.Signature[3]);
7091 } else {
7092 cnt = (uint16_t)
7093 (CHAR_TO_SHORT(cmp->hdr.NumberEntries[0],
7094 cmp->hdr.NumberEntries[1]));
7095 /* Locate entry for function. */
7096 for (i = 0; i < cnt; i++) {
7097 if (cmp->cfg[i].FunctionType == FT_FC &&
7098 cmp->cfg[i].FunctionNumber[0] ==
7099 ha->function_number &&
7100 cmp->cfg[i].FunctionNumber[1] == 0) {
7101 nv_rg = cmp->cfg[i].ConfigRegion;
7102 vpd_rg = cmp->cfg[i].VpdRegion;
7103 break;
7104 }
7105 }
7106
7107 if (nv_rg == 0 || vpd_rg == 0) {
7108 EL(ha, "cfg_map nv_rg=%d, vpd_rg=%d\n", nv_rg,
7109 vpd_rg);
7110 nv_rg = vpd_rg = 0;
7111 }
7112 }
7113 }
7114
7115 /* Process flash layout table regions */
7116 for (frgn = (ql_flt_region_t *)(bp + sizeof (ql_flt_hdr_t));
7117 (uint8_t *)frgn < eaddr; frgn++) {
7118 faddr = CHAR_TO_LONG(frgn->beg_addr[0], frgn->beg_addr[1],
7119 frgn->beg_addr[2], frgn->beg_addr[3]);
7120 faddr >>= 2;
7121 fe_addr = CHAR_TO_LONG(frgn->end_addr[0], frgn->end_addr[1],
7122 frgn->end_addr[2], frgn->end_addr[3]);
7123 fe_addr >>= 2;
7124
7125 switch (frgn->region) {
7126 case FLASH_8021_BOOTLOADER_REGION:
7127 ha->bootloader_addr = faddr;
7128 ha->bootloader_size = (fe_addr - faddr) + 1;
7129 QL_PRINT_9(CE_CONT, "(%d): bootloader_addr=%xh, "
7130 "size=%xh\n", ha->instance, faddr,
7131 ha->bootloader_size);
7132 break;
7133 case FLASH_FW_REGION:
7134 case FLASH_8021_FW_REGION:
7135 ha->flash_fw_addr = faddr;
7136 ha->flash_fw_size = (fe_addr - faddr) + 1;
7137 QL_PRINT_9(CE_CONT, "(%d): flash_fw_addr=%xh, "
7138 "size=%xh\n", ha->instance, faddr,
7139 ha->flash_fw_size);
7140 break;
7141 case FLASH_GOLDEN_FW_REGION:
7142 case FLASH_8021_GOLDEN_FW_REGION:
7143 ha->flash_golden_fw_addr = faddr;
7144 QL_PRINT_9(CE_CONT, "(%d): flash_golden_fw_addr=%xh\n",
7145 ha->instance, faddr);
7146 break;
7147 case FLASH_8021_VPD_REGION:
7148 if (!vpd_rg || vpd_rg == FLASH_8021_VPD_REGION) {
7149 ha->flash_vpd_addr = faddr;
7150 QL_PRINT_9(CE_CONT, "(%d): 8021_flash_vpd_"
7151 "addr=%xh\n", ha->instance, faddr);
7152 }
7153 break;
7154 case FLASH_VPD_0_REGION:
7155 if (vpd_rg) {
7156 if (vpd_rg == FLASH_VPD_0_REGION) {
7157 ha->flash_vpd_addr = faddr;
7158 QL_PRINT_9(CE_CONT, "(%d): vpd_rg "
7159 "flash_vpd_addr=%xh\n",
7160 ha->instance, faddr);
7161 }
7162 } else if (!(ha->flags & FUNCTION_1) &&
7163 !(CFG_IST(ha, CFG_CTRL_8021))) {
7164 ha->flash_vpd_addr = faddr;
7165 QL_PRINT_9(CE_CONT, "(%d): flash_vpd_addr=%xh"
7166 "\n", ha->instance, faddr);
7167 }
7168 break;
7169 case FLASH_NVRAM_0_REGION:
7170 if (nv_rg) {
7171 if (nv_rg == FLASH_NVRAM_0_REGION) {
7172 ADAPTER_STATE_LOCK(ha);
7173 ha->flags &= ~FUNCTION_1;
7174 ADAPTER_STATE_UNLOCK(ha);
7175 ha->flash_nvram_addr = faddr;
7176 QL_PRINT_9(CE_CONT, "(%d): nv_rg "
7177 "flash_nvram_addr=%xh\n",
7178 ha->instance, faddr);
7179 }
7180 } else if (!(ha->flags & FUNCTION_1)) {
7181 ha->flash_nvram_addr = faddr;
7182 QL_PRINT_9(CE_CONT, "(%d): flash_nvram_addr="
7183 "%xh\n", ha->instance, faddr);
7184 }
7185 break;
7186 case FLASH_VPD_1_REGION:
7187 if (vpd_rg) {
7188 if (vpd_rg == FLASH_VPD_1_REGION) {
7189 ha->flash_vpd_addr = faddr;
7190 QL_PRINT_9(CE_CONT, "(%d): vpd_rg "
7191 "flash_vpd_addr=%xh\n",
7192 ha->instance, faddr);
7193 }
7194 } else if (ha->flags & FUNCTION_1 &&
7195 !(CFG_IST(ha, CFG_CTRL_8021))) {
7196 ha->flash_vpd_addr = faddr;
7197 QL_PRINT_9(CE_CONT, "(%d): flash_vpd_addr=%xh"
7198 "\n", ha->instance, faddr);
7199 }
7200 break;
7201 case FLASH_NVRAM_1_REGION:
7202 if (nv_rg) {
7203 if (nv_rg == FLASH_NVRAM_1_REGION) {
7204 ADAPTER_STATE_LOCK(ha);
7205 ha->flags |= FUNCTION_1;
7206 ADAPTER_STATE_UNLOCK(ha);
7207 ha->flash_nvram_addr = faddr;
7208 QL_PRINT_9(CE_CONT, "(%d): nv_rg "
7209 "flash_nvram_addr=%xh\n",
7210 ha->instance, faddr);
7211 }
7212 } else if (ha->flags & FUNCTION_1) {
7213 ha->flash_nvram_addr = faddr;
7214 QL_PRINT_9(CE_CONT, "(%d): flash_nvram_addr="
7215 "%xh\n", ha->instance, faddr);
7216 }
7217 break;
7218 case FLASH_DESC_TABLE_REGION:
7219 if (!(CFG_IST(ha, CFG_CTRL_8021))) {
7220 ha->flash_desc_addr = faddr;
7221 QL_PRINT_9(CE_CONT, "(%d): flash_desc_addr="
7222 "%xh\n", ha->instance, faddr);
7223 }
7224 break;
7225 case FLASH_ERROR_LOG_0_REGION:
7226 if (!(ha->flags & FUNCTION_1)) {
7227 ha->flash_errlog_start = faddr;
7228 QL_PRINT_9(CE_CONT, "(%d): flash_errlog_addr="
7229 "%xh\n", ha->instance, faddr);
7230 }
7231 break;
7232 case FLASH_ERROR_LOG_1_REGION:
7233 if (ha->flags & FUNCTION_1) {
7234 ha->flash_errlog_start = faddr;
7235 QL_PRINT_9(CE_CONT, "(%d): flash_errlog_addr="
7236 "%xh\n", ha->instance, faddr);
7237 }
7238 break;
7239 default:
7240 break;
7241 }
7242 }
7243 kmem_free(bp, FLASH_LAYOUT_TABLE_SIZE);
7244
7245 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
7246 }
7247
7248 /*
7249 * ql_flash_nvram_defaults
7250 * Flash default addresses.
7251 *
7252 * Input:
7253 * ha: adapter state pointer.
7254 *
7255 * Returns:
7256 * ql local function return status code.
7257 *
7258 * Context:
7259 * Kernel context.
7260 */
7261 static void
ql_flash_nvram_defaults(ql_adapter_state_t * ha)7262 ql_flash_nvram_defaults(ql_adapter_state_t *ha)
7263 {
7264 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
7265
7266 if (ha->flags & FUNCTION_1) {
7267 if (CFG_IST(ha, CFG_CTRL_2300)) {
7268 ha->flash_nvram_addr = NVRAM_2300_FUNC1_ADDR;
7269 ha->flash_fw_addr = FLASH_2300_FIRMWARE_ADDR;
7270 } else if (CFG_IST(ha, CFG_CTRL_2422)) {
7271 ha->flash_data_addr = FLASH_24_25_DATA_ADDR;
7272 ha->flash_nvram_addr = NVRAM_2400_FUNC1_ADDR;
7273 ha->flash_vpd_addr = VPD_2400_FUNC1_ADDR;
7274 ha->flash_errlog_start = FLASH_2400_ERRLOG_START_ADDR_1;
7275 ha->flash_desc_addr = FLASH_2400_DESCRIPTOR_TABLE;
7276 ha->flash_fw_addr = FLASH_2400_FIRMWARE_ADDR;
7277 } else if (CFG_IST(ha, CFG_CTRL_25XX)) {
7278 ha->flash_data_addr = FLASH_24_25_DATA_ADDR;
7279 ha->flash_nvram_addr = NVRAM_2500_FUNC1_ADDR;
7280 ha->flash_vpd_addr = VPD_2500_FUNC1_ADDR;
7281 ha->flash_errlog_start = FLASH_2500_ERRLOG_START_ADDR_1;
7282 ha->flash_desc_addr = FLASH_2500_DESCRIPTOR_TABLE;
7283 ha->flash_fw_addr = FLASH_2500_FIRMWARE_ADDR;
7284 } else if (CFG_IST(ha, CFG_CTRL_81XX)) {
7285 ha->flash_data_addr = FLASH_8100_DATA_ADDR;
7286 ha->flash_nvram_addr = NVRAM_8100_FUNC1_ADDR;
7287 ha->flash_vpd_addr = VPD_8100_FUNC1_ADDR;
7288 ha->flash_errlog_start = FLASH_8100_ERRLOG_START_ADDR_1;
7289 ha->flash_desc_addr = FLASH_8100_DESCRIPTOR_TABLE;
7290 ha->flash_fw_addr = FLASH_8100_FIRMWARE_ADDR;
7291 } else if (CFG_IST(ha, CFG_CTRL_8021)) {
7292 ha->flash_data_addr = 0;
7293 ha->flash_nvram_addr = NVRAM_8021_FUNC1_ADDR;
7294 ha->flash_vpd_addr = VPD_8021_FUNC1_ADDR;
7295 ha->flash_errlog_start = 0;
7296 ha->flash_desc_addr = FLASH_8021_DESCRIPTOR_TABLE;
7297 ha->flash_fw_addr = FLASH_8021_FIRMWARE_ADDR;
7298 ha->flash_fw_size = FLASH_8021_FIRMWARE_SIZE;
7299 ha->bootloader_addr = FLASH_8021_BOOTLOADER_ADDR;
7300 ha->bootloader_size = FLASH_8021_BOOTLOADER_SIZE;
7301 }
7302 } else {
7303 if (CFG_IST(ha, CFG_CTRL_2200)) {
7304 ha->flash_nvram_addr = NVRAM_2200_FUNC0_ADDR;
7305 ha->flash_fw_addr = FLASH_2200_FIRMWARE_ADDR;
7306 } else if (CFG_IST(ha, CFG_CTRL_2300) ||
7307 (CFG_IST(ha, CFG_CTRL_6322))) {
7308 ha->flash_nvram_addr = NVRAM_2300_FUNC0_ADDR;
7309 ha->flash_fw_addr = FLASH_2300_FIRMWARE_ADDR;
7310 } else if (CFG_IST(ha, CFG_CTRL_2422)) {
7311 ha->flash_data_addr = FLASH_24_25_DATA_ADDR;
7312 ha->flash_nvram_addr = NVRAM_2400_FUNC0_ADDR;
7313 ha->flash_vpd_addr = VPD_2400_FUNC0_ADDR;
7314 ha->flash_errlog_start = FLASH_2400_ERRLOG_START_ADDR_0;
7315 ha->flash_desc_addr = FLASH_2400_DESCRIPTOR_TABLE;
7316 ha->flash_fw_addr = FLASH_2400_FIRMWARE_ADDR;
7317 } else if (CFG_IST(ha, CFG_CTRL_25XX)) {
7318 ha->flash_data_addr = FLASH_24_25_DATA_ADDR;
7319 ha->flash_nvram_addr = NVRAM_2500_FUNC0_ADDR;
7320 ha->flash_vpd_addr = VPD_2500_FUNC0_ADDR;
7321 ha->flash_errlog_start = FLASH_2500_ERRLOG_START_ADDR_0;
7322 ha->flash_desc_addr = FLASH_2500_DESCRIPTOR_TABLE;
7323 ha->flash_fw_addr = FLASH_2500_FIRMWARE_ADDR;
7324 } else if (CFG_IST(ha, CFG_CTRL_81XX)) {
7325 ha->flash_data_addr = FLASH_8100_DATA_ADDR;
7326 ha->flash_nvram_addr = NVRAM_8100_FUNC0_ADDR;
7327 ha->flash_vpd_addr = VPD_8100_FUNC0_ADDR;
7328 ha->flash_errlog_start = FLASH_8100_ERRLOG_START_ADDR_0;
7329 ha->flash_desc_addr = FLASH_8100_DESCRIPTOR_TABLE;
7330 ha->flash_fw_addr = FLASH_8100_FIRMWARE_ADDR;
7331 } else if (CFG_IST(ha, CFG_CTRL_8021)) {
7332 ha->flash_data_addr = 0;
7333 ha->flash_nvram_addr = NVRAM_8021_FUNC0_ADDR;
7334 ha->flash_vpd_addr = VPD_8021_FUNC0_ADDR;
7335 ha->flash_errlog_start = 0;
7336 ha->flash_desc_addr = FLASH_8021_DESCRIPTOR_TABLE;
7337 ha->flash_fw_addr = FLASH_8021_FIRMWARE_ADDR;
7338 ha->flash_fw_size = FLASH_8021_FIRMWARE_SIZE;
7339 ha->bootloader_addr = FLASH_8021_BOOTLOADER_ADDR;
7340 ha->bootloader_size = FLASH_8021_BOOTLOADER_SIZE;
7341 } else {
7342 EL(ha, "unassigned flash fn0 addr: %x\n",
7343 ha->device_id);
7344 }
7345 }
7346 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
7347 }
7348
7349 /*
7350 * ql_get_sfp
7351 * Returns sfp data to sdmapi caller
7352 *
7353 * Input:
7354 * ha: adapter state pointer.
7355 * cmd: Local EXT_IOCTL cmd struct pointer.
7356 * mode: flags.
7357 *
7358 * Returns:
7359 * None, request status indicated in cmd->Status.
7360 *
7361 * Context:
7362 * Kernel context.
7363 */
7364 static void
ql_get_sfp(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)7365 ql_get_sfp(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
7366 {
7367 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
7368
7369 if ((CFG_IST(ha, CFG_CTRL_24258081)) == 0) {
7370 cmd->Status = EXT_STATUS_INVALID_REQUEST;
7371 EL(ha, "failed, invalid request for HBA\n");
7372 return;
7373 }
7374
7375 if (cmd->ResponseLen < QL_24XX_SFP_SIZE) {
7376 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
7377 cmd->DetailStatus = QL_24XX_SFP_SIZE;
7378 EL(ha, "failed, ResponseLen < SFP len, len passed=%xh\n",
7379 cmd->ResponseLen);
7380 return;
7381 }
7382
7383 /* Dump SFP data in user buffer */
7384 if ((ql_dump_sfp(ha, (void *)(uintptr_t)(cmd->ResponseAdr),
7385 mode)) != 0) {
7386 cmd->Status = EXT_STATUS_COPY_ERR;
7387 EL(ha, "failed, copy error\n");
7388 } else {
7389 cmd->Status = EXT_STATUS_OK;
7390 }
7391
7392 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
7393 }
7394
7395 /*
7396 * ql_dump_sfp
7397 * Dumps SFP.
7398 *
7399 * Input:
7400 * ha: adapter state pointer.
7401 * bp: buffer address.
7402 * mode: flags
7403 *
7404 * Returns:
7405 *
7406 * Context:
7407 * Kernel context.
7408 */
7409 static int
ql_dump_sfp(ql_adapter_state_t * ha,void * bp,int mode)7410 ql_dump_sfp(ql_adapter_state_t *ha, void *bp, int mode)
7411 {
7412 dma_mem_t mem;
7413 uint32_t cnt;
7414 int rval2, rval = 0;
7415 uint32_t dxfer;
7416
7417 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
7418
7419 /* Get memory for SFP. */
7420
7421 if ((rval2 = ql_get_dma_mem(ha, &mem, 64, LITTLE_ENDIAN_DMA,
7422 QL_DMA_DATA_ALIGN)) != QL_SUCCESS) {
7423 EL(ha, "failed, ql_get_dma_mem=%xh\n", rval2);
7424 return (ENOMEM);
7425 }
7426
7427 for (cnt = 0; cnt < QL_24XX_SFP_SIZE; cnt += mem.size) {
7428 rval2 = ql_read_sfp(ha, &mem,
7429 (uint16_t)(cnt < 256 ? 0xA0 : 0xA2),
7430 (uint16_t)(cnt & 0xff));
7431 if (rval2 != QL_SUCCESS) {
7432 EL(ha, "failed, read_sfp=%xh\n", rval2);
7433 rval = EFAULT;
7434 break;
7435 }
7436
7437 /* copy the data back */
7438 if ((dxfer = ql_send_buffer_data(mem.bp, bp, mem.size,
7439 mode)) != mem.size) {
7440 /* ddi copy error */
7441 EL(ha, "failed, ddi copy; byte cnt = %xh", dxfer);
7442 rval = EFAULT;
7443 break;
7444 }
7445
7446 /* adjust the buffer pointer */
7447 bp = (caddr_t)bp + mem.size;
7448 }
7449
7450 ql_free_phys(ha, &mem);
7451
7452 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
7453
7454 return (rval);
7455 }
7456
7457 /*
7458 * ql_port_param
7459 * Retrieves or sets the firmware port speed settings
7460 *
7461 * Input:
7462 * ha: adapter state pointer.
7463 * cmd: Local EXT_IOCTL cmd struct pointer.
7464 * mode: flags.
7465 *
7466 * Returns:
7467 * None, request status indicated in cmd->Status.
7468 *
7469 * Context:
7470 * Kernel context.
7471 *
7472 */
7473 static void
ql_port_param(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)7474 ql_port_param(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
7475 {
7476 uint8_t *name;
7477 ql_tgt_t *tq;
7478 EXT_PORT_PARAM port_param = {0};
7479 uint32_t rval = QL_SUCCESS;
7480 uint32_t idma_rate;
7481
7482 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
7483
7484 if (CFG_IST(ha, CFG_CTRL_242581) == 0) {
7485 EL(ha, "invalid request for this HBA\n");
7486 cmd->Status = EXT_STATUS_INVALID_REQUEST;
7487 cmd->ResponseLen = 0;
7488 return;
7489 }
7490
7491 if (LOOP_NOT_READY(ha)) {
7492 EL(ha, "failed, loop not ready\n");
7493 cmd->Status = EXT_STATUS_DEVICE_OFFLINE;
7494 cmd->ResponseLen = 0;
7495 return;
7496 }
7497
7498 if (ddi_copyin((void *)(uintptr_t)cmd->RequestAdr,
7499 (void*)&port_param, sizeof (EXT_PORT_PARAM), mode) != 0) {
7500 EL(ha, "failed, ddi_copyin\n");
7501 cmd->Status = EXT_STATUS_COPY_ERR;
7502 cmd->ResponseLen = 0;
7503 return;
7504 }
7505
7506 if (port_param.FCScsiAddr.DestType != EXT_DEF_DESTTYPE_WWPN) {
7507 EL(ha, "Unsupported dest lookup type: %xh\n",
7508 port_param.FCScsiAddr.DestType);
7509 cmd->Status = EXT_STATUS_DEV_NOT_FOUND;
7510 cmd->ResponseLen = 0;
7511 return;
7512 }
7513
7514 name = port_param.FCScsiAddr.DestAddr.WWPN;
7515
7516 QL_PRINT_9(CE_CONT, "(%d): wwpn=%02x%02x%02x%02x%02x%02x%02x%02x\n",
7517 ha->instance, name[0], name[1], name[2], name[3], name[4],
7518 name[5], name[6], name[7]);
7519
7520 tq = ql_find_port(ha, name, (uint16_t)QLNT_PORT);
7521 if (tq == NULL || !VALID_TARGET_ID(ha, tq->loop_id)) {
7522 EL(ha, "failed, fc_port not found\n");
7523 cmd->Status = EXT_STATUS_DEV_NOT_FOUND;
7524 cmd->ResponseLen = 0;
7525 return;
7526 }
7527
7528 cmd->Status = EXT_STATUS_OK;
7529 cmd->DetailStatus = EXT_STATUS_OK;
7530
7531 switch (port_param.Mode) {
7532 case EXT_IIDMA_MODE_GET:
7533 /*
7534 * Report the firmware's port rate for the wwpn
7535 */
7536 rval = ql_iidma_rate(ha, tq->loop_id, &idma_rate,
7537 port_param.Mode);
7538
7539 if (rval != QL_SUCCESS) {
7540 EL(ha, "iidma get failed: %xh\n", rval);
7541 cmd->Status = EXT_STATUS_MAILBOX;
7542 cmd->DetailStatus = rval;
7543 cmd->ResponseLen = 0;
7544 } else {
7545 switch (idma_rate) {
7546 case IIDMA_RATE_1GB:
7547 port_param.Speed =
7548 EXT_DEF_PORTSPEED_1GBIT;
7549 break;
7550 case IIDMA_RATE_2GB:
7551 port_param.Speed =
7552 EXT_DEF_PORTSPEED_2GBIT;
7553 break;
7554 case IIDMA_RATE_4GB:
7555 port_param.Speed =
7556 EXT_DEF_PORTSPEED_4GBIT;
7557 break;
7558 case IIDMA_RATE_8GB:
7559 port_param.Speed =
7560 EXT_DEF_PORTSPEED_8GBIT;
7561 break;
7562 case IIDMA_RATE_10GB:
7563 port_param.Speed =
7564 EXT_DEF_PORTSPEED_10GBIT;
7565 break;
7566 default:
7567 port_param.Speed =
7568 EXT_DEF_PORTSPEED_UNKNOWN;
7569 EL(ha, "failed, Port speed rate=%xh\n",
7570 idma_rate);
7571 break;
7572 }
7573
7574 /* Copy back the data */
7575 rval = ddi_copyout((void *)&port_param,
7576 (void *)(uintptr_t)cmd->ResponseAdr,
7577 sizeof (EXT_PORT_PARAM), mode);
7578
7579 if (rval != 0) {
7580 cmd->Status = EXT_STATUS_COPY_ERR;
7581 cmd->ResponseLen = 0;
7582 EL(ha, "failed, ddi_copyout\n");
7583 } else {
7584 cmd->ResponseLen = (uint32_t)
7585 sizeof (EXT_PORT_PARAM);
7586 }
7587 }
7588 break;
7589
7590 case EXT_IIDMA_MODE_SET:
7591 /*
7592 * Set the firmware's port rate for the wwpn
7593 */
7594 switch (port_param.Speed) {
7595 case EXT_DEF_PORTSPEED_1GBIT:
7596 idma_rate = IIDMA_RATE_1GB;
7597 break;
7598 case EXT_DEF_PORTSPEED_2GBIT:
7599 idma_rate = IIDMA_RATE_2GB;
7600 break;
7601 case EXT_DEF_PORTSPEED_4GBIT:
7602 idma_rate = IIDMA_RATE_4GB;
7603 break;
7604 case EXT_DEF_PORTSPEED_8GBIT:
7605 idma_rate = IIDMA_RATE_8GB;
7606 break;
7607 case EXT_DEF_PORTSPEED_10GBIT:
7608 port_param.Speed = IIDMA_RATE_10GB;
7609 break;
7610 default:
7611 EL(ha, "invalid set iidma rate: %x\n",
7612 port_param.Speed);
7613 cmd->Status = EXT_STATUS_INVALID_PARAM;
7614 cmd->ResponseLen = 0;
7615 rval = QL_PARAMETER_ERROR;
7616 break;
7617 }
7618
7619 if (rval == QL_SUCCESS) {
7620 rval = ql_iidma_rate(ha, tq->loop_id, &idma_rate,
7621 port_param.Mode);
7622 if (rval != QL_SUCCESS) {
7623 EL(ha, "iidma set failed: %xh\n", rval);
7624 cmd->Status = EXT_STATUS_MAILBOX;
7625 cmd->DetailStatus = rval;
7626 cmd->ResponseLen = 0;
7627 }
7628 }
7629 break;
7630 default:
7631 EL(ha, "invalid mode specified: %x\n", port_param.Mode);
7632 cmd->Status = EXT_STATUS_INVALID_PARAM;
7633 cmd->ResponseLen = 0;
7634 cmd->DetailStatus = 0;
7635 break;
7636 }
7637
7638 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
7639 }
7640
7641 /*
7642 * ql_get_fwexttrace
7643 * Dumps f/w extended trace buffer
7644 *
7645 * Input:
7646 * ha: adapter state pointer.
7647 * bp: buffer address.
7648 * mode: flags
7649 *
7650 * Returns:
7651 *
7652 * Context:
7653 * Kernel context.
7654 */
7655 /* ARGSUSED */
7656 static void
ql_get_fwexttrace(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)7657 ql_get_fwexttrace(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
7658 {
7659 int rval;
7660 caddr_t payload;
7661
7662 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
7663
7664 if (CFG_IST(ha, CFG_CTRL_24258081) == 0) {
7665 EL(ha, "invalid request for this HBA\n");
7666 cmd->Status = EXT_STATUS_INVALID_REQUEST;
7667 cmd->ResponseLen = 0;
7668 return;
7669 }
7670
7671 if ((CFG_IST(ha, CFG_ENABLE_FWEXTTRACE) == 0) ||
7672 (ha->fwexttracebuf.bp == NULL)) {
7673 EL(ha, "f/w extended trace is not enabled\n");
7674 cmd->Status = EXT_STATUS_INVALID_REQUEST;
7675 cmd->ResponseLen = 0;
7676 return;
7677 }
7678
7679 if (cmd->ResponseLen < FWEXTSIZE) {
7680 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
7681 cmd->DetailStatus = FWEXTSIZE;
7682 EL(ha, "failed, ResponseLen (%xh) < %xh (FWEXTSIZE)\n",
7683 cmd->ResponseLen, FWEXTSIZE);
7684 cmd->ResponseLen = 0;
7685 return;
7686 }
7687
7688 /* Time Stamp */
7689 rval = ql_fw_etrace(ha, &ha->fwexttracebuf, FTO_INSERT_TIME_STAMP);
7690 if (rval != QL_SUCCESS) {
7691 EL(ha, "f/w extended trace insert"
7692 "time stamp failed: %xh\n", rval);
7693 cmd->Status = EXT_STATUS_ERR;
7694 cmd->ResponseLen = 0;
7695 return;
7696 }
7697
7698 /* Disable Tracing */
7699 rval = ql_fw_etrace(ha, &ha->fwexttracebuf, FTO_EXT_TRACE_DISABLE);
7700 if (rval != QL_SUCCESS) {
7701 EL(ha, "f/w extended trace disable failed: %xh\n", rval);
7702 cmd->Status = EXT_STATUS_ERR;
7703 cmd->ResponseLen = 0;
7704 return;
7705 }
7706
7707 /* Allocate payload buffer */
7708 payload = kmem_zalloc(FWEXTSIZE, KM_SLEEP);
7709 if (payload == NULL) {
7710 EL(ha, "failed, kmem_zalloc\n");
7711 cmd->Status = EXT_STATUS_NO_MEMORY;
7712 cmd->ResponseLen = 0;
7713 return;
7714 }
7715
7716 /* Sync DMA buffer. */
7717 (void) ddi_dma_sync(ha->fwexttracebuf.dma_handle, 0,
7718 FWEXTSIZE, DDI_DMA_SYNC_FORKERNEL);
7719
7720 /* Copy trace buffer data. */
7721 ddi_rep_get8(ha->fwexttracebuf.acc_handle, (uint8_t *)payload,
7722 (uint8_t *)ha->fwexttracebuf.bp, FWEXTSIZE,
7723 DDI_DEV_AUTOINCR);
7724
7725 /* Send payload to application. */
7726 if (ql_send_buffer_data(payload, (caddr_t)(uintptr_t)cmd->ResponseAdr,
7727 cmd->ResponseLen, mode) != cmd->ResponseLen) {
7728 EL(ha, "failed, send_buffer_data\n");
7729 cmd->Status = EXT_STATUS_COPY_ERR;
7730 cmd->ResponseLen = 0;
7731 } else {
7732 cmd->Status = EXT_STATUS_OK;
7733 }
7734
7735 kmem_free(payload, FWEXTSIZE);
7736
7737 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
7738 }
7739
7740 /*
7741 * ql_get_fwfcetrace
7742 * Dumps f/w fibre channel event trace buffer
7743 *
7744 * Input:
7745 * ha: adapter state pointer.
7746 * bp: buffer address.
7747 * mode: flags
7748 *
7749 * Returns:
7750 *
7751 * Context:
7752 * Kernel context.
7753 */
7754 /* ARGSUSED */
7755 static void
ql_get_fwfcetrace(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)7756 ql_get_fwfcetrace(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
7757 {
7758 int rval;
7759 caddr_t payload;
7760
7761 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
7762
7763 if (CFG_IST(ha, CFG_CTRL_24258081) == 0) {
7764 EL(ha, "invalid request for this HBA\n");
7765 cmd->Status = EXT_STATUS_INVALID_REQUEST;
7766 cmd->ResponseLen = 0;
7767 return;
7768 }
7769
7770 if ((CFG_IST(ha, CFG_ENABLE_FWFCETRACE) == 0) ||
7771 (ha->fwfcetracebuf.bp == NULL)) {
7772 EL(ha, "f/w FCE trace is not enabled\n");
7773 cmd->Status = EXT_STATUS_INVALID_REQUEST;
7774 cmd->ResponseLen = 0;
7775 return;
7776 }
7777
7778 if (cmd->ResponseLen < FWFCESIZE) {
7779 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
7780 cmd->DetailStatus = FWFCESIZE;
7781 EL(ha, "failed, ResponseLen (%xh) < %xh (FWFCESIZE)\n",
7782 cmd->ResponseLen, FWFCESIZE);
7783 cmd->ResponseLen = 0;
7784 return;
7785 }
7786
7787 /* Disable Tracing */
7788 rval = ql_fw_etrace(ha, &ha->fwfcetracebuf, FTO_FCE_TRACE_DISABLE);
7789 if (rval != QL_SUCCESS) {
7790 EL(ha, "f/w FCE trace disable failed: %xh\n", rval);
7791 cmd->Status = EXT_STATUS_ERR;
7792 cmd->ResponseLen = 0;
7793 return;
7794 }
7795
7796 /* Allocate payload buffer */
7797 payload = kmem_zalloc(FWEXTSIZE, KM_SLEEP);
7798 if (payload == NULL) {
7799 EL(ha, "failed, kmem_zalloc\n");
7800 cmd->Status = EXT_STATUS_NO_MEMORY;
7801 cmd->ResponseLen = 0;
7802 return;
7803 }
7804
7805 /* Sync DMA buffer. */
7806 (void) ddi_dma_sync(ha->fwfcetracebuf.dma_handle, 0,
7807 FWFCESIZE, DDI_DMA_SYNC_FORKERNEL);
7808
7809 /* Copy trace buffer data. */
7810 ddi_rep_get8(ha->fwfcetracebuf.acc_handle, (uint8_t *)payload,
7811 (uint8_t *)ha->fwfcetracebuf.bp, FWFCESIZE,
7812 DDI_DEV_AUTOINCR);
7813
7814 /* Send payload to application. */
7815 if (ql_send_buffer_data(payload, (caddr_t)(uintptr_t)cmd->ResponseAdr,
7816 cmd->ResponseLen, mode) != cmd->ResponseLen) {
7817 EL(ha, "failed, send_buffer_data\n");
7818 cmd->Status = EXT_STATUS_COPY_ERR;
7819 cmd->ResponseLen = 0;
7820 } else {
7821 cmd->Status = EXT_STATUS_OK;
7822 }
7823
7824 kmem_free(payload, FWFCESIZE);
7825
7826 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
7827 }
7828
7829 /*
7830 * ql_get_pci_data
7831 * Retrieves pci config space data
7832 *
7833 * Input:
7834 * ha: adapter state pointer.
7835 * cmd: Local EXT_IOCTL cmd struct pointer.
7836 * mode: flags.
7837 *
7838 * Returns:
7839 * None, request status indicated in cmd->Status.
7840 *
7841 * Context:
7842 * Kernel context.
7843 *
7844 */
7845 static void
ql_get_pci_data(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)7846 ql_get_pci_data(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
7847 {
7848 uint8_t cap_ptr;
7849 uint8_t cap_id;
7850 uint32_t buf_size = 256;
7851
7852 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
7853
7854 /*
7855 * First check the "Capabilities List" bit of the status register.
7856 */
7857 if (ql_pci_config_get16(ha, PCI_CONF_STAT) & PCI_STAT_CAP) {
7858 /*
7859 * Now get the capability pointer
7860 */
7861 cap_ptr = (uint8_t)ql_pci_config_get8(ha, PCI_CONF_CAP_PTR);
7862 while (cap_ptr != PCI_CAP_NEXT_PTR_NULL) {
7863 /*
7864 * Check for the pcie capability.
7865 */
7866 cap_id = (uint8_t)ql_pci_config_get8(ha, cap_ptr);
7867 if (cap_id == PCI_CAP_ID_PCI_E) {
7868 buf_size = 4096;
7869 break;
7870 }
7871 cap_ptr = (uint8_t)ql_pci_config_get8(ha,
7872 (cap_ptr + PCI_CAP_NEXT_PTR));
7873 }
7874 }
7875
7876 if (cmd->ResponseLen < buf_size) {
7877 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
7878 cmd->DetailStatus = buf_size;
7879 EL(ha, "failed ResponseLen < buf_size, len passed=%xh\n",
7880 cmd->ResponseLen);
7881 return;
7882 }
7883
7884 /* Dump PCI config data. */
7885 if ((ql_pci_dump(ha, (void *)(uintptr_t)(cmd->ResponseAdr),
7886 buf_size, mode)) != 0) {
7887 cmd->Status = EXT_STATUS_COPY_ERR;
7888 cmd->DetailStatus = 0;
7889 EL(ha, "failed, copy err pci_dump\n");
7890 } else {
7891 cmd->Status = EXT_STATUS_OK;
7892 cmd->DetailStatus = buf_size;
7893 }
7894
7895 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
7896 }
7897
7898 /*
7899 * ql_pci_dump
7900 * Dumps PCI config data to application buffer.
7901 *
7902 * Input:
7903 * ha = adapter state pointer.
7904 * bp = user buffer address.
7905 *
7906 * Returns:
7907 *
7908 * Context:
7909 * Kernel context.
7910 */
7911 int
ql_pci_dump(ql_adapter_state_t * ha,uint32_t * bp,uint32_t pci_size,int mode)7912 ql_pci_dump(ql_adapter_state_t *ha, uint32_t *bp, uint32_t pci_size, int mode)
7913 {
7914 uint32_t pci_os;
7915 uint32_t *ptr32, *org_ptr32;
7916
7917 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
7918
7919 ptr32 = kmem_zalloc(pci_size, KM_SLEEP);
7920 if (ptr32 == NULL) {
7921 EL(ha, "failed kmem_zalloc\n");
7922 return (ENOMEM);
7923 }
7924
7925 /* store the initial value of ptr32 */
7926 org_ptr32 = ptr32;
7927 for (pci_os = 0; pci_os < pci_size; pci_os += 4) {
7928 *ptr32 = (uint32_t)ql_pci_config_get32(ha, pci_os);
7929 LITTLE_ENDIAN_32(ptr32);
7930 ptr32++;
7931 }
7932
7933 if (ddi_copyout((void *)org_ptr32, (void *)bp, pci_size, mode) !=
7934 0) {
7935 EL(ha, "failed ddi_copyout\n");
7936 kmem_free(org_ptr32, pci_size);
7937 return (EFAULT);
7938 }
7939
7940 QL_DUMP_9(org_ptr32, 8, pci_size);
7941
7942 kmem_free(org_ptr32, pci_size);
7943
7944 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
7945
7946 return (0);
7947 }
7948
7949 /*
7950 * ql_menlo_reset
7951 * Reset Menlo
7952 *
7953 * Input:
7954 * ha: adapter state pointer.
7955 * bp: buffer address.
7956 * mode: flags
7957 *
7958 * Returns:
7959 *
7960 * Context:
7961 * Kernel context.
7962 */
7963 static void
ql_menlo_reset(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)7964 ql_menlo_reset(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
7965 {
7966 EXT_MENLO_RESET rst;
7967 ql_mbx_data_t mr;
7968 int rval;
7969
7970 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
7971
7972 if ((CFG_IST(ha, CFG_CTRL_MENLO)) == 0) {
7973 EL(ha, "failed, invalid request for HBA\n");
7974 cmd->Status = EXT_STATUS_INVALID_REQUEST;
7975 cmd->ResponseLen = 0;
7976 return;
7977 }
7978
7979 /*
7980 * TODO: only vp_index 0 can do this (?)
7981 */
7982
7983 /* Verify the size of request structure. */
7984 if (cmd->RequestLen < sizeof (EXT_MENLO_RESET)) {
7985 /* Return error */
7986 EL(ha, "RequestLen=%d < %d\n", cmd->RequestLen,
7987 sizeof (EXT_MENLO_RESET));
7988 cmd->Status = EXT_STATUS_INVALID_PARAM;
7989 cmd->DetailStatus = EXT_DSTATUS_REQUEST_LEN;
7990 cmd->ResponseLen = 0;
7991 return;
7992 }
7993
7994 /* Get reset request. */
7995 if (ddi_copyin((void *)(uintptr_t)cmd->RequestAdr,
7996 (void *)&rst, sizeof (EXT_MENLO_RESET), mode) != 0) {
7997 EL(ha, "failed, ddi_copyin\n");
7998 cmd->Status = EXT_STATUS_COPY_ERR;
7999 cmd->ResponseLen = 0;
8000 return;
8001 }
8002
8003 /* Wait for I/O to stop and daemon to stall. */
8004 if (ql_suspend_hba(ha, 0) != QL_SUCCESS) {
8005 EL(ha, "ql_stall_driver failed\n");
8006 ql_restart_hba(ha);
8007 cmd->Status = EXT_STATUS_BUSY;
8008 cmd->ResponseLen = 0;
8009 return;
8010 }
8011
8012 rval = ql_reset_menlo(ha, &mr, rst.Flags);
8013 if (rval != QL_SUCCESS) {
8014 EL(ha, "failed, status=%xh\n", rval);
8015 cmd->Status = EXT_STATUS_MAILBOX;
8016 cmd->DetailStatus = rval;
8017 cmd->ResponseLen = 0;
8018 } else if (mr.mb[1] != 0) {
8019 EL(ha, "failed, substatus=%d\n", mr.mb[1]);
8020 cmd->Status = EXT_STATUS_ERR;
8021 cmd->DetailStatus = mr.mb[1];
8022 cmd->ResponseLen = 0;
8023 }
8024
8025 ql_restart_hba(ha);
8026
8027 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
8028 }
8029
8030 /*
8031 * ql_menlo_get_fw_version
8032 * Get Menlo firmware version.
8033 *
8034 * Input:
8035 * ha: adapter state pointer.
8036 * bp: buffer address.
8037 * mode: flags
8038 *
8039 * Returns:
8040 *
8041 * Context:
8042 * Kernel context.
8043 */
8044 static void
ql_menlo_get_fw_version(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)8045 ql_menlo_get_fw_version(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
8046 {
8047 int rval;
8048 ql_mbx_iocb_t *pkt;
8049 EXT_MENLO_GET_FW_VERSION ver = {0};
8050
8051 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
8052
8053 if ((CFG_IST(ha, CFG_CTRL_MENLO)) == 0) {
8054 EL(ha, "failed, invalid request for HBA\n");
8055 cmd->Status = EXT_STATUS_INVALID_REQUEST;
8056 cmd->ResponseLen = 0;
8057 return;
8058 }
8059
8060 if (cmd->ResponseLen < sizeof (EXT_MENLO_GET_FW_VERSION)) {
8061 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
8062 cmd->DetailStatus = sizeof (EXT_MENLO_GET_FW_VERSION);
8063 EL(ha, "ResponseLen=%d < %d\n", cmd->ResponseLen,
8064 sizeof (EXT_MENLO_GET_FW_VERSION));
8065 cmd->ResponseLen = 0;
8066 return;
8067 }
8068
8069 /* Allocate packet. */
8070 pkt = kmem_zalloc(sizeof (ql_mbx_iocb_t), KM_SLEEP);
8071 if (pkt == NULL) {
8072 EL(ha, "failed, kmem_zalloc\n");
8073 cmd->Status = EXT_STATUS_NO_MEMORY;
8074 cmd->ResponseLen = 0;
8075 return;
8076 }
8077
8078 pkt->mvfy.entry_type = VERIFY_MENLO_TYPE;
8079 pkt->mvfy.entry_count = 1;
8080 pkt->mvfy.options_status = LE_16(VMF_DO_NOT_UPDATE_FW);
8081
8082 rval = ql_issue_mbx_iocb(ha, (caddr_t)pkt, sizeof (ql_mbx_iocb_t));
8083 LITTLE_ENDIAN_16(&pkt->mvfy.options_status);
8084 LITTLE_ENDIAN_16(&pkt->mvfy.failure_code);
8085 ver.FwVersion = LE_32(pkt->mvfy.fw_version);
8086
8087 if (rval != QL_SUCCESS || (pkt->mvfy.entry_status & 0x3c) != 0 ||
8088 pkt->mvfy.options_status != CS_COMPLETE) {
8089 /* Command error */
8090 EL(ha, "failed, status=%xh, es=%xh, cs=%xh, fc=%xh\n", rval,
8091 pkt->mvfy.entry_status & 0x3c, pkt->mvfy.options_status,
8092 pkt->mvfy.failure_code);
8093 cmd->Status = EXT_STATUS_ERR;
8094 cmd->DetailStatus = rval != QL_SUCCESS ? rval :
8095 QL_FUNCTION_FAILED;
8096 cmd->ResponseLen = 0;
8097 } else if (ddi_copyout((void *)&ver,
8098 (void *)(uintptr_t)cmd->ResponseAdr,
8099 sizeof (EXT_MENLO_GET_FW_VERSION), mode) != 0) {
8100 EL(ha, "failed, ddi_copyout\n");
8101 cmd->Status = EXT_STATUS_COPY_ERR;
8102 cmd->ResponseLen = 0;
8103 } else {
8104 cmd->ResponseLen = sizeof (EXT_MENLO_GET_FW_VERSION);
8105 }
8106
8107 kmem_free(pkt, sizeof (ql_mbx_iocb_t));
8108
8109 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
8110 }
8111
8112 /*
8113 * ql_menlo_update_fw
8114 * Get Menlo update firmware.
8115 *
8116 * Input:
8117 * ha: adapter state pointer.
8118 * bp: buffer address.
8119 * mode: flags
8120 *
8121 * Returns:
8122 *
8123 * Context:
8124 * Kernel context.
8125 */
8126 static void
ql_menlo_update_fw(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)8127 ql_menlo_update_fw(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
8128 {
8129 ql_mbx_iocb_t *pkt;
8130 dma_mem_t *dma_mem;
8131 EXT_MENLO_UPDATE_FW fw;
8132 uint32_t *ptr32;
8133 int rval;
8134
8135 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
8136
8137 if ((CFG_IST(ha, CFG_CTRL_MENLO)) == 0) {
8138 EL(ha, "failed, invalid request for HBA\n");
8139 cmd->Status = EXT_STATUS_INVALID_REQUEST;
8140 cmd->ResponseLen = 0;
8141 return;
8142 }
8143
8144 /*
8145 * TODO: only vp_index 0 can do this (?)
8146 */
8147
8148 /* Verify the size of request structure. */
8149 if (cmd->RequestLen < sizeof (EXT_MENLO_UPDATE_FW)) {
8150 /* Return error */
8151 EL(ha, "RequestLen=%d < %d\n", cmd->RequestLen,
8152 sizeof (EXT_MENLO_UPDATE_FW));
8153 cmd->Status = EXT_STATUS_INVALID_PARAM;
8154 cmd->DetailStatus = EXT_DSTATUS_REQUEST_LEN;
8155 cmd->ResponseLen = 0;
8156 return;
8157 }
8158
8159 /* Get update fw request. */
8160 if (ddi_copyin((caddr_t)(uintptr_t)cmd->RequestAdr, (caddr_t)&fw,
8161 sizeof (EXT_MENLO_UPDATE_FW), mode) != 0) {
8162 EL(ha, "failed, ddi_copyin\n");
8163 cmd->Status = EXT_STATUS_COPY_ERR;
8164 cmd->ResponseLen = 0;
8165 return;
8166 }
8167
8168 /* Wait for I/O to stop and daemon to stall. */
8169 if (ql_suspend_hba(ha, 0) != QL_SUCCESS) {
8170 EL(ha, "ql_stall_driver failed\n");
8171 ql_restart_hba(ha);
8172 cmd->Status = EXT_STATUS_BUSY;
8173 cmd->ResponseLen = 0;
8174 return;
8175 }
8176
8177 /* Allocate packet. */
8178 dma_mem = (dma_mem_t *)kmem_zalloc(sizeof (dma_mem_t), KM_SLEEP);
8179 if (dma_mem == NULL) {
8180 EL(ha, "failed, kmem_zalloc\n");
8181 cmd->Status = EXT_STATUS_NO_MEMORY;
8182 cmd->ResponseLen = 0;
8183 return;
8184 }
8185 pkt = kmem_zalloc(sizeof (ql_mbx_iocb_t), KM_SLEEP);
8186 if (pkt == NULL) {
8187 EL(ha, "failed, kmem_zalloc\n");
8188 kmem_free(dma_mem, sizeof (dma_mem_t));
8189 ql_restart_hba(ha);
8190 cmd->Status = EXT_STATUS_NO_MEMORY;
8191 cmd->ResponseLen = 0;
8192 return;
8193 }
8194
8195 /* Get DMA memory for the IOCB */
8196 if (ql_get_dma_mem(ha, dma_mem, fw.TotalByteCount, LITTLE_ENDIAN_DMA,
8197 QL_DMA_DATA_ALIGN) != QL_SUCCESS) {
8198 cmn_err(CE_WARN, "%s(%d): request queue DMA memory "
8199 "alloc failed", QL_NAME, ha->instance);
8200 kmem_free(pkt, sizeof (ql_mbx_iocb_t));
8201 kmem_free(dma_mem, sizeof (dma_mem_t));
8202 ql_restart_hba(ha);
8203 cmd->Status = EXT_STATUS_MS_NO_RESPONSE;
8204 cmd->ResponseLen = 0;
8205 return;
8206 }
8207
8208 /* Get firmware data. */
8209 if (ql_get_buffer_data((caddr_t)(uintptr_t)fw.pFwDataBytes, dma_mem->bp,
8210 fw.TotalByteCount, mode) != fw.TotalByteCount) {
8211 EL(ha, "failed, get_buffer_data\n");
8212 ql_free_dma_resource(ha, dma_mem);
8213 kmem_free(pkt, sizeof (ql_mbx_iocb_t));
8214 kmem_free(dma_mem, sizeof (dma_mem_t));
8215 ql_restart_hba(ha);
8216 cmd->Status = EXT_STATUS_COPY_ERR;
8217 cmd->ResponseLen = 0;
8218 return;
8219 }
8220
8221 /* Sync DMA buffer. */
8222 (void) ddi_dma_sync(dma_mem->dma_handle, 0, dma_mem->size,
8223 DDI_DMA_SYNC_FORDEV);
8224
8225 pkt->mvfy.entry_type = VERIFY_MENLO_TYPE;
8226 pkt->mvfy.entry_count = 1;
8227 pkt->mvfy.options_status = (uint16_t)LE_16(fw.Flags);
8228 ptr32 = dma_mem->bp;
8229 pkt->mvfy.fw_version = LE_32(ptr32[2]);
8230 pkt->mvfy.fw_size = LE_32(fw.TotalByteCount);
8231 pkt->mvfy.fw_sequence_size = LE_32(fw.TotalByteCount);
8232 pkt->mvfy.dseg_count = LE_16(1);
8233 pkt->mvfy.dseg_0_address[0] = (uint32_t)
8234 LE_32(LSD(dma_mem->cookie.dmac_laddress));
8235 pkt->mvfy.dseg_0_address[1] = (uint32_t)
8236 LE_32(MSD(dma_mem->cookie.dmac_laddress));
8237 pkt->mvfy.dseg_0_length = LE_32(fw.TotalByteCount);
8238
8239 rval = ql_issue_mbx_iocb(ha, (caddr_t)pkt, sizeof (ql_mbx_iocb_t));
8240 LITTLE_ENDIAN_16(&pkt->mvfy.options_status);
8241 LITTLE_ENDIAN_16(&pkt->mvfy.failure_code);
8242
8243 if (rval != QL_SUCCESS || (pkt->mvfy.entry_status & 0x3c) != 0 ||
8244 pkt->mvfy.options_status != CS_COMPLETE) {
8245 /* Command error */
8246 EL(ha, "failed, status=%xh, es=%xh, cs=%xh, fc=%xh\n", rval,
8247 pkt->mvfy.entry_status & 0x3c, pkt->mvfy.options_status,
8248 pkt->mvfy.failure_code);
8249 cmd->Status = EXT_STATUS_ERR;
8250 cmd->DetailStatus = rval != QL_SUCCESS ? rval :
8251 QL_FUNCTION_FAILED;
8252 cmd->ResponseLen = 0;
8253 }
8254
8255 ql_free_dma_resource(ha, dma_mem);
8256 kmem_free(pkt, sizeof (ql_mbx_iocb_t));
8257 kmem_free(dma_mem, sizeof (dma_mem_t));
8258 ql_restart_hba(ha);
8259
8260 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
8261 }
8262
8263 /*
8264 * ql_menlo_manage_info
8265 * Get Menlo manage info.
8266 *
8267 * Input:
8268 * ha: adapter state pointer.
8269 * bp: buffer address.
8270 * mode: flags
8271 *
8272 * Returns:
8273 *
8274 * Context:
8275 * Kernel context.
8276 */
8277 static void
ql_menlo_manage_info(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)8278 ql_menlo_manage_info(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
8279 {
8280 ql_mbx_iocb_t *pkt;
8281 dma_mem_t *dma_mem = NULL;
8282 EXT_MENLO_MANAGE_INFO info;
8283 int rval;
8284
8285 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
8286
8287
8288 /* The call is only supported for Schultz right now */
8289 if (CFG_IST(ha, CFG_CTRL_8081)) {
8290 ql_get_xgmac_statistics(ha, cmd, mode);
8291 QL_PRINT_9(CE_CONT, "(%d): CFG_CTRL_81XX done\n",
8292 ha->instance);
8293 return;
8294 }
8295
8296 if (!CFG_IST(ha, CFG_CTRL_8081) || !CFG_IST(ha, CFG_CTRL_MENLO)) {
8297 EL(ha, "failed, invalid request for HBA\n");
8298 cmd->Status = EXT_STATUS_INVALID_REQUEST;
8299 cmd->ResponseLen = 0;
8300 return;
8301 }
8302
8303 /* Verify the size of request structure. */
8304 if (cmd->RequestLen < sizeof (EXT_MENLO_MANAGE_INFO)) {
8305 /* Return error */
8306 EL(ha, "RequestLen=%d < %d\n", cmd->RequestLen,
8307 sizeof (EXT_MENLO_MANAGE_INFO));
8308 cmd->Status = EXT_STATUS_INVALID_PARAM;
8309 cmd->DetailStatus = EXT_DSTATUS_REQUEST_LEN;
8310 cmd->ResponseLen = 0;
8311 return;
8312 }
8313
8314 /* Get manage info request. */
8315 if (ddi_copyin((caddr_t)(uintptr_t)cmd->RequestAdr,
8316 (caddr_t)&info, sizeof (EXT_MENLO_MANAGE_INFO), mode) != 0) {
8317 EL(ha, "failed, ddi_copyin\n");
8318 cmd->Status = EXT_STATUS_COPY_ERR;
8319 cmd->ResponseLen = 0;
8320 return;
8321 }
8322
8323 /* Allocate packet. */
8324 pkt = kmem_zalloc(sizeof (ql_mbx_iocb_t), KM_SLEEP);
8325 if (pkt == NULL) {
8326 EL(ha, "failed, kmem_zalloc\n");
8327 ql_restart_driver(ha);
8328 cmd->Status = EXT_STATUS_NO_MEMORY;
8329 cmd->ResponseLen = 0;
8330 return;
8331 }
8332
8333 pkt->mdata.entry_type = MENLO_DATA_TYPE;
8334 pkt->mdata.entry_count = 1;
8335 pkt->mdata.options_status = (uint16_t)LE_16(info.Operation);
8336
8337 /* Get DMA memory for the IOCB */
8338 if (info.Operation == MENLO_OP_READ_MEM ||
8339 info.Operation == MENLO_OP_WRITE_MEM) {
8340 pkt->mdata.total_byte_count = LE_32(info.TotalByteCount);
8341 pkt->mdata.parameter_1 =
8342 LE_32(info.Parameters.ap.MenloMemory.StartingAddr);
8343 dma_mem = (dma_mem_t *)kmem_zalloc(sizeof (dma_mem_t),
8344 KM_SLEEP);
8345 if (dma_mem == NULL) {
8346 EL(ha, "failed, kmem_zalloc\n");
8347 kmem_free(pkt, sizeof (ql_mbx_iocb_t));
8348 cmd->Status = EXT_STATUS_NO_MEMORY;
8349 cmd->ResponseLen = 0;
8350 return;
8351 }
8352 if (ql_get_dma_mem(ha, dma_mem, info.TotalByteCount,
8353 LITTLE_ENDIAN_DMA, QL_DMA_DATA_ALIGN) != QL_SUCCESS) {
8354 cmn_err(CE_WARN, "%s(%d): request queue DMA memory "
8355 "alloc failed", QL_NAME, ha->instance);
8356 kmem_free(dma_mem, sizeof (dma_mem_t));
8357 kmem_free(pkt, sizeof (ql_mbx_iocb_t));
8358 cmd->Status = EXT_STATUS_MS_NO_RESPONSE;
8359 cmd->ResponseLen = 0;
8360 return;
8361 }
8362 if (info.Operation == MENLO_OP_WRITE_MEM) {
8363 /* Get data. */
8364 if (ql_get_buffer_data(
8365 (caddr_t)(uintptr_t)info.pDataBytes,
8366 dma_mem->bp, info.TotalByteCount, mode) !=
8367 info.TotalByteCount) {
8368 EL(ha, "failed, get_buffer_data\n");
8369 ql_free_dma_resource(ha, dma_mem);
8370 kmem_free(dma_mem, sizeof (dma_mem_t));
8371 kmem_free(pkt, sizeof (ql_mbx_iocb_t));
8372 cmd->Status = EXT_STATUS_COPY_ERR;
8373 cmd->ResponseLen = 0;
8374 return;
8375 }
8376 (void) ddi_dma_sync(dma_mem->dma_handle, 0,
8377 dma_mem->size, DDI_DMA_SYNC_FORDEV);
8378 }
8379 pkt->mdata.dseg_count = LE_16(1);
8380 pkt->mdata.dseg_0_address[0] = (uint32_t)
8381 LE_32(LSD(dma_mem->cookie.dmac_laddress));
8382 pkt->mdata.dseg_0_address[1] = (uint32_t)
8383 LE_32(MSD(dma_mem->cookie.dmac_laddress));
8384 pkt->mdata.dseg_0_length = LE_32(info.TotalByteCount);
8385 } else if (info.Operation & MENLO_OP_CHANGE_CONFIG) {
8386 pkt->mdata.parameter_1 =
8387 LE_32(info.Parameters.ap.MenloConfig.ConfigParamID);
8388 pkt->mdata.parameter_2 =
8389 LE_32(info.Parameters.ap.MenloConfig.ConfigParamData0);
8390 pkt->mdata.parameter_3 =
8391 LE_32(info.Parameters.ap.MenloConfig.ConfigParamData1);
8392 } else if (info.Operation & MENLO_OP_GET_INFO) {
8393 pkt->mdata.parameter_1 =
8394 LE_32(info.Parameters.ap.MenloInfo.InfoDataType);
8395 pkt->mdata.parameter_2 =
8396 LE_32(info.Parameters.ap.MenloInfo.InfoContext);
8397 }
8398
8399 rval = ql_issue_mbx_iocb(ha, (caddr_t)pkt, sizeof (ql_mbx_iocb_t));
8400 LITTLE_ENDIAN_16(&pkt->mdata.options_status);
8401 LITTLE_ENDIAN_16(&pkt->mdata.failure_code);
8402
8403 if (rval != QL_SUCCESS || (pkt->mdata.entry_status & 0x3c) != 0 ||
8404 pkt->mdata.options_status != CS_COMPLETE) {
8405 /* Command error */
8406 EL(ha, "failed, status=%xh, es=%xh, cs=%xh, fc=%xh\n", rval,
8407 pkt->mdata.entry_status & 0x3c, pkt->mdata.options_status,
8408 pkt->mdata.failure_code);
8409 cmd->Status = EXT_STATUS_ERR;
8410 cmd->DetailStatus = rval != QL_SUCCESS ? rval :
8411 QL_FUNCTION_FAILED;
8412 cmd->ResponseLen = 0;
8413 } else if (info.Operation == MENLO_OP_READ_MEM) {
8414 (void) ddi_dma_sync(dma_mem->dma_handle, 0, dma_mem->size,
8415 DDI_DMA_SYNC_FORKERNEL);
8416 if (ql_send_buffer_data((caddr_t)(uintptr_t)info.pDataBytes,
8417 dma_mem->bp, info.TotalByteCount, mode) !=
8418 info.TotalByteCount) {
8419 cmd->Status = EXT_STATUS_COPY_ERR;
8420 cmd->ResponseLen = 0;
8421 }
8422 }
8423
8424 ql_free_dma_resource(ha, dma_mem);
8425 kmem_free(dma_mem, sizeof (dma_mem_t));
8426 kmem_free(pkt, sizeof (ql_mbx_iocb_t));
8427
8428 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
8429 }
8430
8431 /*
8432 * ql_suspend_hba
8433 * Suspends all adapter ports.
8434 *
8435 * Input:
8436 * ha: adapter state pointer.
8437 * options: BIT_0 --> leave driver stalled on exit if
8438 * failed.
8439 *
8440 * Returns:
8441 * ql local function return status code.
8442 *
8443 * Context:
8444 * Kernel context.
8445 */
8446 static int
ql_suspend_hba(ql_adapter_state_t * ha,uint32_t opt)8447 ql_suspend_hba(ql_adapter_state_t *ha, uint32_t opt)
8448 {
8449 ql_adapter_state_t *ha2;
8450 ql_link_t *link;
8451 int rval = QL_SUCCESS;
8452
8453 /* Quiesce I/O on all adapter ports */
8454 for (link = ql_hba.first; link != NULL; link = link->next) {
8455 ha2 = link->base_address;
8456
8457 if (ha2->fru_hba_index != ha->fru_hba_index) {
8458 continue;
8459 }
8460
8461 if ((rval = ql_stall_driver(ha2, opt)) != QL_SUCCESS) {
8462 EL(ha, "ql_stall_driver status=%xh\n", rval);
8463 break;
8464 }
8465 }
8466
8467 return (rval);
8468 }
8469
8470 /*
8471 * ql_restart_hba
8472 * Restarts adapter.
8473 *
8474 * Input:
8475 * ha: adapter state pointer.
8476 *
8477 * Context:
8478 * Kernel context.
8479 */
8480 static void
ql_restart_hba(ql_adapter_state_t * ha)8481 ql_restart_hba(ql_adapter_state_t *ha)
8482 {
8483 ql_adapter_state_t *ha2;
8484 ql_link_t *link;
8485
8486 /* Resume I/O on all adapter ports */
8487 for (link = ql_hba.first; link != NULL; link = link->next) {
8488 ha2 = link->base_address;
8489
8490 if (ha2->fru_hba_index != ha->fru_hba_index) {
8491 continue;
8492 }
8493
8494 ql_restart_driver(ha2);
8495 }
8496 }
8497
8498 /*
8499 * ql_get_vp_cnt_id
8500 * Retrieves pci config space data
8501 *
8502 * Input:
8503 * ha: adapter state pointer.
8504 * cmd: Local EXT_IOCTL cmd struct pointer.
8505 * mode: flags.
8506 *
8507 * Returns:
8508 * None, request status indicated in cmd->Status.
8509 *
8510 * Context:
8511 * Kernel context.
8512 *
8513 */
8514 static void
ql_get_vp_cnt_id(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)8515 ql_get_vp_cnt_id(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
8516 {
8517 ql_adapter_state_t *vha;
8518 PEXT_VPORT_ID_CNT ptmp_vp;
8519 int id = 0;
8520 int rval;
8521 char name[MAXPATHLEN];
8522
8523 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
8524
8525 /*
8526 * To be backward compatible with older API
8527 * check for the size of old EXT_VPORT_ID_CNT
8528 */
8529 if (cmd->ResponseLen < sizeof (EXT_VPORT_ID_CNT) &&
8530 (cmd->ResponseLen != EXT_OLD_VPORT_ID_CNT_SIZE)) {
8531 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
8532 cmd->DetailStatus = sizeof (EXT_VPORT_ID_CNT);
8533 EL(ha, "failed, ResponseLen < EXT_VPORT_ID_CNT, Len=%xh\n",
8534 cmd->ResponseLen);
8535 cmd->ResponseLen = 0;
8536 return;
8537 }
8538
8539 ptmp_vp = (EXT_VPORT_ID_CNT *)
8540 kmem_zalloc(sizeof (EXT_VPORT_ID_CNT), KM_SLEEP);
8541 if (ptmp_vp == NULL) {
8542 EL(ha, "failed, kmem_zalloc\n");
8543 cmd->ResponseLen = 0;
8544 return;
8545 }
8546 vha = ha->vp_next;
8547 while (vha != NULL) {
8548 ptmp_vp->VpCnt++;
8549 ptmp_vp->VpId[id] = vha->vp_index;
8550 (void) ddi_pathname(vha->dip, name);
8551 (void) strcpy((char *)ptmp_vp->vp_path[id], name);
8552 ptmp_vp->VpDrvInst[id] = (int32_t)vha->instance;
8553 id++;
8554 vha = vha->vp_next;
8555 }
8556 rval = ddi_copyout((void *)ptmp_vp,
8557 (void *)(uintptr_t)(cmd->ResponseAdr),
8558 cmd->ResponseLen, mode);
8559 if (rval != 0) {
8560 cmd->Status = EXT_STATUS_COPY_ERR;
8561 cmd->ResponseLen = 0;
8562 EL(ha, "failed, ddi_copyout\n");
8563 } else {
8564 cmd->ResponseLen = sizeof (EXT_VPORT_ID_CNT);
8565 QL_PRINT_9(CE_CONT, "(%d): done, vport_cnt=%d\n",
8566 ha->instance, ptmp_vp->VpCnt);
8567 }
8568
8569 }
8570
8571 /*
8572 * ql_vp_ioctl
8573 * Performs all EXT_CC_VPORT_CMD functions.
8574 *
8575 * Input:
8576 * ha: adapter state pointer.
8577 * cmd: Local EXT_IOCTL cmd struct pointer.
8578 * mode: flags.
8579 *
8580 * Returns:
8581 * None, request status indicated in cmd->Status.
8582 *
8583 * Context:
8584 * Kernel context.
8585 */
8586 static void
ql_vp_ioctl(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)8587 ql_vp_ioctl(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
8588 {
8589 QL_PRINT_9(CE_CONT, "(%d): started, cmd=%d\n", ha->instance,
8590 cmd->SubCode);
8591
8592 /* case off on command subcode */
8593 switch (cmd->SubCode) {
8594 case EXT_VF_SC_VPORT_GETINFO:
8595 ql_qry_vport(ha, cmd, mode);
8596 break;
8597 default:
8598 /* function not supported. */
8599 cmd->Status = EXT_STATUS_UNSUPPORTED_SUBCODE;
8600 EL(ha, "failed, Unsupported Subcode=%xh\n",
8601 cmd->SubCode);
8602 break;
8603 }
8604
8605 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
8606 }
8607
8608 /*
8609 * ql_qry_vport
8610 * Performs EXT_VF_SC_VPORT_GETINFO subfunction.
8611 *
8612 * Input:
8613 * ha: adapter state pointer.
8614 * cmd: EXT_IOCTL cmd struct pointer.
8615 * mode: flags.
8616 *
8617 * Returns:
8618 * None, request status indicated in cmd->Status.
8619 *
8620 * Context:
8621 * Kernel context.
8622 */
8623 static void
ql_qry_vport(ql_adapter_state_t * vha,EXT_IOCTL * cmd,int mode)8624 ql_qry_vport(ql_adapter_state_t *vha, EXT_IOCTL *cmd, int mode)
8625 {
8626 ql_adapter_state_t *tmp_vha;
8627 EXT_VPORT_INFO tmp_vport = {0};
8628 int max_vport;
8629
8630 QL_PRINT_9(CE_CONT, "(%d): started\n", vha->instance);
8631
8632 if (cmd->ResponseLen < sizeof (EXT_VPORT_INFO)) {
8633 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
8634 cmd->DetailStatus = sizeof (EXT_VPORT_INFO);
8635 EL(vha, "failed, ResponseLen < EXT_VPORT_INFO, Len=%xh\n",
8636 cmd->ResponseLen);
8637 cmd->ResponseLen = 0;
8638 return;
8639 }
8640
8641 /* Fill in the vport information. */
8642 bcopy(vha->loginparams.node_ww_name.raw_wwn, tmp_vport.wwnn,
8643 EXT_DEF_WWN_NAME_SIZE);
8644 bcopy(vha->loginparams.nport_ww_name.raw_wwn, tmp_vport.wwpn,
8645 EXT_DEF_WWN_NAME_SIZE);
8646 tmp_vport.state = vha->state;
8647 tmp_vport.id = vha->vp_index;
8648
8649 tmp_vha = vha->pha->vp_next;
8650 while (tmp_vha != NULL) {
8651 tmp_vport.used++;
8652 tmp_vha = tmp_vha->vp_next;
8653 }
8654
8655 max_vport = (CFG_IST(vha, CFG_CTRL_2422) ? MAX_24_VIRTUAL_PORTS :
8656 MAX_25_VIRTUAL_PORTS);
8657 if (max_vport > tmp_vport.used) {
8658 tmp_vport.free = max_vport - tmp_vport.used;
8659 }
8660
8661 if (ddi_copyout((void *)&tmp_vport,
8662 (void *)(uintptr_t)(cmd->ResponseAdr),
8663 sizeof (EXT_VPORT_INFO), mode) != 0) {
8664 cmd->Status = EXT_STATUS_COPY_ERR;
8665 cmd->ResponseLen = 0;
8666 EL(vha, "failed, ddi_copyout\n");
8667 } else {
8668 cmd->ResponseLen = sizeof (EXT_VPORT_INFO);
8669 QL_PRINT_9(CE_CONT, "(%d): done\n", vha->instance);
8670 }
8671 }
8672
8673 /*
8674 * ql_access_flash
8675 * Performs all EXT_CC_ACCESS_FLASH_OS functions.
8676 *
8677 * Input:
8678 * pi: port info pointer.
8679 * cmd: Local EXT_IOCTL cmd struct pointer.
8680 * mode: flags.
8681 *
8682 * Returns:
8683 * None, request status indicated in cmd->Status.
8684 *
8685 * Context:
8686 * Kernel context.
8687 */
8688 static void
ql_access_flash(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)8689 ql_access_flash(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
8690 {
8691 int rval;
8692
8693 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
8694
8695 switch (cmd->SubCode) {
8696 case EXT_SC_FLASH_READ:
8697 if ((rval = ql_flash_fcode_dump(ha,
8698 (void *)(uintptr_t)(cmd->ResponseAdr),
8699 (size_t)(cmd->ResponseLen), cmd->Reserved1, mode)) != 0) {
8700 cmd->Status = EXT_STATUS_COPY_ERR;
8701 cmd->ResponseLen = 0;
8702 EL(ha, "flash_fcode_dump status=%xh\n", rval);
8703 }
8704 break;
8705 case EXT_SC_FLASH_WRITE:
8706 if ((rval = ql_r_m_w_flash(ha,
8707 (void *)(uintptr_t)(cmd->RequestAdr),
8708 (size_t)(cmd->RequestLen), cmd->Reserved1, mode)) !=
8709 QL_SUCCESS) {
8710 cmd->Status = EXT_STATUS_COPY_ERR;
8711 cmd->ResponseLen = 0;
8712 EL(ha, "r_m_w_flash status=%xh\n", rval);
8713 } else {
8714 /* Reset caches on all adapter instances. */
8715 ql_update_flash_caches(ha);
8716 }
8717 break;
8718 default:
8719 EL(ha, "unknown subcode=%xh\n", cmd->SubCode);
8720 cmd->Status = EXT_STATUS_ERR;
8721 cmd->ResponseLen = 0;
8722 break;
8723 }
8724
8725 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
8726 }
8727
8728 /*
8729 * ql_reset_cmd
8730 * Performs all EXT_CC_RESET_FW_OS functions.
8731 *
8732 * Input:
8733 * ha: adapter state pointer.
8734 * cmd: Local EXT_IOCTL cmd struct pointer.
8735 *
8736 * Returns:
8737 * None, request status indicated in cmd->Status.
8738 *
8739 * Context:
8740 * Kernel context.
8741 */
8742 static void
ql_reset_cmd(ql_adapter_state_t * ha,EXT_IOCTL * cmd)8743 ql_reset_cmd(ql_adapter_state_t *ha, EXT_IOCTL *cmd)
8744 {
8745 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
8746
8747 switch (cmd->SubCode) {
8748 case EXT_SC_RESET_FC_FW:
8749 EL(ha, "isp_abort_needed\n");
8750 ql_awaken_task_daemon(ha, NULL, ISP_ABORT_NEEDED, 0);
8751 break;
8752 case EXT_SC_RESET_MPI_FW:
8753 if (!(CFG_IST(ha, CFG_CTRL_81XX))) {
8754 EL(ha, "invalid request for HBA\n");
8755 cmd->Status = EXT_STATUS_INVALID_REQUEST;
8756 cmd->ResponseLen = 0;
8757 } else {
8758 /* Wait for I/O to stop and daemon to stall. */
8759 if (ql_suspend_hba(ha, 0) != QL_SUCCESS) {
8760 EL(ha, "ql_suspend_hba failed\n");
8761 cmd->Status = EXT_STATUS_BUSY;
8762 cmd->ResponseLen = 0;
8763 } else if (ql_restart_mpi(ha) != QL_SUCCESS) {
8764 cmd->Status = EXT_STATUS_ERR;
8765 cmd->ResponseLen = 0;
8766 } else {
8767 uint8_t timer;
8768 /*
8769 * While the restart_mpi mailbox cmd may be
8770 * done the MPI is not. Wait at least 6 sec. or
8771 * exit if the loop comes up.
8772 */
8773 for (timer = 6; timer; timer--) {
8774 if (!(ha->task_daemon_flags &
8775 LOOP_DOWN)) {
8776 break;
8777 }
8778 /* Delay for 1 second. */
8779 ql_delay(ha, 1000000);
8780 }
8781 }
8782 ql_restart_hba(ha);
8783 }
8784 break;
8785 default:
8786 EL(ha, "unknown subcode=%xh\n", cmd->SubCode);
8787 cmd->Status = EXT_STATUS_ERR;
8788 cmd->ResponseLen = 0;
8789 break;
8790 }
8791
8792 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
8793 }
8794
8795 /*
8796 * ql_get_dcbx_parameters
8797 * Get DCBX parameters.
8798 *
8799 * Input:
8800 * ha: adapter state pointer.
8801 * cmd: User space CT arguments pointer.
8802 * mode: flags.
8803 */
8804 static void
ql_get_dcbx_parameters(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)8805 ql_get_dcbx_parameters(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
8806 {
8807 uint8_t *tmp_buf;
8808 int rval;
8809
8810 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
8811
8812 if (!(CFG_IST(ha, CFG_CTRL_8081))) {
8813 EL(ha, "invalid request for HBA\n");
8814 cmd->Status = EXT_STATUS_INVALID_REQUEST;
8815 cmd->ResponseLen = 0;
8816 return;
8817 }
8818
8819 /* Allocate memory for command. */
8820 tmp_buf = kmem_zalloc(EXT_DEF_DCBX_PARAM_BUF_SIZE, KM_SLEEP);
8821 if (tmp_buf == NULL) {
8822 EL(ha, "failed, kmem_zalloc\n");
8823 cmd->Status = EXT_STATUS_NO_MEMORY;
8824 cmd->ResponseLen = 0;
8825 return;
8826 }
8827 /* Send command */
8828 rval = ql_get_dcbx_params(ha, EXT_DEF_DCBX_PARAM_BUF_SIZE,
8829 (caddr_t)tmp_buf);
8830 if (rval != QL_SUCCESS) {
8831 /* error */
8832 EL(ha, "failed, get_dcbx_params_mbx=%xh\n", rval);
8833 kmem_free(tmp_buf, EXT_DEF_DCBX_PARAM_BUF_SIZE);
8834 cmd->Status = EXT_STATUS_ERR;
8835 cmd->ResponseLen = 0;
8836 return;
8837 }
8838
8839 /* Copy the response */
8840 if (ql_send_buffer_data((caddr_t)tmp_buf,
8841 (caddr_t)(uintptr_t)cmd->ResponseAdr,
8842 EXT_DEF_DCBX_PARAM_BUF_SIZE, mode) != EXT_DEF_DCBX_PARAM_BUF_SIZE) {
8843 EL(ha, "failed, ddi_copyout\n");
8844 cmd->Status = EXT_STATUS_COPY_ERR;
8845 cmd->ResponseLen = 0;
8846 } else {
8847 cmd->ResponseLen = EXT_DEF_DCBX_PARAM_BUF_SIZE;
8848 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
8849 }
8850 kmem_free(tmp_buf, EXT_DEF_DCBX_PARAM_BUF_SIZE);
8851
8852 }
8853
8854 /*
8855 * ql_qry_cna_port
8856 * Performs EXT_SC_QUERY_CNA_PORT subfunction.
8857 *
8858 * Input:
8859 * ha: adapter state pointer.
8860 * cmd: EXT_IOCTL cmd struct pointer.
8861 * mode: flags.
8862 *
8863 * Returns:
8864 * None, request status indicated in cmd->Status.
8865 *
8866 * Context:
8867 * Kernel context.
8868 */
8869 static void
ql_qry_cna_port(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)8870 ql_qry_cna_port(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
8871 {
8872 EXT_CNA_PORT cna_port = {0};
8873
8874 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
8875
8876 if (!(CFG_IST(ha, CFG_CTRL_8081))) {
8877 EL(ha, "invalid request for HBA\n");
8878 cmd->Status = EXT_STATUS_INVALID_REQUEST;
8879 cmd->ResponseLen = 0;
8880 return;
8881 }
8882
8883 if (cmd->ResponseLen < sizeof (EXT_CNA_PORT)) {
8884 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
8885 cmd->DetailStatus = sizeof (EXT_CNA_PORT);
8886 EL(ha, "failed, ResponseLen < EXT_CNA_PORT, Len=%xh\n",
8887 cmd->ResponseLen);
8888 cmd->ResponseLen = 0;
8889 return;
8890 }
8891
8892 cna_port.VLanId = ha->fcoe_vlan_id;
8893 cna_port.FabricParam = ha->fabric_params;
8894 bcopy(ha->fcoe_vnport_mac, cna_port.VNPortMACAddress,
8895 EXT_DEF_MAC_ADDRESS_SIZE);
8896
8897 if (ddi_copyout((void *)&cna_port,
8898 (void *)(uintptr_t)(cmd->ResponseAdr),
8899 sizeof (EXT_CNA_PORT), mode) != 0) {
8900 cmd->Status = EXT_STATUS_COPY_ERR;
8901 cmd->ResponseLen = 0;
8902 EL(ha, "failed, ddi_copyout\n");
8903 } else {
8904 cmd->ResponseLen = sizeof (EXT_CNA_PORT);
8905 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
8906 }
8907 }
8908
8909 /*
8910 * ql_qry_adapter_versions
8911 * Performs EXT_SC_QUERY_ADAPTER_VERSIONS subfunction.
8912 *
8913 * Input:
8914 * ha: adapter state pointer.
8915 * cmd: EXT_IOCTL cmd struct pointer.
8916 * mode: flags.
8917 *
8918 * Returns:
8919 * None, request status indicated in cmd->Status.
8920 *
8921 * Context:
8922 * Kernel context.
8923 */
8924 static void
ql_qry_adapter_versions(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)8925 ql_qry_adapter_versions(ql_adapter_state_t *ha, EXT_IOCTL *cmd,
8926 int mode)
8927 {
8928 uint8_t is_8142, mpi_cap;
8929 uint32_t ver_len, transfer_size;
8930 PEXT_ADAPTERREGIONVERSION padapter_ver = NULL;
8931
8932 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
8933
8934 /* 8142s do not have a EDC PHY firmware. */
8935 mpi_cap = (uint8_t)(ha->mpi_capability_list >> 8);
8936
8937 is_8142 = 0;
8938 /* Sizeof (Length + Reserved) = 8 Bytes */
8939 if (mpi_cap == 0x02 || mpi_cap == 0x04) {
8940 ver_len = (sizeof (EXT_REGIONVERSION) * (NO_OF_VERSIONS - 1))
8941 + 8;
8942 is_8142 = 1;
8943 } else {
8944 ver_len = (sizeof (EXT_REGIONVERSION) * NO_OF_VERSIONS) + 8;
8945 }
8946
8947 /* Allocate local memory for EXT_ADAPTERREGIONVERSION */
8948 padapter_ver = (EXT_ADAPTERREGIONVERSION *)kmem_zalloc(ver_len,
8949 KM_SLEEP);
8950
8951 if (padapter_ver == NULL) {
8952 EL(ha, "failed, kmem_zalloc\n");
8953 cmd->Status = EXT_STATUS_NO_MEMORY;
8954 cmd->ResponseLen = 0;
8955 return;
8956 }
8957
8958 padapter_ver->Length = 1;
8959 /* Copy MPI version */
8960 padapter_ver->RegionVersion[0].Region =
8961 EXT_OPT_ROM_REGION_MPI_RISC_FW;
8962 padapter_ver->RegionVersion[0].Version[0] =
8963 ha->mpi_fw_major_version;
8964 padapter_ver->RegionVersion[0].Version[1] =
8965 ha->mpi_fw_minor_version;
8966 padapter_ver->RegionVersion[0].Version[2] =
8967 ha->mpi_fw_subminor_version;
8968 padapter_ver->RegionVersion[0].VersionLength = 3;
8969 padapter_ver->RegionVersion[0].Location = RUNNING_VERSION;
8970
8971 if (!is_8142) {
8972 padapter_ver->RegionVersion[1].Region =
8973 EXT_OPT_ROM_REGION_EDC_PHY_FW;
8974 padapter_ver->RegionVersion[1].Version[0] =
8975 ha->phy_fw_major_version;
8976 padapter_ver->RegionVersion[1].Version[1] =
8977 ha->phy_fw_minor_version;
8978 padapter_ver->RegionVersion[1].Version[2] =
8979 ha->phy_fw_subminor_version;
8980 padapter_ver->RegionVersion[1].VersionLength = 3;
8981 padapter_ver->RegionVersion[1].Location = RUNNING_VERSION;
8982 padapter_ver->Length = NO_OF_VERSIONS;
8983 }
8984
8985 if (cmd->ResponseLen < ver_len) {
8986 EL(ha, "failed, ResponseLen < ver_len, ",
8987 "RespLen=%xh ver_len=%xh\n", cmd->ResponseLen, ver_len);
8988 /* Calculate the No. of valid versions being returned. */
8989 padapter_ver->Length = (uint32_t)
8990 ((cmd->ResponseLen - 8) / sizeof (EXT_REGIONVERSION));
8991 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
8992 cmd->DetailStatus = ver_len;
8993 transfer_size = cmd->ResponseLen;
8994 } else {
8995 transfer_size = ver_len;
8996 }
8997
8998 if (ddi_copyout((void *)padapter_ver,
8999 (void *)(uintptr_t)(cmd->ResponseAdr),
9000 transfer_size, mode) != 0) {
9001 cmd->Status = EXT_STATUS_COPY_ERR;
9002 cmd->ResponseLen = 0;
9003 EL(ha, "failed, ddi_copyout\n");
9004 } else {
9005 cmd->ResponseLen = ver_len;
9006 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
9007 }
9008
9009 kmem_free(padapter_ver, ver_len);
9010 }
9011
9012 /*
9013 * ql_get_xgmac_statistics
9014 * Get XgMac information
9015 *
9016 * Input:
9017 * ha: adapter state pointer.
9018 * cmd: EXT_IOCTL cmd struct pointer.
9019 * mode: flags.
9020 *
9021 * Returns:
9022 * None, request status indicated in cmd->Status.
9023 *
9024 * Context:
9025 * Kernel context.
9026 */
9027 static void
ql_get_xgmac_statistics(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)9028 ql_get_xgmac_statistics(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
9029 {
9030 int rval;
9031 uint32_t size;
9032 int8_t *tmp_buf;
9033 EXT_MENLO_MANAGE_INFO info;
9034
9035 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
9036
9037 /* Verify the size of request structure. */
9038 if (cmd->RequestLen < sizeof (EXT_MENLO_MANAGE_INFO)) {
9039 /* Return error */
9040 EL(ha, "RequestLen=%d < %d\n", cmd->RequestLen,
9041 sizeof (EXT_MENLO_MANAGE_INFO));
9042 cmd->Status = EXT_STATUS_INVALID_PARAM;
9043 cmd->DetailStatus = EXT_DSTATUS_REQUEST_LEN;
9044 cmd->ResponseLen = 0;
9045 return;
9046 }
9047
9048 /* Get manage info request. */
9049 if (ddi_copyin((caddr_t)(uintptr_t)cmd->RequestAdr,
9050 (caddr_t)&info, sizeof (EXT_MENLO_MANAGE_INFO), mode) != 0) {
9051 EL(ha, "failed, ddi_copyin\n");
9052 cmd->Status = EXT_STATUS_COPY_ERR;
9053 cmd->ResponseLen = 0;
9054 return;
9055 }
9056
9057 size = info.TotalByteCount;
9058 if (!size) {
9059 /* parameter error */
9060 cmd->Status = EXT_STATUS_INVALID_PARAM;
9061 cmd->DetailStatus = 0;
9062 EL(ha, "failed, size=%xh\n", size);
9063 cmd->ResponseLen = 0;
9064 return;
9065 }
9066
9067 /* Allocate memory for command. */
9068 tmp_buf = kmem_zalloc(size, KM_SLEEP);
9069 if (tmp_buf == NULL) {
9070 EL(ha, "failed, kmem_zalloc\n");
9071 cmd->Status = EXT_STATUS_NO_MEMORY;
9072 cmd->ResponseLen = 0;
9073 return;
9074 }
9075
9076 if (!(info.Operation & MENLO_OP_GET_INFO)) {
9077 EL(ha, "Invalid request for 81XX\n");
9078 kmem_free(tmp_buf, size);
9079 cmd->Status = EXT_STATUS_ERR;
9080 cmd->ResponseLen = 0;
9081 return;
9082 }
9083
9084 rval = ql_get_xgmac_stats(ha, size, (caddr_t)tmp_buf);
9085
9086 if (rval != QL_SUCCESS) {
9087 /* error */
9088 EL(ha, "failed, get_xgmac_stats =%xh\n", rval);
9089 kmem_free(tmp_buf, size);
9090 cmd->Status = EXT_STATUS_ERR;
9091 cmd->ResponseLen = 0;
9092 return;
9093 }
9094
9095 if (ql_send_buffer_data(tmp_buf, (caddr_t)(uintptr_t)info.pDataBytes,
9096 size, mode) != size) {
9097 EL(ha, "failed, ddi_copyout\n");
9098 cmd->Status = EXT_STATUS_COPY_ERR;
9099 cmd->ResponseLen = 0;
9100 } else {
9101 cmd->ResponseLen = info.TotalByteCount;
9102 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
9103 }
9104 kmem_free(tmp_buf, size);
9105 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
9106 }
9107
9108 /*
9109 * ql_get_fcf_list
9110 * Get FCF list.
9111 *
9112 * Input:
9113 * ha: adapter state pointer.
9114 * cmd: User space CT arguments pointer.
9115 * mode: flags.
9116 */
9117 static void
ql_get_fcf_list(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)9118 ql_get_fcf_list(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
9119 {
9120 uint8_t *tmp_buf;
9121 int rval;
9122 EXT_FCF_LIST fcf_list = {0};
9123 ql_fcf_list_desc_t mb_fcf_list = {0};
9124
9125 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
9126
9127 if (!(CFG_IST(ha, CFG_CTRL_81XX))) {
9128 EL(ha, "invalid request for HBA\n");
9129 cmd->Status = EXT_STATUS_INVALID_REQUEST;
9130 cmd->ResponseLen = 0;
9131 return;
9132 }
9133 /* Get manage info request. */
9134 if (ddi_copyin((caddr_t)(uintptr_t)cmd->RequestAdr,
9135 (caddr_t)&fcf_list, sizeof (EXT_FCF_LIST), mode) != 0) {
9136 EL(ha, "failed, ddi_copyin\n");
9137 cmd->Status = EXT_STATUS_COPY_ERR;
9138 cmd->ResponseLen = 0;
9139 return;
9140 }
9141
9142 if (!(fcf_list.BufSize)) {
9143 /* Return error */
9144 EL(ha, "failed, fcf_list BufSize is=%xh\n",
9145 fcf_list.BufSize);
9146 cmd->Status = EXT_STATUS_INVALID_PARAM;
9147 cmd->ResponseLen = 0;
9148 return;
9149 }
9150 /* Allocate memory for command. */
9151 tmp_buf = kmem_zalloc(fcf_list.BufSize, KM_SLEEP);
9152 if (tmp_buf == NULL) {
9153 EL(ha, "failed, kmem_zalloc\n");
9154 cmd->Status = EXT_STATUS_NO_MEMORY;
9155 cmd->ResponseLen = 0;
9156 return;
9157 }
9158 /* build the descriptor */
9159 if (fcf_list.Options) {
9160 mb_fcf_list.options = FCF_LIST_RETURN_ONE;
9161 } else {
9162 mb_fcf_list.options = FCF_LIST_RETURN_ALL;
9163 }
9164 mb_fcf_list.fcf_index = (uint16_t)fcf_list.FcfIndex;
9165 mb_fcf_list.buffer_size = fcf_list.BufSize;
9166
9167 /* Send command */
9168 rval = ql_get_fcf_list_mbx(ha, &mb_fcf_list, (caddr_t)tmp_buf);
9169 if (rval != QL_SUCCESS) {
9170 /* error */
9171 EL(ha, "failed, get_fcf_list_mbx=%xh\n", rval);
9172 kmem_free(tmp_buf, fcf_list.BufSize);
9173 cmd->Status = EXT_STATUS_ERR;
9174 cmd->ResponseLen = 0;
9175 return;
9176 }
9177
9178 /* Copy the response */
9179 if (ql_send_buffer_data((caddr_t)tmp_buf,
9180 (caddr_t)(uintptr_t)cmd->ResponseAdr,
9181 fcf_list.BufSize, mode) != fcf_list.BufSize) {
9182 EL(ha, "failed, ddi_copyout\n");
9183 cmd->Status = EXT_STATUS_COPY_ERR;
9184 cmd->ResponseLen = 0;
9185 } else {
9186 cmd->ResponseLen = mb_fcf_list.buffer_size;
9187 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
9188 }
9189
9190 kmem_free(tmp_buf, fcf_list.BufSize);
9191 }
9192
9193 /*
9194 * ql_get_resource_counts
9195 * Get Resource counts:
9196 *
9197 * Input:
9198 * ha: adapter state pointer.
9199 * cmd: User space CT arguments pointer.
9200 * mode: flags.
9201 */
9202 static void
ql_get_resource_counts(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)9203 ql_get_resource_counts(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
9204 {
9205 int rval;
9206 ql_mbx_data_t mr;
9207 EXT_RESOURCE_CNTS tmp_rc_cnt = {0};
9208
9209 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
9210
9211 if (!(CFG_IST(ha, CFG_CTRL_242581))) {
9212 EL(ha, "invalid request for HBA\n");
9213 cmd->Status = EXT_STATUS_INVALID_REQUEST;
9214 cmd->ResponseLen = 0;
9215 return;
9216 }
9217
9218 if (cmd->ResponseLen < sizeof (EXT_RESOURCE_CNTS)) {
9219 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
9220 cmd->DetailStatus = sizeof (EXT_RESOURCE_CNTS);
9221 EL(ha, "failed, ResponseLen < EXT_RESOURCE_CNTS, "
9222 "Len=%xh\n", cmd->ResponseLen);
9223 cmd->ResponseLen = 0;
9224 return;
9225 }
9226
9227 rval = ql_get_resource_cnts(ha, &mr);
9228 if (rval != QL_SUCCESS) {
9229 EL(ha, "resource cnt mbx failed\n");
9230 cmd->Status = EXT_STATUS_ERR;
9231 cmd->ResponseLen = 0;
9232 return;
9233 }
9234
9235 tmp_rc_cnt.OrgTgtXchgCtrlCnt = (uint32_t)mr.mb[1];
9236 tmp_rc_cnt.CurTgtXchgCtrlCnt = (uint32_t)mr.mb[2];
9237 tmp_rc_cnt.CurXchgCtrlCnt = (uint32_t)mr.mb[3];
9238 tmp_rc_cnt.OrgXchgCtrlCnt = (uint32_t)mr.mb[6];
9239 tmp_rc_cnt.CurIocbBufCnt = (uint32_t)mr.mb[7];
9240 tmp_rc_cnt.OrgIocbBufCnt = (uint32_t)mr.mb[10];
9241 tmp_rc_cnt.NoOfSupVPs = (uint32_t)mr.mb[11];
9242 tmp_rc_cnt.NoOfSupFCFs = (uint32_t)mr.mb[12];
9243
9244 rval = ddi_copyout((void *)&tmp_rc_cnt,
9245 (void *)(uintptr_t)(cmd->ResponseAdr),
9246 sizeof (EXT_RESOURCE_CNTS), mode);
9247 if (rval != 0) {
9248 cmd->Status = EXT_STATUS_COPY_ERR;
9249 cmd->ResponseLen = 0;
9250 EL(ha, "failed, ddi_copyout\n");
9251 } else {
9252 cmd->ResponseLen = sizeof (EXT_RESOURCE_CNTS);
9253 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
9254 }
9255 }
9256