diff options
author | <jejb@titanic.il.steeleye.com> | 2005-04-17 17:05:31 -0400 |
---|---|---|
committer | James Bottomley <jejb@titanic> | 2005-04-18 14:50:53 -0400 |
commit | dea3101e0a5c897d2c9351a7444e139db9f40247 (patch) | |
tree | 61de19e98eed08bb760703b362eab2038c34f261 /drivers/scsi/lpfc/lpfc_attr.c | |
parent | 8e8790415e91964096f862a58cacb55d2bc9a817 (diff) |
lpfc: add Emulex FC driver version 8.0.28
From: James.Smart@Emulex.Com
Modified for kernel import and
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers/scsi/lpfc/lpfc_attr.c')
-rw-r--r-- | drivers/scsi/lpfc/lpfc_attr.c | 1291 |
1 files changed, 1291 insertions, 0 deletions
diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c new file mode 100644 index 000000000000..1276bd77b995 --- /dev/null +++ b/drivers/scsi/lpfc/lpfc_attr.c | |||
@@ -0,0 +1,1291 @@ | |||
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 | } | ||