dea3101e |
1 | /******************************************************************* |
2 | * This file is part of the Emulex Linux Device Driver for * |
3 | * Enterprise Fibre Channel Host Bus Adapters. * |
4 | * Refer to the README file included with this package for * |
5 | * driver version and adapter support. * |
6 | * Copyright (C) 2004 Emulex Corporation. * |
7 | * www.emulex.com * |
8 | * * |
9 | * This program is free software; you can redistribute it and/or * |
10 | * modify it under the terms of the GNU General Public License * |
11 | * as published by the Free Software Foundation; either version 2 * |
12 | * of the License, or (at your option) any later version. * |
13 | * * |
14 | * This program is distributed in the hope that it will be useful, * |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * |
17 | * GNU General Public License for more details, a copy of which * |
18 | * can be found in the file COPYING included with this package. * |
19 | *******************************************************************/ |
20 | |
21 | /* |
22 | * $Id: lpfc_attr.c 1.24 2005/04/13 11:58:55EDT sf_support Exp $ |
23 | */ |
24 | |
25 | #include <linux/ctype.h> |
26 | #include <linux/pci.h> |
27 | #include <linux/interrupt.h> |
28 | |
29 | #include <scsi/scsi_device.h> |
30 | #include <scsi/scsi_host.h> |
31 | #include <scsi/scsi_tcq.h> |
32 | #include <scsi/scsi_transport_fc.h> |
33 | |
34 | #include "lpfc_hw.h" |
35 | #include "lpfc_sli.h" |
36 | #include "lpfc_disc.h" |
37 | #include "lpfc_scsi.h" |
38 | #include "lpfc.h" |
39 | #include "lpfc_logmsg.h" |
40 | #include "lpfc_version.h" |
41 | #include "lpfc_compat.h" |
42 | #include "lpfc_crtn.h" |
43 | |
44 | |
45 | static void |
46 | lpfc_jedec_to_ascii(int incr, char hdw[]) |
47 | { |
48 | int i, j; |
49 | for (i = 0; i < 8; i++) { |
50 | j = (incr & 0xf); |
51 | if (j <= 9) |
52 | hdw[7 - i] = 0x30 + j; |
53 | else |
54 | hdw[7 - i] = 0x61 + j - 10; |
55 | incr = (incr >> 4); |
56 | } |
57 | hdw[8] = 0; |
58 | return; |
59 | } |
60 | |
61 | static ssize_t |
62 | lpfc_drvr_version_show(struct class_device *cdev, char *buf) |
63 | { |
64 | return snprintf(buf, PAGE_SIZE, LPFC_MODULE_DESC "\n"); |
65 | } |
66 | |
67 | static ssize_t |
68 | management_version_show(struct class_device *cdev, char *buf) |
69 | { |
70 | return snprintf(buf, PAGE_SIZE, DFC_API_VERSION "\n"); |
71 | } |
72 | |
73 | static ssize_t |
74 | lpfc_info_show(struct class_device *cdev, char *buf) |
75 | { |
76 | struct Scsi_Host *host = class_to_shost(cdev); |
77 | return snprintf(buf, PAGE_SIZE, "%s\n",lpfc_info(host)); |
78 | } |
79 | |
80 | static ssize_t |
81 | lpfc_serialnum_show(struct class_device *cdev, char *buf) |
82 | { |
83 | struct Scsi_Host *host = class_to_shost(cdev); |
84 | struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0]; |
85 | return snprintf(buf, PAGE_SIZE, "%s\n",phba->SerialNumber); |
86 | } |
87 | |
88 | static ssize_t |
89 | lpfc_modeldesc_show(struct class_device *cdev, char *buf) |
90 | { |
91 | struct Scsi_Host *host = class_to_shost(cdev); |
92 | struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0]; |
93 | return snprintf(buf, PAGE_SIZE, "%s\n",phba->ModelDesc); |
94 | } |
95 | |
96 | static ssize_t |
97 | lpfc_modelname_show(struct class_device *cdev, char *buf) |
98 | { |
99 | struct Scsi_Host *host = class_to_shost(cdev); |
100 | struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0]; |
101 | return snprintf(buf, PAGE_SIZE, "%s\n",phba->ModelName); |
102 | } |
103 | |
104 | static ssize_t |
105 | lpfc_programtype_show(struct class_device *cdev, char *buf) |
106 | { |
107 | struct Scsi_Host *host = class_to_shost(cdev); |
108 | struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0]; |
109 | return snprintf(buf, PAGE_SIZE, "%s\n",phba->ProgramType); |
110 | } |
111 | |
112 | static ssize_t |
113 | lpfc_portnum_show(struct class_device *cdev, char *buf) |
114 | { |
115 | struct Scsi_Host *host = class_to_shost(cdev); |
116 | struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0]; |
117 | return snprintf(buf, PAGE_SIZE, "%s\n",phba->Port); |
118 | } |
119 | |
120 | static ssize_t |
121 | lpfc_fwrev_show(struct class_device *cdev, char *buf) |
122 | { |
123 | struct Scsi_Host *host = class_to_shost(cdev); |
124 | struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0]; |
125 | char fwrev[32]; |
126 | lpfc_decode_firmware_rev(phba, fwrev, 1); |
127 | return snprintf(buf, PAGE_SIZE, "%s\n",fwrev); |
128 | } |
129 | |
130 | static ssize_t |
131 | lpfc_hdw_show(struct class_device *cdev, char *buf) |
132 | { |
133 | char hdw[9]; |
134 | struct Scsi_Host *host = class_to_shost(cdev); |
135 | struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0]; |
136 | lpfc_vpd_t *vp = &phba->vpd; |
137 | lpfc_jedec_to_ascii(vp->rev.biuRev, hdw); |
138 | return snprintf(buf, PAGE_SIZE, "%s\n", hdw); |
139 | } |
140 | static ssize_t |
141 | lpfc_option_rom_version_show(struct class_device *cdev, char *buf) |
142 | { |
143 | struct Scsi_Host *host = class_to_shost(cdev); |
144 | struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0]; |
145 | return snprintf(buf, PAGE_SIZE, "%s\n", phba->OptionROMVersion); |
146 | } |
147 | static ssize_t |
148 | lpfc_state_show(struct class_device *cdev, char *buf) |
149 | { |
150 | struct Scsi_Host *host = class_to_shost(cdev); |
151 | struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0]; |
152 | int len = 0; |
153 | switch (phba->hba_state) { |
154 | case LPFC_INIT_START: |
155 | case LPFC_INIT_MBX_CMDS: |
156 | case LPFC_LINK_DOWN: |
157 | len += snprintf(buf + len, PAGE_SIZE-len, "Link Down\n"); |
158 | break; |
159 | case LPFC_LINK_UP: |
160 | case LPFC_LOCAL_CFG_LINK: |
161 | len += snprintf(buf + len, PAGE_SIZE-len, "Link Up\n"); |
162 | break; |
163 | case LPFC_FLOGI: |
164 | case LPFC_FABRIC_CFG_LINK: |
165 | case LPFC_NS_REG: |
166 | case LPFC_NS_QRY: |
167 | case LPFC_BUILD_DISC_LIST: |
168 | case LPFC_DISC_AUTH: |
169 | case LPFC_CLEAR_LA: |
170 | len += snprintf(buf + len, PAGE_SIZE-len, |
171 | "Link Up - Discovery\n"); |
172 | break; |
173 | case LPFC_HBA_READY: |
174 | len += snprintf(buf + len, PAGE_SIZE-len, |
175 | "Link Up - Ready:\n"); |
176 | if (phba->fc_topology == TOPOLOGY_LOOP) { |
177 | if (phba->fc_flag & FC_PUBLIC_LOOP) |
178 | len += snprintf(buf + len, PAGE_SIZE-len, |
179 | " Public Loop\n"); |
180 | else |
181 | len += snprintf(buf + len, PAGE_SIZE-len, |
182 | " Private Loop\n"); |
183 | } else { |
184 | if (phba->fc_flag & FC_FABRIC) |
185 | len += snprintf(buf + len, PAGE_SIZE-len, |
186 | " Fabric\n"); |
187 | else |
188 | len += snprintf(buf + len, PAGE_SIZE-len, |
189 | " Point-2-Point\n"); |
190 | } |
191 | } |
192 | return len; |
193 | } |
194 | |
195 | static ssize_t |
196 | lpfc_num_discovered_ports_show(struct class_device *cdev, char *buf) |
197 | { |
198 | struct Scsi_Host *host = class_to_shost(cdev); |
199 | struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0]; |
200 | return snprintf(buf, PAGE_SIZE, "%d\n", phba->fc_map_cnt + |
201 | phba->fc_unmap_cnt); |
202 | } |
203 | |
204 | |
205 | static ssize_t |
206 | lpfc_issue_lip (struct class_device *cdev, const char *buf, size_t count) |
207 | { |
208 | struct Scsi_Host *host = class_to_shost(cdev); |
209 | struct lpfc_hba *phba = (struct lpfc_hba *) host->hostdata[0]; |
210 | int val = 0; |
211 | LPFC_MBOXQ_t *pmboxq; |
212 | int mbxstatus = MBXERR_ERROR; |
213 | |
214 | if ((sscanf(buf, "%d", &val) != 1) || |
215 | (val != 1)) |
216 | return -EINVAL; |
217 | |
218 | if ((phba->fc_flag & FC_OFFLINE_MODE) || |
219 | (phba->hba_state != LPFC_HBA_READY)) |
220 | return -EPERM; |
221 | |
222 | pmboxq = mempool_alloc(phba->mbox_mem_pool,GFP_KERNEL); |
223 | |
224 | if (!pmboxq) |
225 | return -ENOMEM; |
226 | |
227 | memset((void *)pmboxq, 0, sizeof (LPFC_MBOXQ_t)); |
228 | lpfc_init_link(phba, pmboxq, phba->cfg_topology, phba->cfg_link_speed); |
229 | mbxstatus = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2); |
230 | |
231 | if (mbxstatus == MBX_TIMEOUT) |
232 | pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl; |
233 | else |
234 | mempool_free( pmboxq, phba->mbox_mem_pool); |
235 | |
236 | if (mbxstatus == MBXERR_ERROR) |
237 | return -EIO; |
238 | |
239 | return strlen(buf); |
240 | } |
241 | |
242 | static ssize_t |
243 | lpfc_nport_evt_cnt_show(struct class_device *cdev, char *buf) |
244 | { |
245 | struct Scsi_Host *host = class_to_shost(cdev); |
246 | struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0]; |
247 | return snprintf(buf, PAGE_SIZE, "%d\n", phba->nport_event_cnt); |
248 | } |
249 | |
250 | static ssize_t |
251 | lpfc_board_online_show(struct class_device *cdev, char *buf) |
252 | { |
253 | struct Scsi_Host *host = class_to_shost(cdev); |
254 | struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0]; |
255 | |
256 | if (!phba) return 0; |
257 | |
258 | if (phba->fc_flag & FC_OFFLINE_MODE) |
259 | return snprintf(buf, PAGE_SIZE, "0\n"); |
260 | else |
261 | return snprintf(buf, PAGE_SIZE, "1\n"); |
262 | } |
263 | |
264 | static ssize_t |
265 | lpfc_board_online_store(struct class_device *cdev, const char *buf, |
266 | size_t count) |
267 | { |
268 | struct Scsi_Host *host = class_to_shost(cdev); |
269 | struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0]; |
270 | struct completion online_compl; |
271 | int val=0, status=0; |
272 | |
273 | if (sscanf(buf, "%d", &val) != 1) |
274 | return 0; |
275 | |
276 | init_completion(&online_compl); |
277 | |
278 | if (val) |
279 | lpfc_workq_post_event(phba, &status, &online_compl, |
280 | LPFC_EVT_ONLINE); |
281 | else |
282 | lpfc_workq_post_event(phba, &status, &online_compl, |
283 | LPFC_EVT_OFFLINE); |
284 | wait_for_completion(&online_compl); |
285 | if (!status) |
286 | return strlen(buf); |
287 | else |
288 | return 0; |
289 | } |
290 | |
291 | |
292 | #define lpfc_param_show(attr) \ |
293 | static ssize_t \ |
294 | lpfc_##attr##_show(struct class_device *cdev, char *buf) \ |
295 | { \ |
296 | struct Scsi_Host *host = class_to_shost(cdev);\ |
297 | struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0];\ |
298 | int val = 0;\ |
299 | if (phba){\ |
300 | val = phba->cfg_##attr;\ |
301 | return snprintf(buf, PAGE_SIZE, "%d\n",\ |
302 | phba->cfg_##attr);\ |
303 | }\ |
304 | return 0;\ |
305 | } |
306 | |
307 | #define lpfc_param_store(attr, minval, maxval) \ |
308 | static ssize_t \ |
309 | lpfc_##attr##_store(struct class_device *cdev, const char *buf, size_t count) \ |
310 | { \ |
311 | struct Scsi_Host *host = class_to_shost(cdev);\ |
312 | struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0];\ |
313 | int val = 0;\ |
314 | if (!isdigit(buf[0]))\ |
315 | return -EINVAL;\ |
316 | if (sscanf(buf, "0x%x", &val) != 1)\ |
317 | if (sscanf(buf, "%d", &val) != 1)\ |
318 | return -EINVAL;\ |
319 | if (phba){\ |
320 | if (val >= minval && val <= maxval) {\ |
321 | phba->cfg_##attr = val;\ |
322 | return strlen(buf);\ |
323 | }\ |
324 | }\ |
325 | return 0;\ |
326 | } |
327 | |
328 | #define LPFC_ATTR_R_NOINIT(name, desc) \ |
329 | extern int lpfc_##name;\ |
330 | module_param(lpfc_##name, int, 0);\ |
331 | MODULE_PARM_DESC(lpfc_##name, desc);\ |
332 | lpfc_param_show(name)\ |
333 | static CLASS_DEVICE_ATTR(lpfc_##name, S_IRUGO , lpfc_##name##_show, NULL) |
334 | |
335 | #define LPFC_ATTR_R(name, defval, minval, maxval, desc) \ |
336 | static int lpfc_##name = defval;\ |
337 | module_param(lpfc_##name, int, 0);\ |
338 | MODULE_PARM_DESC(lpfc_##name, desc);\ |
339 | lpfc_param_show(name)\ |
340 | static CLASS_DEVICE_ATTR(lpfc_##name, S_IRUGO , lpfc_##name##_show, NULL) |
341 | |
342 | #define LPFC_ATTR_RW(name, defval, minval, maxval, desc) \ |
343 | static int lpfc_##name = defval;\ |
344 | module_param(lpfc_##name, int, 0);\ |
345 | MODULE_PARM_DESC(lpfc_##name, desc);\ |
346 | lpfc_param_show(name)\ |
347 | lpfc_param_store(name, minval, maxval)\ |
348 | static CLASS_DEVICE_ATTR(lpfc_##name, S_IRUGO | S_IWUSR,\ |
349 | lpfc_##name##_show, lpfc_##name##_store) |
350 | |
351 | static CLASS_DEVICE_ATTR(info, S_IRUGO, lpfc_info_show, NULL); |
352 | static CLASS_DEVICE_ATTR(serialnum, S_IRUGO, lpfc_serialnum_show, NULL); |
353 | static CLASS_DEVICE_ATTR(modeldesc, S_IRUGO, lpfc_modeldesc_show, NULL); |
354 | static CLASS_DEVICE_ATTR(modelname, S_IRUGO, lpfc_modelname_show, NULL); |
355 | static CLASS_DEVICE_ATTR(programtype, S_IRUGO, lpfc_programtype_show, NULL); |
356 | static CLASS_DEVICE_ATTR(portnum, S_IRUGO, lpfc_portnum_show, NULL); |
357 | static CLASS_DEVICE_ATTR(fwrev, S_IRUGO, lpfc_fwrev_show, NULL); |
358 | static CLASS_DEVICE_ATTR(hdw, S_IRUGO, lpfc_hdw_show, NULL); |
359 | static CLASS_DEVICE_ATTR(state, S_IRUGO, lpfc_state_show, NULL); |
360 | static CLASS_DEVICE_ATTR(option_rom_version, S_IRUGO, |
361 | lpfc_option_rom_version_show, NULL); |
362 | static CLASS_DEVICE_ATTR(num_discovered_ports, S_IRUGO, |
363 | lpfc_num_discovered_ports_show, NULL); |
364 | static CLASS_DEVICE_ATTR(nport_evt_cnt, S_IRUGO, lpfc_nport_evt_cnt_show, NULL); |
365 | static CLASS_DEVICE_ATTR(lpfc_drvr_version, S_IRUGO, lpfc_drvr_version_show, |
366 | NULL); |
367 | static CLASS_DEVICE_ATTR(management_version, S_IRUGO, management_version_show, |
368 | NULL); |
369 | static CLASS_DEVICE_ATTR(issue_lip, S_IWUSR, NULL, lpfc_issue_lip); |
370 | static CLASS_DEVICE_ATTR(board_online, S_IRUGO | S_IWUSR, |
371 | lpfc_board_online_show, lpfc_board_online_store); |
372 | |
373 | |
374 | /* |
375 | # lpfc_log_verbose: Only turn this flag on if you are willing to risk being |
376 | # deluged with LOTS of information. |
377 | # You can set a bit mask to record specific types of verbose messages: |
378 | # |
379 | # LOG_ELS 0x1 ELS events |
380 | # LOG_DISCOVERY 0x2 Link discovery events |
381 | # LOG_MBOX 0x4 Mailbox events |
382 | # LOG_INIT 0x8 Initialization events |
383 | # LOG_LINK_EVENT 0x10 Link events |
384 | # LOG_IP 0x20 IP traffic history |
385 | # LOG_FCP 0x40 FCP traffic history |
386 | # LOG_NODE 0x80 Node table events |
387 | # LOG_MISC 0x400 Miscellaneous events |
388 | # LOG_SLI 0x800 SLI events |
389 | # LOG_CHK_COND 0x1000 FCP Check condition flag |
390 | # LOG_LIBDFC 0x2000 LIBDFC events |
391 | # LOG_ALL_MSG 0xffff LOG all messages |
392 | */ |
393 | LPFC_ATTR_RW(log_verbose, 0x0, 0x0, 0xffff, "Verbose logging bit-mask"); |
394 | |
395 | /* |
396 | # lun_queue_depth: This parameter is used to limit the number of outstanding |
397 | # commands per FCP LUN. Value range is [1,128]. Default value is 30. |
398 | */ |
399 | LPFC_ATTR_R(lun_queue_depth, 30, 1, 128, |
400 | "Max number of FCP commands we can queue to a specific LUN"); |
401 | |
402 | /* |
403 | # Some disk devices have a "select ID" or "select Target" capability. |
404 | # From a protocol standpoint "select ID" usually means select the |
405 | # Fibre channel "ALPA". In the FC-AL Profile there is an "informative |
406 | # annex" which contains a table that maps a "select ID" (a number |
407 | # between 0 and 7F) to an ALPA. By default, for compatibility with |
408 | # older drivers, the lpfc driver scans this table from low ALPA to high |
409 | # ALPA. |
410 | # |
411 | # Turning on the scan-down variable (on = 1, off = 0) will |
412 | # cause the lpfc driver to use an inverted table, effectively |
413 | # scanning ALPAs from high to low. Value range is [0,1]. Default value is 1. |
414 | # |
415 | # (Note: This "select ID" functionality is a LOOP ONLY characteristic |
416 | # and will not work across a fabric. Also this parameter will take |
417 | # effect only in the case when ALPA map is not available.) |
418 | */ |
419 | LPFC_ATTR_R(scan_down, 1, 0, 1, |
420 | "Start scanning for devices from highest ALPA to lowest"); |
421 | |
422 | /* |
423 | # lpfc_nodev_tmo: If set, it will hold all I/O errors on devices that disappear |
424 | # until the timer expires. Value range is [0,255]. Default value is 20. |
425 | # NOTE: this MUST be less then the SCSI Layer command timeout - 1. |
426 | */ |
427 | LPFC_ATTR_RW(nodev_tmo, 30, 0, 255, |
428 | "Seconds driver will hold I/O waiting for a device to come back"); |
429 | |
430 | /* |
431 | # lpfc_topology: link topology for init link |
432 | # 0x0 = attempt loop mode then point-to-point |
433 | # 0x02 = attempt point-to-point mode only |
434 | # 0x04 = attempt loop mode only |
435 | # 0x06 = attempt point-to-point mode then loop |
436 | # Set point-to-point mode if you want to run as an N_Port. |
437 | # Set loop mode if you want to run as an NL_Port. Value range is [0,0x6]. |
438 | # Default value is 0. |
439 | */ |
440 | LPFC_ATTR_R(topology, 0, 0, 6, "Select Fibre Channel topology"); |
441 | |
442 | /* |
443 | # lpfc_link_speed: Link speed selection for initializing the Fibre Channel |
444 | # connection. |
445 | # 0 = auto select (default) |
446 | # 1 = 1 Gigabaud |
447 | # 2 = 2 Gigabaud |
448 | # 4 = 4 Gigabaud |
449 | # Value range is [0,4]. Default value is 0. |
450 | */ |
451 | LPFC_ATTR_R(link_speed, 0, 0, 4, "Select link speed"); |
452 | |
453 | /* |
454 | # lpfc_fcp_class: Determines FC class to use for the FCP protocol. |
455 | # Value range is [2,3]. Default value is 3. |
456 | */ |
457 | LPFC_ATTR_R(fcp_class, 3, 2, 3, |
458 | "Select Fibre Channel class of service for FCP sequences"); |
459 | |
460 | /* |
461 | # lpfc_use_adisc: Use ADISC for FCP rediscovery instead of PLOGI. Value range |
462 | # is [0,1]. Default value is 0. |
463 | */ |
464 | LPFC_ATTR_RW(use_adisc, 0, 0, 1, |
465 | "Use ADISC on rediscovery to authenticate FCP devices"); |
466 | |
467 | /* |
468 | # lpfc_ack0: Use ACK0, instead of ACK1 for class 2 acknowledgement. Value |
469 | # range is [0,1]. Default value is 0. |
470 | */ |
471 | LPFC_ATTR_R(ack0, 0, 0, 1, "Enable ACK0 support"); |
472 | |
473 | /* |
474 | # lpfc_cr_delay & lpfc_cr_count: Default values for I/O colaesing |
475 | # cr_delay (msec) or cr_count outstanding commands. cr_delay can take |
476 | # value [0,63]. cr_count can take value [0,255]. Default value of cr_delay |
477 | # is 0. Default value of cr_count is 1. The cr_count feature is disabled if |
478 | # cr_delay is set to 0. |
479 | */ |
480 | static int lpfc_cr_delay = 0; |
481 | module_param(lpfc_cr_delay, int , 0); |
482 | MODULE_PARM_DESC(lpfc_cr_delay, "A count of milliseconds after which an " |
483 | "interrupt response is generated"); |
484 | |
485 | static int lpfc_cr_count = 1; |
486 | module_param(lpfc_cr_count, int, 0); |
487 | MODULE_PARM_DESC(lpfc_cr_count, "A count of I/O completions after which an " |
488 | "interrupt response is generated"); |
489 | |
490 | /* |
491 | # lpfc_fdmi_on: controls FDMI support. |
492 | # 0 = no FDMI support |
493 | # 1 = support FDMI without attribute of hostname |
494 | # 2 = support FDMI with attribute of hostname |
495 | # Value range [0,2]. Default value is 0. |
496 | */ |
497 | LPFC_ATTR_RW(fdmi_on, 0, 0, 2, "Enable FDMI support"); |
498 | |
499 | /* |
500 | # Specifies the maximum number of ELS cmds we can have outstanding (for |
501 | # discovery). Value range is [1,64]. Default value = 32. |
502 | */ |
503 | static int lpfc_discovery_threads = 32; |
504 | module_param(lpfc_discovery_threads, int, 0); |
505 | MODULE_PARM_DESC(lpfc_discovery_threads, "Maximum number of ELS commands " |
506 | "during discovery"); |
507 | |
508 | /* |
509 | # lpfc_max_luns: maximum number of LUNs per target driver will support |
510 | # Value range is [1,32768]. Default value is 256. |
511 | # NOTE: The SCSI layer will scan each target for this many luns |
512 | */ |
513 | LPFC_ATTR_R(max_luns, 256, 1, 32768, |
514 | "Maximum number of LUNs per target driver will support"); |
515 | |
516 | struct class_device_attribute *lpfc_host_attrs[] = { |
517 | &class_device_attr_info, |
518 | &class_device_attr_serialnum, |
519 | &class_device_attr_modeldesc, |
520 | &class_device_attr_modelname, |
521 | &class_device_attr_programtype, |
522 | &class_device_attr_portnum, |
523 | &class_device_attr_fwrev, |
524 | &class_device_attr_hdw, |
525 | &class_device_attr_option_rom_version, |
526 | &class_device_attr_state, |
527 | &class_device_attr_num_discovered_ports, |
528 | &class_device_attr_lpfc_drvr_version, |
529 | &class_device_attr_lpfc_log_verbose, |
530 | &class_device_attr_lpfc_lun_queue_depth, |
531 | &class_device_attr_lpfc_nodev_tmo, |
532 | &class_device_attr_lpfc_fcp_class, |
533 | &class_device_attr_lpfc_use_adisc, |
534 | &class_device_attr_lpfc_ack0, |
535 | &class_device_attr_lpfc_topology, |
536 | &class_device_attr_lpfc_scan_down, |
537 | &class_device_attr_lpfc_link_speed, |
538 | &class_device_attr_lpfc_fdmi_on, |
539 | &class_device_attr_lpfc_max_luns, |
540 | &class_device_attr_nport_evt_cnt, |
541 | &class_device_attr_management_version, |
542 | &class_device_attr_issue_lip, |
543 | &class_device_attr_board_online, |
544 | NULL, |
545 | }; |
546 | |
547 | static ssize_t |
548 | sysfs_ctlreg_write(struct kobject *kobj, char *buf, loff_t off, size_t count) |
549 | { |
550 | size_t buf_off; |
551 | struct Scsi_Host *host = class_to_shost(container_of(kobj, |
552 | struct class_device, kobj)); |
553 | struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0]; |
554 | |
555 | if ((off + count) > FF_REG_AREA_SIZE) |
556 | return -ERANGE; |
557 | |
558 | if (count == 0) return 0; |
559 | |
560 | if (off % 4 || count % 4 || (unsigned long)buf % 4) |
561 | return -EINVAL; |
562 | |
563 | spin_lock_irq(phba->host->host_lock); |
564 | |
565 | if (!(phba->fc_flag & FC_OFFLINE_MODE)) { |
566 | spin_unlock_irq(phba->host->host_lock); |
567 | return -EPERM; |
568 | } |
569 | |
570 | for (buf_off = 0; buf_off < count; buf_off += sizeof(uint32_t)) |
571 | writel(*((uint32_t *)(buf + buf_off)), |
572 | phba->ctrl_regs_memmap_p + off + buf_off); |
573 | |
574 | spin_unlock_irq(phba->host->host_lock); |
575 | |
576 | return count; |
577 | } |
578 | |
579 | static ssize_t |
580 | sysfs_ctlreg_read(struct kobject *kobj, char *buf, loff_t off, size_t count) |
581 | { |
582 | size_t buf_off; |
583 | uint32_t * tmp_ptr; |
584 | struct Scsi_Host *host = class_to_shost(container_of(kobj, |
585 | struct class_device, kobj)); |
586 | struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0]; |
587 | |
588 | if (off > FF_REG_AREA_SIZE) |
589 | return -ERANGE; |
590 | |
591 | if ((off + count) > FF_REG_AREA_SIZE) |
592 | count = FF_REG_AREA_SIZE - off; |
593 | |
594 | if (count == 0) return 0; |
595 | |
596 | if (off % 4 || count % 4 || (unsigned long)buf % 4) |
597 | return -EINVAL; |
598 | |
599 | spin_lock_irq(phba->host->host_lock); |
600 | |
601 | for (buf_off = 0; buf_off < count; buf_off += sizeof(uint32_t)) { |
602 | tmp_ptr = (uint32_t *)(buf + buf_off); |
603 | *tmp_ptr = readl(phba->ctrl_regs_memmap_p + off + buf_off); |
604 | } |
605 | |
606 | spin_unlock_irq(phba->host->host_lock); |
607 | |
608 | return count; |
609 | } |
610 | |
611 | static struct bin_attribute sysfs_ctlreg_attr = { |
612 | .attr = { |
613 | .name = "ctlreg", |
614 | .mode = S_IRUSR | S_IWUSR, |
615 | .owner = THIS_MODULE, |
616 | }, |
617 | .size = 256, |
618 | .read = sysfs_ctlreg_read, |
619 | .write = sysfs_ctlreg_write, |
620 | }; |
621 | |
622 | |
623 | static void |
624 | sysfs_mbox_idle (struct lpfc_hba * phba) |
625 | { |
626 | phba->sysfs_mbox.state = SMBOX_IDLE; |
627 | phba->sysfs_mbox.offset = 0; |
628 | |
629 | if (phba->sysfs_mbox.mbox) { |
630 | mempool_free(phba->sysfs_mbox.mbox, |
631 | phba->mbox_mem_pool); |
632 | phba->sysfs_mbox.mbox = NULL; |
633 | } |
634 | } |
635 | |
636 | static ssize_t |
637 | sysfs_mbox_write(struct kobject *kobj, char *buf, loff_t off, size_t count) |
638 | { |
639 | struct Scsi_Host * host = |
640 | class_to_shost(container_of(kobj, struct class_device, kobj)); |
641 | struct lpfc_hba * phba = (struct lpfc_hba*)host->hostdata[0]; |
642 | struct lpfcMboxq * mbox = NULL; |
643 | |
644 | if ((count + off) > MAILBOX_CMD_SIZE) |
645 | return -ERANGE; |
646 | |
647 | if (off % 4 || count % 4 || (unsigned long)buf % 4) |
648 | return -EINVAL; |
649 | |
650 | if (count == 0) |
651 | return 0; |
652 | |
653 | if (off == 0) { |
654 | mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); |
655 | if (!mbox) |
656 | return -ENOMEM; |
657 | |
658 | } |
659 | |
660 | spin_lock_irq(host->host_lock); |
661 | |
662 | if (off == 0) { |
663 | if (phba->sysfs_mbox.mbox) |
664 | mempool_free(mbox, phba->mbox_mem_pool); |
665 | else |
666 | phba->sysfs_mbox.mbox = mbox; |
667 | phba->sysfs_mbox.state = SMBOX_WRITING; |
668 | } else { |
669 | if (phba->sysfs_mbox.state != SMBOX_WRITING || |
670 | phba->sysfs_mbox.offset != off || |
671 | phba->sysfs_mbox.mbox == NULL ) { |
672 | sysfs_mbox_idle(phba); |
673 | spin_unlock_irq(host->host_lock); |
674 | return -EINVAL; |
675 | } |
676 | } |
677 | |
678 | memcpy((uint8_t *) & phba->sysfs_mbox.mbox->mb + off, |
679 | buf, count); |
680 | |
681 | phba->sysfs_mbox.offset = off + count; |
682 | |
683 | spin_unlock_irq(host->host_lock); |
684 | |
685 | return count; |
686 | } |
687 | |
688 | static ssize_t |
689 | sysfs_mbox_read(struct kobject *kobj, char *buf, loff_t off, size_t count) |
690 | { |
691 | struct Scsi_Host *host = |
692 | class_to_shost(container_of(kobj, struct class_device, |
693 | kobj)); |
694 | struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0]; |
695 | int rc; |
696 | |
697 | if (off > sizeof(MAILBOX_t)) |
698 | return -ERANGE; |
699 | |
700 | if ((count + off) > sizeof(MAILBOX_t)) |
701 | count = sizeof(MAILBOX_t) - off; |
702 | |
703 | if (off % 4 || count % 4 || (unsigned long)buf % 4) |
704 | return -EINVAL; |
705 | |
706 | if (off && count == 0) |
707 | return 0; |
708 | |
709 | spin_lock_irq(phba->host->host_lock); |
710 | |
711 | if (off == 0 && |
712 | phba->sysfs_mbox.state == SMBOX_WRITING && |
713 | phba->sysfs_mbox.offset >= 2 * sizeof(uint32_t)) { |
714 | |
715 | switch (phba->sysfs_mbox.mbox->mb.mbxCommand) { |
716 | /* Offline only */ |
717 | case MBX_WRITE_NV: |
718 | case MBX_INIT_LINK: |
719 | case MBX_DOWN_LINK: |
720 | case MBX_CONFIG_LINK: |
721 | case MBX_CONFIG_RING: |
722 | case MBX_RESET_RING: |
723 | case MBX_UNREG_LOGIN: |
724 | case MBX_CLEAR_LA: |
725 | case MBX_DUMP_CONTEXT: |
726 | case MBX_RUN_DIAGS: |
727 | case MBX_RESTART: |
728 | case MBX_FLASH_WR_ULA: |
729 | case MBX_SET_MASK: |
730 | case MBX_SET_SLIM: |
731 | case MBX_SET_DEBUG: |
732 | if (!(phba->fc_flag & FC_OFFLINE_MODE)) { |
733 | printk(KERN_WARNING "mbox_read:Command 0x%x " |
734 | "is illegal in on-line state\n", |
735 | phba->sysfs_mbox.mbox->mb.mbxCommand); |
736 | sysfs_mbox_idle(phba); |
737 | spin_unlock_irq(phba->host->host_lock); |
738 | return -EPERM; |
739 | } |
740 | case MBX_LOAD_SM: |
741 | case MBX_READ_NV: |
742 | case MBX_READ_CONFIG: |
743 | case MBX_READ_RCONFIG: |
744 | case MBX_READ_STATUS: |
745 | case MBX_READ_XRI: |
746 | case MBX_READ_REV: |
747 | case MBX_READ_LNK_STAT: |
748 | case MBX_DUMP_MEMORY: |
749 | case MBX_DOWN_LOAD: |
750 | case MBX_UPDATE_CFG: |
751 | case MBX_LOAD_AREA: |
752 | case MBX_LOAD_EXP_ROM: |
753 | break; |
754 | case MBX_READ_SPARM64: |
755 | case MBX_READ_LA: |
756 | case MBX_READ_LA64: |
757 | case MBX_REG_LOGIN: |
758 | case MBX_REG_LOGIN64: |
759 | case MBX_CONFIG_PORT: |
760 | case MBX_RUN_BIU_DIAG: |
761 | printk(KERN_WARNING "mbox_read: Illegal Command 0x%x\n", |
762 | phba->sysfs_mbox.mbox->mb.mbxCommand); |
763 | sysfs_mbox_idle(phba); |
764 | spin_unlock_irq(phba->host->host_lock); |
765 | return -EPERM; |
766 | default: |
767 | printk(KERN_WARNING "mbox_read: Unknown Command 0x%x\n", |
768 | phba->sysfs_mbox.mbox->mb.mbxCommand); |
769 | sysfs_mbox_idle(phba); |
770 | spin_unlock_irq(phba->host->host_lock); |
771 | return -EPERM; |
772 | } |
773 | |
774 | if ((phba->fc_flag & FC_OFFLINE_MODE) || |
775 | (!(phba->sli.sli_flag & LPFC_SLI2_ACTIVE))){ |
776 | |
777 | spin_unlock_irq(phba->host->host_lock); |
778 | rc = lpfc_sli_issue_mbox (phba, |
779 | phba->sysfs_mbox.mbox, |
780 | MBX_POLL); |
781 | spin_lock_irq(phba->host->host_lock); |
782 | |
783 | } else { |
784 | spin_unlock_irq(phba->host->host_lock); |
785 | rc = lpfc_sli_issue_mbox_wait (phba, |
786 | phba->sysfs_mbox.mbox, |
787 | phba->fc_ratov * 2); |
788 | spin_lock_irq(phba->host->host_lock); |
789 | } |
790 | |
791 | if (rc != MBX_SUCCESS) { |
792 | sysfs_mbox_idle(phba); |
793 | spin_unlock_irq(host->host_lock); |
794 | return -ENODEV; |
795 | } |
796 | phba->sysfs_mbox.state = SMBOX_READING; |
797 | } |
798 | else if (phba->sysfs_mbox.offset != off || |
799 | phba->sysfs_mbox.state != SMBOX_READING) { |
800 | printk(KERN_WARNING "mbox_read: Bad State\n"); |
801 | sysfs_mbox_idle(phba); |
802 | spin_unlock_irq(host->host_lock); |
803 | return -EINVAL; |
804 | } |
805 | |
806 | memcpy(buf, (uint8_t *) & phba->sysfs_mbox.mbox->mb + off, count); |
807 | |
808 | phba->sysfs_mbox.offset = off + count; |
809 | |
810 | if (phba->sysfs_mbox.offset == sizeof(MAILBOX_t)) |
811 | sysfs_mbox_idle(phba); |
812 | |
813 | spin_unlock_irq(phba->host->host_lock); |
814 | |
815 | return count; |
816 | } |
817 | |
818 | static struct bin_attribute sysfs_mbox_attr = { |
819 | .attr = { |
820 | .name = "mbox", |
821 | .mode = S_IRUSR | S_IWUSR, |
822 | .owner = THIS_MODULE, |
823 | }, |
824 | .size = sizeof(MAILBOX_t), |
825 | .read = sysfs_mbox_read, |
826 | .write = sysfs_mbox_write, |
827 | }; |
828 | |
829 | int |
830 | lpfc_alloc_sysfs_attr(struct lpfc_hba *phba) |
831 | { |
832 | struct Scsi_Host *host = phba->host; |
833 | int error; |
834 | |
835 | error = sysfs_create_bin_file(&host->shost_classdev.kobj, |
836 | &sysfs_ctlreg_attr); |
837 | if (error) |
838 | goto out; |
839 | |
840 | error = sysfs_create_bin_file(&host->shost_classdev.kobj, |
841 | &sysfs_mbox_attr); |
842 | if (error) |
843 | goto out_remove_ctlreg_attr; |
844 | |
845 | return 0; |
846 | out_remove_ctlreg_attr: |
847 | sysfs_remove_bin_file(&host->shost_classdev.kobj, &sysfs_ctlreg_attr); |
848 | out: |
849 | return error; |
850 | } |
851 | |
852 | void |
853 | lpfc_free_sysfs_attr(struct lpfc_hba *phba) |
854 | { |
855 | struct Scsi_Host *host = phba->host; |
856 | |
857 | sysfs_remove_bin_file(&host->shost_classdev.kobj, &sysfs_mbox_attr); |
858 | sysfs_remove_bin_file(&host->shost_classdev.kobj, &sysfs_ctlreg_attr); |
859 | } |
860 | |
861 | |
862 | /* |
863 | * Dynamic FC Host Attributes Support |
864 | */ |
865 | |
866 | static void |
867 | lpfc_get_host_port_id(struct Scsi_Host *shost) |
868 | { |
869 | struct lpfc_hba *phba = (struct lpfc_hba*)shost->hostdata[0]; |
870 | /* note: fc_myDID already in cpu endianness */ |
871 | fc_host_port_id(shost) = phba->fc_myDID; |
872 | } |
873 | |
874 | static void |
875 | lpfc_get_host_port_type(struct Scsi_Host *shost) |
876 | { |
877 | struct lpfc_hba *phba = (struct lpfc_hba*)shost->hostdata[0]; |
878 | |
879 | spin_lock_irq(shost->host_lock); |
880 | |
881 | if (phba->hba_state == LPFC_HBA_READY) { |
882 | if (phba->fc_topology == TOPOLOGY_LOOP) { |
883 | if (phba->fc_flag & FC_PUBLIC_LOOP) |
884 | fc_host_port_type(shost) = FC_PORTTYPE_NLPORT; |
885 | else |
886 | fc_host_port_type(shost) = FC_PORTTYPE_LPORT; |
887 | } else { |
888 | if (phba->fc_flag & FC_FABRIC) |
889 | fc_host_port_type(shost) = FC_PORTTYPE_NPORT; |
890 | else |
891 | fc_host_port_type(shost) = FC_PORTTYPE_PTP; |
892 | } |
893 | } else |
894 | fc_host_port_type(shost) = FC_PORTTYPE_UNKNOWN; |
895 | |
896 | spin_unlock_irq(shost->host_lock); |
897 | } |
898 | |
899 | static void |
900 | lpfc_get_host_port_state(struct Scsi_Host *shost) |
901 | { |
902 | struct lpfc_hba *phba = (struct lpfc_hba*)shost->hostdata[0]; |
903 | |
904 | spin_lock_irq(shost->host_lock); |
905 | |
906 | if (phba->fc_flag & FC_OFFLINE_MODE) |
907 | fc_host_port_state(shost) = FC_PORTSTATE_OFFLINE; |
908 | else { |
909 | switch (phba->hba_state) { |
910 | case LPFC_INIT_START: |
911 | case LPFC_INIT_MBX_CMDS: |
912 | case LPFC_LINK_DOWN: |
913 | fc_host_port_state(shost) = FC_PORTSTATE_LINKDOWN; |
914 | break; |
915 | case LPFC_LINK_UP: |
916 | case LPFC_LOCAL_CFG_LINK: |
917 | case LPFC_FLOGI: |
918 | case LPFC_FABRIC_CFG_LINK: |
919 | case LPFC_NS_REG: |
920 | case LPFC_NS_QRY: |
921 | case LPFC_BUILD_DISC_LIST: |
922 | case LPFC_DISC_AUTH: |
923 | case LPFC_CLEAR_LA: |
924 | case LPFC_HBA_READY: |
925 | /* Links up, beyond this port_type reports state */ |
926 | fc_host_port_state(shost) = FC_PORTSTATE_ONLINE; |
927 | break; |
928 | case LPFC_HBA_ERROR: |
929 | fc_host_port_state(shost) = FC_PORTSTATE_ERROR; |
930 | break; |
931 | default: |
932 | fc_host_port_state(shost) = FC_PORTSTATE_UNKNOWN; |
933 | break; |
934 | } |
935 | } |
936 | |
937 | spin_unlock_irq(shost->host_lock); |
938 | } |
939 | |
940 | static void |
941 | lpfc_get_host_speed(struct Scsi_Host *shost) |
942 | { |
943 | struct lpfc_hba *phba = (struct lpfc_hba*)shost->hostdata[0]; |
944 | |
945 | spin_lock_irq(shost->host_lock); |
946 | |
947 | if (phba->hba_state == LPFC_HBA_READY) { |
948 | switch(phba->fc_linkspeed) { |
949 | case LA_1GHZ_LINK: |
950 | fc_host_speed(shost) = FC_PORTSPEED_1GBIT; |
951 | break; |
952 | case LA_2GHZ_LINK: |
953 | fc_host_speed(shost) = FC_PORTSPEED_2GBIT; |
954 | break; |
955 | case LA_4GHZ_LINK: |
956 | fc_host_speed(shost) = FC_PORTSPEED_4GBIT; |
957 | break; |
958 | default: |
959 | fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN; |
960 | break; |
961 | } |
962 | } |
963 | |
964 | spin_unlock_irq(shost->host_lock); |
965 | } |
966 | |
967 | static void |
968 | lpfc_get_host_fabric_name (struct Scsi_Host *shost) |
969 | { |
970 | struct lpfc_hba *phba = (struct lpfc_hba*)shost->hostdata[0]; |
971 | u64 nodename; |
972 | |
973 | spin_lock_irq(shost->host_lock); |
974 | |
975 | if ((phba->fc_flag & FC_FABRIC) || |
976 | ((phba->fc_topology == TOPOLOGY_LOOP) && |
977 | (phba->fc_flag & FC_PUBLIC_LOOP))) |
978 | memcpy(&nodename, &phba->fc_fabparam.nodeName, sizeof(u64)); |
979 | else |
980 | /* fabric is local port if there is no F/FL_Port */ |
981 | memcpy(&nodename, &phba->fc_nodename, sizeof(u64)); |
982 | |
983 | spin_unlock_irq(shost->host_lock); |
984 | |
985 | fc_host_fabric_name(shost) = be64_to_cpu(nodename); |
986 | } |
987 | |
988 | |
989 | static struct fc_host_statistics * |
990 | lpfc_get_stats(struct Scsi_Host *shost) |
991 | { |
992 | struct lpfc_hba *phba = (struct lpfc_hba *)shost->hostdata[0]; |
993 | struct lpfc_sli *psli = &phba->sli; |
994 | struct fc_host_statistics *hs = |
995 | (struct fc_host_statistics *)phba->link_stats; |
996 | LPFC_MBOXQ_t *pmboxq; |
997 | MAILBOX_t *pmb; |
998 | int rc=0; |
999 | |
1000 | pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); |
1001 | if (!pmboxq) |
1002 | return NULL; |
1003 | memset(pmboxq, 0, sizeof (LPFC_MBOXQ_t)); |
1004 | |
1005 | pmb = &pmboxq->mb; |
1006 | pmb->mbxCommand = MBX_READ_STATUS; |
1007 | pmb->mbxOwner = OWN_HOST; |
1008 | pmboxq->context1 = NULL; |
1009 | |
1010 | if ((phba->fc_flag & FC_OFFLINE_MODE) || |
1011 | (!(psli->sli_flag & LPFC_SLI2_ACTIVE))){ |
1012 | rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL); |
1013 | } else |
1014 | rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2); |
1015 | |
1016 | if (rc != MBX_SUCCESS) { |
1017 | if (pmboxq) { |
1018 | if (rc == MBX_TIMEOUT) |
1019 | pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl; |
1020 | else |
1021 | mempool_free( pmboxq, phba->mbox_mem_pool); |
1022 | } |
1023 | return NULL; |
1024 | } |
1025 | |
1026 | hs->tx_frames = pmb->un.varRdStatus.xmitFrameCnt; |
1027 | hs->tx_words = (pmb->un.varRdStatus.xmitByteCnt * 256); |
1028 | hs->rx_frames = pmb->un.varRdStatus.rcvFrameCnt; |
1029 | hs->rx_words = (pmb->un.varRdStatus.rcvByteCnt * 256); |
1030 | |
1031 | memset((void *)pmboxq, 0, sizeof (LPFC_MBOXQ_t)); |
1032 | pmb->mbxCommand = MBX_READ_LNK_STAT; |
1033 | pmb->mbxOwner = OWN_HOST; |
1034 | pmboxq->context1 = NULL; |
1035 | |
1036 | if ((phba->fc_flag & FC_OFFLINE_MODE) || |
1037 | (!(psli->sli_flag & LPFC_SLI2_ACTIVE))) { |
1038 | rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL); |
1039 | } else |
1040 | rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2); |
1041 | |
1042 | if (rc != MBX_SUCCESS) { |
1043 | if (pmboxq) { |
1044 | if (rc == MBX_TIMEOUT) |
1045 | pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl; |
1046 | else |
1047 | mempool_free( pmboxq, phba->mbox_mem_pool); |
1048 | } |
1049 | return NULL; |
1050 | } |
1051 | |
1052 | hs->link_failure_count = pmb->un.varRdLnk.linkFailureCnt; |
1053 | hs->loss_of_sync_count = pmb->un.varRdLnk.lossSyncCnt; |
1054 | hs->loss_of_signal_count = pmb->un.varRdLnk.lossSignalCnt; |
1055 | hs->prim_seq_protocol_err_count = pmb->un.varRdLnk.primSeqErrCnt; |
1056 | hs->invalid_tx_word_count = pmb->un.varRdLnk.invalidXmitWord; |
1057 | hs->invalid_crc_count = pmb->un.varRdLnk.crcCnt; |
1058 | hs->error_frames = pmb->un.varRdLnk.crcCnt; |
1059 | |
1060 | if (phba->fc_topology == TOPOLOGY_LOOP) { |
1061 | hs->lip_count = (phba->fc_eventTag >> 1); |
1062 | hs->nos_count = -1; |
1063 | } else { |
1064 | hs->lip_count = -1; |
1065 | hs->nos_count = (phba->fc_eventTag >> 1); |
1066 | } |
1067 | |
1068 | hs->dumped_frames = -1; |
1069 | |
1070 | /* FIX ME */ |
1071 | /*hs->SecondsSinceLastReset = (jiffies - lpfc_loadtime) / HZ;*/ |
1072 | |
1073 | return hs; |
1074 | } |
1075 | |
1076 | |
1077 | /* |
1078 | * The LPFC driver treats linkdown handling as target loss events so there |
1079 | * are no sysfs handlers for link_down_tmo. |
1080 | */ |
1081 | static void |
1082 | lpfc_get_starget_port_id(struct scsi_target *starget) |
1083 | { |
1084 | struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); |
1085 | struct lpfc_hba *phba = (struct lpfc_hba *) shost->hostdata[0]; |
1086 | uint32_t did = -1; |
1087 | struct lpfc_nodelist *ndlp = NULL; |
1088 | |
1089 | spin_lock_irq(shost->host_lock); |
1090 | /* Search the mapped list for this target ID */ |
1091 | list_for_each_entry(ndlp, &phba->fc_nlpmap_list, nlp_listp) { |
1092 | if (starget->id == ndlp->nlp_sid) { |
1093 | did = ndlp->nlp_DID; |
1094 | break; |
1095 | } |
1096 | } |
1097 | spin_unlock_irq(shost->host_lock); |
1098 | |
1099 | fc_starget_port_id(starget) = did; |
1100 | } |
1101 | |
1102 | static void |
1103 | lpfc_get_starget_node_name(struct scsi_target *starget) |
1104 | { |
1105 | struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); |
1106 | struct lpfc_hba *phba = (struct lpfc_hba *) shost->hostdata[0]; |
1107 | uint64_t node_name = 0; |
1108 | struct lpfc_nodelist *ndlp = NULL; |
1109 | |
1110 | spin_lock_irq(shost->host_lock); |
1111 | /* Search the mapped list for this target ID */ |
1112 | list_for_each_entry(ndlp, &phba->fc_nlpmap_list, nlp_listp) { |
1113 | if (starget->id == ndlp->nlp_sid) { |
1114 | memcpy(&node_name, &ndlp->nlp_nodename, |
1115 | sizeof(struct lpfc_name)); |
1116 | break; |
1117 | } |
1118 | } |
1119 | spin_unlock_irq(shost->host_lock); |
1120 | |
1121 | fc_starget_node_name(starget) = be64_to_cpu(node_name); |
1122 | } |
1123 | |
1124 | static void |
1125 | lpfc_get_starget_port_name(struct scsi_target *starget) |
1126 | { |
1127 | struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); |
1128 | struct lpfc_hba *phba = (struct lpfc_hba *) shost->hostdata[0]; |
1129 | uint64_t port_name = 0; |
1130 | struct lpfc_nodelist *ndlp = NULL; |
1131 | |
1132 | spin_lock_irq(shost->host_lock); |
1133 | /* Search the mapped list for this target ID */ |
1134 | list_for_each_entry(ndlp, &phba->fc_nlpmap_list, nlp_listp) { |
1135 | if (starget->id == ndlp->nlp_sid) { |
1136 | memcpy(&port_name, &ndlp->nlp_portname, |
1137 | sizeof(struct lpfc_name)); |
1138 | break; |
1139 | } |
1140 | } |
1141 | spin_unlock_irq(shost->host_lock); |
1142 | |
1143 | fc_starget_port_name(starget) = be64_to_cpu(port_name); |
1144 | } |
1145 | |
1146 | static void |
1147 | lpfc_get_rport_loss_tmo(struct fc_rport *rport) |
1148 | { |
1149 | /* |
1150 | * Return the driver's global value for device loss timeout plus |
1151 | * five seconds to allow the driver's nodev timer to run. |
1152 | */ |
1153 | rport->dev_loss_tmo = lpfc_nodev_tmo + 5; |
1154 | } |
1155 | |
1156 | static void |
1157 | lpfc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout) |
1158 | { |
1159 | /* |
1160 | * The driver doesn't have a per-target timeout setting. Set |
1161 | * this value globally. lpfc_nodev_tmo should be greater then 0. |
1162 | */ |
1163 | if (timeout) |
1164 | lpfc_nodev_tmo = timeout; |
1165 | else |
1166 | lpfc_nodev_tmo = 1; |
1167 | rport->dev_loss_tmo = lpfc_nodev_tmo + 5; |
1168 | } |
1169 | |
1170 | |
1171 | #define lpfc_rport_show_function(field, format_string, sz, cast) \ |
1172 | static ssize_t \ |
1173 | lpfc_show_rport_##field (struct class_device *cdev, char *buf) \ |
1174 | { \ |
1175 | struct fc_rport *rport = transport_class_to_rport(cdev); \ |
1176 | struct lpfc_rport_data *rdata = rport->hostdata; \ |
1177 | return snprintf(buf, sz, format_string, \ |
1178 | (rdata->target) ? cast rdata->target->field : 0); \ |
1179 | } |
1180 | |
1181 | #define lpfc_rport_rd_attr(field, format_string, sz) \ |
1182 | lpfc_rport_show_function(field, format_string, sz, ) \ |
1183 | static FC_RPORT_ATTR(field, S_IRUGO, lpfc_show_rport_##field, NULL) |
1184 | |
1185 | |
1186 | struct fc_function_template lpfc_transport_functions = { |
1187 | /* fixed attributes the driver supports */ |
1188 | .show_host_node_name = 1, |
1189 | .show_host_port_name = 1, |
1190 | .show_host_supported_classes = 1, |
1191 | .show_host_supported_fc4s = 1, |
1192 | .show_host_symbolic_name = 1, |
1193 | .show_host_supported_speeds = 1, |
1194 | .show_host_maxframe_size = 1, |
1195 | |
1196 | /* dynamic attributes the driver supports */ |
1197 | .get_host_port_id = lpfc_get_host_port_id, |
1198 | .show_host_port_id = 1, |
1199 | |
1200 | .get_host_port_type = lpfc_get_host_port_type, |
1201 | .show_host_port_type = 1, |
1202 | |
1203 | .get_host_port_state = lpfc_get_host_port_state, |
1204 | .show_host_port_state = 1, |
1205 | |
1206 | /* active_fc4s is shown but doesn't change (thus no get function) */ |
1207 | .show_host_active_fc4s = 1, |
1208 | |
1209 | .get_host_speed = lpfc_get_host_speed, |
1210 | .show_host_speed = 1, |
1211 | |
1212 | .get_host_fabric_name = lpfc_get_host_fabric_name, |
1213 | .show_host_fabric_name = 1, |
1214 | |
1215 | /* |
1216 | * The LPFC driver treats linkdown handling as target loss events |
1217 | * so there are no sysfs handlers for link_down_tmo. |
1218 | */ |
1219 | |
1220 | .get_fc_host_stats = lpfc_get_stats, |
1221 | |
1222 | /* the LPFC driver doesn't support resetting stats yet */ |
1223 | |
1224 | .dd_fcrport_size = sizeof(struct lpfc_rport_data), |
1225 | .show_rport_maxframe_size = 1, |
1226 | .show_rport_supported_classes = 1, |
1227 | |
1228 | .get_rport_dev_loss_tmo = lpfc_get_rport_loss_tmo, |
1229 | .set_rport_dev_loss_tmo = lpfc_set_rport_loss_tmo, |
1230 | .show_rport_dev_loss_tmo = 1, |
1231 | |
1232 | .get_starget_port_id = lpfc_get_starget_port_id, |
1233 | .show_starget_port_id = 1, |
1234 | |
1235 | .get_starget_node_name = lpfc_get_starget_node_name, |
1236 | .show_starget_node_name = 1, |
1237 | |
1238 | .get_starget_port_name = lpfc_get_starget_port_name, |
1239 | .show_starget_port_name = 1, |
1240 | }; |
1241 | |
1242 | void |
1243 | lpfc_get_cfgparam(struct lpfc_hba *phba) |
1244 | { |
1245 | phba->cfg_log_verbose = lpfc_log_verbose; |
1246 | phba->cfg_cr_delay = lpfc_cr_delay; |
1247 | phba->cfg_cr_count = lpfc_cr_count; |
1248 | phba->cfg_lun_queue_depth = lpfc_lun_queue_depth; |
1249 | phba->cfg_fcp_class = lpfc_fcp_class; |
1250 | phba->cfg_use_adisc = lpfc_use_adisc; |
1251 | phba->cfg_ack0 = lpfc_ack0; |
1252 | phba->cfg_topology = lpfc_topology; |
1253 | phba->cfg_scan_down = lpfc_scan_down; |
1254 | phba->cfg_nodev_tmo = lpfc_nodev_tmo; |
1255 | phba->cfg_link_speed = lpfc_link_speed; |
1256 | phba->cfg_fdmi_on = lpfc_fdmi_on; |
1257 | phba->cfg_discovery_threads = lpfc_discovery_threads; |
1258 | phba->cfg_max_luns = lpfc_max_luns; |
1259 | |
1260 | /* |
1261 | * The total number of segments is the configuration value plus 2 |
1262 | * since the IOCB need a command and response bde. |
1263 | */ |
1264 | phba->cfg_sg_seg_cnt = LPFC_SG_SEG_CNT + 2; |
1265 | |
1266 | /* |
1267 | * Since the sg_tablesize is module parameter, the sg_dma_buf_size |
1268 | * used to create the sg_dma_buf_pool must be dynamically calculated |
1269 | */ |
1270 | phba->cfg_sg_dma_buf_size = sizeof(struct fcp_cmnd) + |
1271 | sizeof(struct fcp_rsp) + |
1272 | (phba->cfg_sg_seg_cnt * sizeof(struct ulp_bde64)); |
1273 | |
1274 | switch (phba->pcidev->device) { |
1275 | case PCI_DEVICE_ID_LP101: |
1276 | case PCI_DEVICE_ID_BSMB: |
1277 | case PCI_DEVICE_ID_ZSMB: |
1278 | phba->cfg_hba_queue_depth = LPFC_LP101_HBA_Q_DEPTH; |
1279 | break; |
1280 | case PCI_DEVICE_ID_RFLY: |
1281 | case PCI_DEVICE_ID_PFLY: |
1282 | case PCI_DEVICE_ID_BMID: |
1283 | case PCI_DEVICE_ID_ZMID: |
1284 | case PCI_DEVICE_ID_TFLY: |
1285 | phba->cfg_hba_queue_depth = LPFC_LC_HBA_Q_DEPTH; |
1286 | break; |
1287 | default: |
1288 | phba->cfg_hba_queue_depth = LPFC_DFT_HBA_Q_DEPTH; |
1289 | } |
1290 | return; |
1291 | } |