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