diff options
Diffstat (limited to 'drivers/scsi/lpfc/lpfc_attr.c')
-rw-r--r-- | drivers/scsi/lpfc/lpfc_attr.c | 628 |
1 files changed, 573 insertions, 55 deletions
diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index 00656fc92b93..8d5b6ceec9c9 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c | |||
@@ -529,6 +529,27 @@ lpfc_sli4_protocol_show(struct device *dev, struct device_attribute *attr, | |||
529 | } | 529 | } |
530 | 530 | ||
531 | /** | 531 | /** |
532 | * lpfc_oas_supported_show - Return whether or not Optimized Access Storage | ||
533 | * (OAS) is supported. | ||
534 | * @dev: class unused variable. | ||
535 | * @attr: device attribute, not used. | ||
536 | * @buf: on return contains the module description text. | ||
537 | * | ||
538 | * Returns: size of formatted string. | ||
539 | **/ | ||
540 | static ssize_t | ||
541 | lpfc_oas_supported_show(struct device *dev, struct device_attribute *attr, | ||
542 | char *buf) | ||
543 | { | ||
544 | struct Scsi_Host *shost = class_to_shost(dev); | ||
545 | struct lpfc_vport *vport = (struct lpfc_vport *)shost->hostdata; | ||
546 | struct lpfc_hba *phba = vport->phba; | ||
547 | |||
548 | return snprintf(buf, PAGE_SIZE, "%d\n", | ||
549 | phba->sli4_hba.pc_sli4_params.oas_supported); | ||
550 | } | ||
551 | |||
552 | /** | ||
532 | * lpfc_link_state_store - Transition the link_state on an HBA port | 553 | * lpfc_link_state_store - Transition the link_state on an HBA port |
533 | * @dev: class device that is converted into a Scsi_host. | 554 | * @dev: class device that is converted into a Scsi_host. |
534 | * @attr: device attribute, not used. | 555 | * @attr: device attribute, not used. |
@@ -2041,9 +2062,53 @@ static DEVICE_ATTR(lpfc_dss, S_IRUGO, lpfc_dss_show, NULL); | |||
2041 | static DEVICE_ATTR(lpfc_sriov_hw_max_virtfn, S_IRUGO, | 2062 | static DEVICE_ATTR(lpfc_sriov_hw_max_virtfn, S_IRUGO, |
2042 | lpfc_sriov_hw_max_virtfn_show, NULL); | 2063 | lpfc_sriov_hw_max_virtfn_show, NULL); |
2043 | static DEVICE_ATTR(protocol, S_IRUGO, lpfc_sli4_protocol_show, NULL); | 2064 | static DEVICE_ATTR(protocol, S_IRUGO, lpfc_sli4_protocol_show, NULL); |
2065 | static DEVICE_ATTR(lpfc_xlane_supported, S_IRUGO, lpfc_oas_supported_show, | ||
2066 | NULL); | ||
2044 | 2067 | ||
2045 | static char *lpfc_soft_wwn_key = "C99G71SL8032A"; | 2068 | static char *lpfc_soft_wwn_key = "C99G71SL8032A"; |
2069 | #define WWN_SZ 8 | ||
2070 | /** | ||
2071 | * lpfc_wwn_set - Convert string to the 8 byte WWN value. | ||
2072 | * @buf: WWN string. | ||
2073 | * @cnt: Length of string. | ||
2074 | * @wwn: Array to receive converted wwn value. | ||
2075 | * | ||
2076 | * Returns: | ||
2077 | * -EINVAL if the buffer does not contain a valid wwn | ||
2078 | * 0 success | ||
2079 | **/ | ||
2080 | static size_t | ||
2081 | lpfc_wwn_set(const char *buf, size_t cnt, char wwn[]) | ||
2082 | { | ||
2083 | unsigned int i, j; | ||
2084 | |||
2085 | /* Count may include a LF at end of string */ | ||
2086 | if (buf[cnt-1] == '\n') | ||
2087 | cnt--; | ||
2046 | 2088 | ||
2089 | if ((cnt < 16) || (cnt > 18) || ((cnt == 17) && (*buf++ != 'x')) || | ||
2090 | ((cnt == 18) && ((*buf++ != '0') || (*buf++ != 'x')))) | ||
2091 | return -EINVAL; | ||
2092 | |||
2093 | memset(wwn, 0, WWN_SZ); | ||
2094 | |||
2095 | /* Validate and store the new name */ | ||
2096 | for (i = 0, j = 0; i < 16; i++) { | ||
2097 | if ((*buf >= 'a') && (*buf <= 'f')) | ||
2098 | j = ((j << 4) | ((*buf++ - 'a') + 10)); | ||
2099 | else if ((*buf >= 'A') && (*buf <= 'F')) | ||
2100 | j = ((j << 4) | ((*buf++ - 'A') + 10)); | ||
2101 | else if ((*buf >= '0') && (*buf <= '9')) | ||
2102 | j = ((j << 4) | (*buf++ - '0')); | ||
2103 | else | ||
2104 | return -EINVAL; | ||
2105 | if (i % 2) { | ||
2106 | wwn[i/2] = j & 0xff; | ||
2107 | j = 0; | ||
2108 | } | ||
2109 | } | ||
2110 | return 0; | ||
2111 | } | ||
2047 | /** | 2112 | /** |
2048 | * lpfc_soft_wwn_enable_store - Allows setting of the wwn if the key is valid | 2113 | * lpfc_soft_wwn_enable_store - Allows setting of the wwn if the key is valid |
2049 | * @dev: class device that is converted into a Scsi_host. | 2114 | * @dev: class device that is converted into a Scsi_host. |
@@ -2132,9 +2197,9 @@ lpfc_soft_wwpn_store(struct device *dev, struct device_attribute *attr, | |||
2132 | struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; | 2197 | struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; |
2133 | struct lpfc_hba *phba = vport->phba; | 2198 | struct lpfc_hba *phba = vport->phba; |
2134 | struct completion online_compl; | 2199 | struct completion online_compl; |
2135 | int stat1=0, stat2=0; | 2200 | int stat1 = 0, stat2 = 0; |
2136 | unsigned int i, j, cnt=count; | 2201 | unsigned int cnt = count; |
2137 | u8 wwpn[8]; | 2202 | u8 wwpn[WWN_SZ]; |
2138 | int rc; | 2203 | int rc; |
2139 | 2204 | ||
2140 | if (!phba->cfg_enable_hba_reset) | 2205 | if (!phba->cfg_enable_hba_reset) |
@@ -2149,29 +2214,19 @@ lpfc_soft_wwpn_store(struct device *dev, struct device_attribute *attr, | |||
2149 | if (buf[cnt-1] == '\n') | 2214 | if (buf[cnt-1] == '\n') |
2150 | cnt--; | 2215 | cnt--; |
2151 | 2216 | ||
2152 | if (!phba->soft_wwn_enable || (cnt < 16) || (cnt > 18) || | 2217 | if (!phba->soft_wwn_enable) |
2153 | ((cnt == 17) && (*buf++ != 'x')) || | ||
2154 | ((cnt == 18) && ((*buf++ != '0') || (*buf++ != 'x')))) | ||
2155 | return -EINVAL; | 2218 | return -EINVAL; |
2156 | 2219 | ||
2220 | /* lock setting wwpn, wwnn down */ | ||
2157 | phba->soft_wwn_enable = 0; | 2221 | phba->soft_wwn_enable = 0; |
2158 | 2222 | ||
2159 | memset(wwpn, 0, sizeof(wwpn)); | 2223 | rc = lpfc_wwn_set(buf, cnt, wwpn); |
2160 | 2224 | if (!rc) { | |
2161 | /* Validate and store the new name */ | 2225 | /* not able to set wwpn, unlock it */ |
2162 | for (i=0, j=0; i < 16; i++) { | 2226 | phba->soft_wwn_enable = 1; |
2163 | int value; | 2227 | return rc; |
2164 | |||
2165 | value = hex_to_bin(*buf++); | ||
2166 | if (value >= 0) | ||
2167 | j = (j << 4) | value; | ||
2168 | else | ||
2169 | return -EINVAL; | ||
2170 | if (i % 2) { | ||
2171 | wwpn[i/2] = j & 0xff; | ||
2172 | j = 0; | ||
2173 | } | ||
2174 | } | 2228 | } |
2229 | |||
2175 | phba->cfg_soft_wwpn = wwn_to_u64(wwpn); | 2230 | phba->cfg_soft_wwpn = wwn_to_u64(wwpn); |
2176 | fc_host_port_name(shost) = phba->cfg_soft_wwpn; | 2231 | fc_host_port_name(shost) = phba->cfg_soft_wwpn; |
2177 | if (phba->cfg_soft_wwnn) | 2232 | if (phba->cfg_soft_wwnn) |
@@ -2198,7 +2253,7 @@ lpfc_soft_wwpn_store(struct device *dev, struct device_attribute *attr, | |||
2198 | "reinit adapter - %d\n", stat2); | 2253 | "reinit adapter - %d\n", stat2); |
2199 | return (stat1 || stat2) ? -EIO : count; | 2254 | return (stat1 || stat2) ? -EIO : count; |
2200 | } | 2255 | } |
2201 | static DEVICE_ATTR(lpfc_soft_wwpn, S_IRUGO | S_IWUSR,\ | 2256 | static DEVICE_ATTR(lpfc_soft_wwpn, S_IRUGO | S_IWUSR, |
2202 | lpfc_soft_wwpn_show, lpfc_soft_wwpn_store); | 2257 | lpfc_soft_wwpn_show, lpfc_soft_wwpn_store); |
2203 | 2258 | ||
2204 | /** | 2259 | /** |
@@ -2235,39 +2290,25 @@ lpfc_soft_wwnn_store(struct device *dev, struct device_attribute *attr, | |||
2235 | { | 2290 | { |
2236 | struct Scsi_Host *shost = class_to_shost(dev); | 2291 | struct Scsi_Host *shost = class_to_shost(dev); |
2237 | struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; | 2292 | struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; |
2238 | unsigned int i, j, cnt=count; | 2293 | unsigned int cnt = count; |
2239 | u8 wwnn[8]; | 2294 | u8 wwnn[WWN_SZ]; |
2295 | int rc; | ||
2240 | 2296 | ||
2241 | /* count may include a LF at end of string */ | 2297 | /* count may include a LF at end of string */ |
2242 | if (buf[cnt-1] == '\n') | 2298 | if (buf[cnt-1] == '\n') |
2243 | cnt--; | 2299 | cnt--; |
2244 | 2300 | ||
2245 | if (!phba->soft_wwn_enable || (cnt < 16) || (cnt > 18) || | 2301 | if (!phba->soft_wwn_enable) |
2246 | ((cnt == 17) && (*buf++ != 'x')) || | ||
2247 | ((cnt == 18) && ((*buf++ != '0') || (*buf++ != 'x')))) | ||
2248 | return -EINVAL; | 2302 | return -EINVAL; |
2249 | 2303 | ||
2250 | /* | 2304 | rc = lpfc_wwn_set(buf, cnt, wwnn); |
2251 | * Allow wwnn to be set many times, as long as the enable is set. | 2305 | if (!rc) { |
2252 | * However, once the wwpn is set, everything locks. | 2306 | /* Allow wwnn to be set many times, as long as the enable |
2253 | */ | 2307 | * is set. However, once the wwpn is set, everything locks. |
2254 | 2308 | */ | |
2255 | memset(wwnn, 0, sizeof(wwnn)); | 2309 | return rc; |
2256 | |||
2257 | /* Validate and store the new name */ | ||
2258 | for (i=0, j=0; i < 16; i++) { | ||
2259 | int value; | ||
2260 | |||
2261 | value = hex_to_bin(*buf++); | ||
2262 | if (value >= 0) | ||
2263 | j = (j << 4) | value; | ||
2264 | else | ||
2265 | return -EINVAL; | ||
2266 | if (i % 2) { | ||
2267 | wwnn[i/2] = j & 0xff; | ||
2268 | j = 0; | ||
2269 | } | ||
2270 | } | 2310 | } |
2311 | |||
2271 | phba->cfg_soft_wwnn = wwn_to_u64(wwnn); | 2312 | phba->cfg_soft_wwnn = wwn_to_u64(wwnn); |
2272 | 2313 | ||
2273 | dev_printk(KERN_NOTICE, &phba->pcidev->dev, | 2314 | dev_printk(KERN_NOTICE, &phba->pcidev->dev, |
@@ -2276,9 +2317,438 @@ lpfc_soft_wwnn_store(struct device *dev, struct device_attribute *attr, | |||
2276 | 2317 | ||
2277 | return count; | 2318 | return count; |
2278 | } | 2319 | } |
2279 | static DEVICE_ATTR(lpfc_soft_wwnn, S_IRUGO | S_IWUSR,\ | 2320 | static DEVICE_ATTR(lpfc_soft_wwnn, S_IRUGO | S_IWUSR, |
2280 | lpfc_soft_wwnn_show, lpfc_soft_wwnn_store); | 2321 | lpfc_soft_wwnn_show, lpfc_soft_wwnn_store); |
2281 | 2322 | ||
2323 | /** | ||
2324 | * lpfc_oas_tgt_show - Return wwpn of target whose luns maybe enabled for | ||
2325 | * Optimized Access Storage (OAS) operations. | ||
2326 | * @dev: class device that is converted into a Scsi_host. | ||
2327 | * @attr: device attribute, not used. | ||
2328 | * @buf: buffer for passing information. | ||
2329 | * | ||
2330 | * Returns: | ||
2331 | * value of count | ||
2332 | **/ | ||
2333 | static ssize_t | ||
2334 | lpfc_oas_tgt_show(struct device *dev, struct device_attribute *attr, | ||
2335 | char *buf) | ||
2336 | { | ||
2337 | struct Scsi_Host *shost = class_to_shost(dev); | ||
2338 | struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; | ||
2339 | |||
2340 | return snprintf(buf, PAGE_SIZE, "0x%llx\n", | ||
2341 | wwn_to_u64(phba->cfg_oas_tgt_wwpn)); | ||
2342 | } | ||
2343 | |||
2344 | /** | ||
2345 | * lpfc_oas_tgt_store - Store wwpn of target whose luns maybe enabled for | ||
2346 | * Optimized Access Storage (OAS) operations. | ||
2347 | * @dev: class device that is converted into a Scsi_host. | ||
2348 | * @attr: device attribute, not used. | ||
2349 | * @buf: buffer for passing information. | ||
2350 | * @count: Size of the data buffer. | ||
2351 | * | ||
2352 | * Returns: | ||
2353 | * -EINVAL count is invalid, invalid wwpn byte invalid | ||
2354 | * -EPERM oas is not supported by hba | ||
2355 | * value of count on success | ||
2356 | **/ | ||
2357 | static ssize_t | ||
2358 | lpfc_oas_tgt_store(struct device *dev, struct device_attribute *attr, | ||
2359 | const char *buf, size_t count) | ||
2360 | { | ||
2361 | struct Scsi_Host *shost = class_to_shost(dev); | ||
2362 | struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; | ||
2363 | unsigned int cnt = count; | ||
2364 | uint8_t wwpn[WWN_SZ]; | ||
2365 | int rc; | ||
2366 | |||
2367 | if (!phba->cfg_EnableXLane) | ||
2368 | return -EPERM; | ||
2369 | |||
2370 | /* count may include a LF at end of string */ | ||
2371 | if (buf[cnt-1] == '\n') | ||
2372 | cnt--; | ||
2373 | |||
2374 | rc = lpfc_wwn_set(buf, cnt, wwpn); | ||
2375 | if (rc) | ||
2376 | return rc; | ||
2377 | |||
2378 | memcpy(phba->cfg_oas_tgt_wwpn, wwpn, (8 * sizeof(uint8_t))); | ||
2379 | memcpy(phba->sli4_hba.oas_next_tgt_wwpn, wwpn, (8 * sizeof(uint8_t))); | ||
2380 | if (wwn_to_u64(wwpn) == 0) | ||
2381 | phba->cfg_oas_flags |= OAS_FIND_ANY_TARGET; | ||
2382 | else | ||
2383 | phba->cfg_oas_flags &= ~OAS_FIND_ANY_TARGET; | ||
2384 | phba->cfg_oas_flags &= ~OAS_LUN_VALID; | ||
2385 | phba->sli4_hba.oas_next_lun = FIND_FIRST_OAS_LUN; | ||
2386 | return count; | ||
2387 | } | ||
2388 | static DEVICE_ATTR(lpfc_xlane_tgt, S_IRUGO | S_IWUSR, | ||
2389 | lpfc_oas_tgt_show, lpfc_oas_tgt_store); | ||
2390 | |||
2391 | /** | ||
2392 | * lpfc_oas_vpt_show - Return wwpn of vport whose targets maybe enabled | ||
2393 | * for Optimized Access Storage (OAS) operations. | ||
2394 | * @dev: class device that is converted into a Scsi_host. | ||
2395 | * @attr: device attribute, not used. | ||
2396 | * @buf: buffer for passing information. | ||
2397 | * | ||
2398 | * Returns: | ||
2399 | * value of count on success | ||
2400 | **/ | ||
2401 | static ssize_t | ||
2402 | lpfc_oas_vpt_show(struct device *dev, struct device_attribute *attr, | ||
2403 | char *buf) | ||
2404 | { | ||
2405 | struct Scsi_Host *shost = class_to_shost(dev); | ||
2406 | struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; | ||
2407 | |||
2408 | return snprintf(buf, PAGE_SIZE, "0x%llx\n", | ||
2409 | wwn_to_u64(phba->cfg_oas_vpt_wwpn)); | ||
2410 | } | ||
2411 | |||
2412 | /** | ||
2413 | * lpfc_oas_vpt_store - Store wwpn of vport whose targets maybe enabled | ||
2414 | * for Optimized Access Storage (OAS) operations. | ||
2415 | * @dev: class device that is converted into a Scsi_host. | ||
2416 | * @attr: device attribute, not used. | ||
2417 | * @buf: buffer for passing information. | ||
2418 | * @count: Size of the data buffer. | ||
2419 | * | ||
2420 | * Returns: | ||
2421 | * -EINVAL count is invalid, invalid wwpn byte invalid | ||
2422 | * -EPERM oas is not supported by hba | ||
2423 | * value of count on success | ||
2424 | **/ | ||
2425 | static ssize_t | ||
2426 | lpfc_oas_vpt_store(struct device *dev, struct device_attribute *attr, | ||
2427 | const char *buf, size_t count) | ||
2428 | { | ||
2429 | struct Scsi_Host *shost = class_to_shost(dev); | ||
2430 | struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; | ||
2431 | unsigned int cnt = count; | ||
2432 | uint8_t wwpn[WWN_SZ]; | ||
2433 | int rc; | ||
2434 | |||
2435 | if (!phba->cfg_EnableXLane) | ||
2436 | return -EPERM; | ||
2437 | |||
2438 | /* count may include a LF at end of string */ | ||
2439 | if (buf[cnt-1] == '\n') | ||
2440 | cnt--; | ||
2441 | |||
2442 | rc = lpfc_wwn_set(buf, cnt, wwpn); | ||
2443 | if (rc) | ||
2444 | return rc; | ||
2445 | |||
2446 | memcpy(phba->cfg_oas_vpt_wwpn, wwpn, (8 * sizeof(uint8_t))); | ||
2447 | memcpy(phba->sli4_hba.oas_next_vpt_wwpn, wwpn, (8 * sizeof(uint8_t))); | ||
2448 | if (wwn_to_u64(wwpn) == 0) | ||
2449 | phba->cfg_oas_flags |= OAS_FIND_ANY_VPORT; | ||
2450 | else | ||
2451 | phba->cfg_oas_flags &= ~OAS_FIND_ANY_VPORT; | ||
2452 | phba->cfg_oas_flags &= ~OAS_LUN_VALID; | ||
2453 | phba->sli4_hba.oas_next_lun = FIND_FIRST_OAS_LUN; | ||
2454 | return count; | ||
2455 | } | ||
2456 | static DEVICE_ATTR(lpfc_xlane_vpt, S_IRUGO | S_IWUSR, | ||
2457 | lpfc_oas_vpt_show, lpfc_oas_vpt_store); | ||
2458 | |||
2459 | /** | ||
2460 | * lpfc_oas_lun_state_show - Return the current state (enabled or disabled) | ||
2461 | * of whether luns will be enabled or disabled | ||
2462 | * for Optimized Access Storage (OAS) operations. | ||
2463 | * @dev: class device that is converted into a Scsi_host. | ||
2464 | * @attr: device attribute, not used. | ||
2465 | * @buf: buffer for passing information. | ||
2466 | * | ||
2467 | * Returns: | ||
2468 | * size of formatted string. | ||
2469 | **/ | ||
2470 | static ssize_t | ||
2471 | lpfc_oas_lun_state_show(struct device *dev, struct device_attribute *attr, | ||
2472 | char *buf) | ||
2473 | { | ||
2474 | struct Scsi_Host *shost = class_to_shost(dev); | ||
2475 | struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; | ||
2476 | |||
2477 | return snprintf(buf, PAGE_SIZE, "%d\n", phba->cfg_oas_lun_state); | ||
2478 | } | ||
2479 | |||
2480 | /** | ||
2481 | * lpfc_oas_lun_state_store - Store the state (enabled or disabled) | ||
2482 | * of whether luns will be enabled or disabled | ||
2483 | * for Optimized Access Storage (OAS) operations. | ||
2484 | * @dev: class device that is converted into a Scsi_host. | ||
2485 | * @attr: device attribute, not used. | ||
2486 | * @buf: buffer for passing information. | ||
2487 | * @count: Size of the data buffer. | ||
2488 | * | ||
2489 | * Returns: | ||
2490 | * -EINVAL count is invalid, invalid wwpn byte invalid | ||
2491 | * -EPERM oas is not supported by hba | ||
2492 | * value of count on success | ||
2493 | **/ | ||
2494 | static ssize_t | ||
2495 | lpfc_oas_lun_state_store(struct device *dev, struct device_attribute *attr, | ||
2496 | const char *buf, size_t count) | ||
2497 | { | ||
2498 | struct Scsi_Host *shost = class_to_shost(dev); | ||
2499 | struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; | ||
2500 | int val = 0; | ||
2501 | |||
2502 | if (!phba->cfg_EnableXLane) | ||
2503 | return -EPERM; | ||
2504 | |||
2505 | if (!isdigit(buf[0])) | ||
2506 | return -EINVAL; | ||
2507 | |||
2508 | if (sscanf(buf, "%i", &val) != 1) | ||
2509 | return -EINVAL; | ||
2510 | |||
2511 | if ((val != 0) && (val != 1)) | ||
2512 | return -EINVAL; | ||
2513 | |||
2514 | phba->cfg_oas_lun_state = val; | ||
2515 | |||
2516 | return strlen(buf); | ||
2517 | } | ||
2518 | static DEVICE_ATTR(lpfc_xlane_lun_state, S_IRUGO | S_IWUSR, | ||
2519 | lpfc_oas_lun_state_show, lpfc_oas_lun_state_store); | ||
2520 | |||
2521 | /** | ||
2522 | * lpfc_oas_lun_status_show - Return the status of the Optimized Access | ||
2523 | * Storage (OAS) lun returned by the | ||
2524 | * lpfc_oas_lun_show function. | ||
2525 | * @dev: class device that is converted into a Scsi_host. | ||
2526 | * @attr: device attribute, not used. | ||
2527 | * @buf: buffer for passing information. | ||
2528 | * | ||
2529 | * Returns: | ||
2530 | * size of formatted string. | ||
2531 | **/ | ||
2532 | static ssize_t | ||
2533 | lpfc_oas_lun_status_show(struct device *dev, struct device_attribute *attr, | ||
2534 | char *buf) | ||
2535 | { | ||
2536 | struct Scsi_Host *shost = class_to_shost(dev); | ||
2537 | struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; | ||
2538 | |||
2539 | if (!(phba->cfg_oas_flags & OAS_LUN_VALID)) | ||
2540 | return -EFAULT; | ||
2541 | |||
2542 | return snprintf(buf, PAGE_SIZE, "%d\n", phba->cfg_oas_lun_status); | ||
2543 | } | ||
2544 | static DEVICE_ATTR(lpfc_xlane_lun_status, S_IRUGO, | ||
2545 | lpfc_oas_lun_status_show, NULL); | ||
2546 | |||
2547 | |||
2548 | /** | ||
2549 | * lpfc_oas_lun_state_set - enable or disable a lun for Optimized Access Storage | ||
2550 | * (OAS) operations. | ||
2551 | * @phba: lpfc_hba pointer. | ||
2552 | * @ndlp: pointer to fcp target node. | ||
2553 | * @lun: the fc lun for setting oas state. | ||
2554 | * @oas_state: the oas state to be set to the lun. | ||
2555 | * | ||
2556 | * Returns: | ||
2557 | * SUCCESS : 0 | ||
2558 | * -EPERM OAS is not enabled or not supported by this port. | ||
2559 | * | ||
2560 | */ | ||
2561 | static size_t | ||
2562 | lpfc_oas_lun_state_set(struct lpfc_hba *phba, uint8_t vpt_wwpn[], | ||
2563 | uint8_t tgt_wwpn[], uint64_t lun, uint32_t oas_state) | ||
2564 | { | ||
2565 | |||
2566 | int rc = 0; | ||
2567 | |||
2568 | if (!phba->cfg_EnableXLane) | ||
2569 | return -EPERM; | ||
2570 | |||
2571 | if (oas_state) { | ||
2572 | if (!lpfc_enable_oas_lun(phba, (struct lpfc_name *)vpt_wwpn, | ||
2573 | (struct lpfc_name *)tgt_wwpn, lun)) | ||
2574 | rc = -ENOMEM; | ||
2575 | } else { | ||
2576 | lpfc_disable_oas_lun(phba, (struct lpfc_name *)vpt_wwpn, | ||
2577 | (struct lpfc_name *)tgt_wwpn, lun); | ||
2578 | } | ||
2579 | return rc; | ||
2580 | |||
2581 | } | ||
2582 | |||
2583 | /** | ||
2584 | * lpfc_oas_lun_get_next - get the next lun that has been enabled for Optimized | ||
2585 | * Access Storage (OAS) operations. | ||
2586 | * @phba: lpfc_hba pointer. | ||
2587 | * @vpt_wwpn: wwpn of the vport associated with the returned lun | ||
2588 | * @tgt_wwpn: wwpn of the target associated with the returned lun | ||
2589 | * @lun_status: status of the lun returned lun | ||
2590 | * | ||
2591 | * Returns the first or next lun enabled for OAS operations for the vport/target | ||
2592 | * specified. If a lun is found, its vport wwpn, target wwpn and status is | ||
2593 | * returned. If the lun is not found, NOT_OAS_ENABLED_LUN is returned. | ||
2594 | * | ||
2595 | * Return: | ||
2596 | * lun that is OAS enabled for the vport/target | ||
2597 | * NOT_OAS_ENABLED_LUN when no oas enabled lun found. | ||
2598 | */ | ||
2599 | static uint64_t | ||
2600 | lpfc_oas_lun_get_next(struct lpfc_hba *phba, uint8_t vpt_wwpn[], | ||
2601 | uint8_t tgt_wwpn[], uint32_t *lun_status) | ||
2602 | { | ||
2603 | uint64_t found_lun; | ||
2604 | |||
2605 | if (unlikely(!phba) || !vpt_wwpn || !tgt_wwpn) | ||
2606 | return NOT_OAS_ENABLED_LUN; | ||
2607 | if (lpfc_find_next_oas_lun(phba, (struct lpfc_name *) | ||
2608 | phba->sli4_hba.oas_next_vpt_wwpn, | ||
2609 | (struct lpfc_name *) | ||
2610 | phba->sli4_hba.oas_next_tgt_wwpn, | ||
2611 | &phba->sli4_hba.oas_next_lun, | ||
2612 | (struct lpfc_name *)vpt_wwpn, | ||
2613 | (struct lpfc_name *)tgt_wwpn, | ||
2614 | &found_lun, lun_status)) | ||
2615 | return found_lun; | ||
2616 | else | ||
2617 | return NOT_OAS_ENABLED_LUN; | ||
2618 | } | ||
2619 | |||
2620 | /** | ||
2621 | * lpfc_oas_lun_state_change - enable/disable a lun for OAS operations | ||
2622 | * @phba: lpfc_hba pointer. | ||
2623 | * @vpt_wwpn: vport wwpn by reference. | ||
2624 | * @tgt_wwpn: target wwpn by reference. | ||
2625 | * @lun: the fc lun for setting oas state. | ||
2626 | * @oas_state: the oas state to be set to the oas_lun. | ||
2627 | * | ||
2628 | * This routine enables (OAS_LUN_ENABLE) or disables (OAS_LUN_DISABLE) | ||
2629 | * a lun for OAS operations. | ||
2630 | * | ||
2631 | * Return: | ||
2632 | * SUCCESS: 0 | ||
2633 | * -ENOMEM: failed to enable an lun for OAS operations | ||
2634 | * -EPERM: OAS is not enabled | ||
2635 | */ | ||
2636 | static ssize_t | ||
2637 | lpfc_oas_lun_state_change(struct lpfc_hba *phba, uint8_t vpt_wwpn[], | ||
2638 | uint8_t tgt_wwpn[], uint64_t lun, | ||
2639 | uint32_t oas_state) | ||
2640 | { | ||
2641 | |||
2642 | int rc; | ||
2643 | |||
2644 | rc = lpfc_oas_lun_state_set(phba, vpt_wwpn, tgt_wwpn, lun, | ||
2645 | oas_state); | ||
2646 | return rc; | ||
2647 | } | ||
2648 | |||
2649 | /** | ||
2650 | * lpfc_oas_lun_show - Return oas enabled luns from a chosen target | ||
2651 | * @dev: class device that is converted into a Scsi_host. | ||
2652 | * @attr: device attribute, not used. | ||
2653 | * @buf: buffer for passing information. | ||
2654 | * | ||
2655 | * This routine returns a lun enabled for OAS each time the function | ||
2656 | * is called. | ||
2657 | * | ||
2658 | * Returns: | ||
2659 | * SUCCESS: size of formatted string. | ||
2660 | * -EFAULT: target or vport wwpn was not set properly. | ||
2661 | * -EPERM: oas is not enabled. | ||
2662 | **/ | ||
2663 | static ssize_t | ||
2664 | lpfc_oas_lun_show(struct device *dev, struct device_attribute *attr, | ||
2665 | char *buf) | ||
2666 | { | ||
2667 | struct Scsi_Host *shost = class_to_shost(dev); | ||
2668 | struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; | ||
2669 | |||
2670 | uint64_t oas_lun; | ||
2671 | int len = 0; | ||
2672 | |||
2673 | if (!phba->cfg_EnableXLane) | ||
2674 | return -EPERM; | ||
2675 | |||
2676 | if (wwn_to_u64(phba->cfg_oas_vpt_wwpn) == 0) | ||
2677 | if (!(phba->cfg_oas_flags & OAS_FIND_ANY_VPORT)) | ||
2678 | return -EFAULT; | ||
2679 | |||
2680 | if (wwn_to_u64(phba->cfg_oas_tgt_wwpn) == 0) | ||
2681 | if (!(phba->cfg_oas_flags & OAS_FIND_ANY_TARGET)) | ||
2682 | return -EFAULT; | ||
2683 | |||
2684 | oas_lun = lpfc_oas_lun_get_next(phba, phba->cfg_oas_vpt_wwpn, | ||
2685 | phba->cfg_oas_tgt_wwpn, | ||
2686 | &phba->cfg_oas_lun_status); | ||
2687 | if (oas_lun != NOT_OAS_ENABLED_LUN) | ||
2688 | phba->cfg_oas_flags |= OAS_LUN_VALID; | ||
2689 | |||
2690 | len += snprintf(buf + len, PAGE_SIZE-len, "0x%llx", oas_lun); | ||
2691 | |||
2692 | return len; | ||
2693 | } | ||
2694 | |||
2695 | /** | ||
2696 | * lpfc_oas_lun_store - Sets the OAS state for lun | ||
2697 | * @dev: class device that is converted into a Scsi_host. | ||
2698 | * @attr: device attribute, not used. | ||
2699 | * @buf: buffer for passing information. | ||
2700 | * | ||
2701 | * This function sets the OAS state for lun. Before this function is called, | ||
2702 | * the vport wwpn, target wwpn, and oas state need to be set. | ||
2703 | * | ||
2704 | * Returns: | ||
2705 | * SUCCESS: size of formatted string. | ||
2706 | * -EFAULT: target or vport wwpn was not set properly. | ||
2707 | * -EPERM: oas is not enabled. | ||
2708 | * size of formatted string. | ||
2709 | **/ | ||
2710 | static ssize_t | ||
2711 | lpfc_oas_lun_store(struct device *dev, struct device_attribute *attr, | ||
2712 | const char *buf, size_t count) | ||
2713 | { | ||
2714 | struct Scsi_Host *shost = class_to_shost(dev); | ||
2715 | struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; | ||
2716 | uint64_t scsi_lun; | ||
2717 | ssize_t rc; | ||
2718 | |||
2719 | if (!phba->cfg_EnableXLane) | ||
2720 | return -EPERM; | ||
2721 | |||
2722 | if (wwn_to_u64(phba->cfg_oas_vpt_wwpn) == 0) | ||
2723 | return -EFAULT; | ||
2724 | |||
2725 | if (wwn_to_u64(phba->cfg_oas_tgt_wwpn) == 0) | ||
2726 | return -EFAULT; | ||
2727 | |||
2728 | if (!isdigit(buf[0])) | ||
2729 | return -EINVAL; | ||
2730 | |||
2731 | if (sscanf(buf, "0x%llx", &scsi_lun) != 1) | ||
2732 | return -EINVAL; | ||
2733 | |||
2734 | lpfc_printf_log(phba, KERN_INFO, LOG_INIT, | ||
2735 | "3372 Try to set vport 0x%llx target 0x%llx lun:%lld " | ||
2736 | "with oas set to %d\n", | ||
2737 | wwn_to_u64(phba->cfg_oas_vpt_wwpn), | ||
2738 | wwn_to_u64(phba->cfg_oas_tgt_wwpn), scsi_lun, | ||
2739 | phba->cfg_oas_lun_state); | ||
2740 | |||
2741 | rc = lpfc_oas_lun_state_change(phba, phba->cfg_oas_vpt_wwpn, | ||
2742 | phba->cfg_oas_tgt_wwpn, scsi_lun, | ||
2743 | phba->cfg_oas_lun_state); | ||
2744 | |||
2745 | if (rc) | ||
2746 | return rc; | ||
2747 | |||
2748 | return count; | ||
2749 | } | ||
2750 | static DEVICE_ATTR(lpfc_xlane_lun, S_IRUGO | S_IWUSR, | ||
2751 | lpfc_oas_lun_show, lpfc_oas_lun_store); | ||
2282 | 2752 | ||
2283 | static int lpfc_poll = 0; | 2753 | static int lpfc_poll = 0; |
2284 | module_param(lpfc_poll, int, S_IRUGO); | 2754 | module_param(lpfc_poll, int, S_IRUGO); |
@@ -3818,7 +4288,7 @@ lpfc_fcp_cpu_map_show(struct device *dev, struct device_attribute *attr, | |||
3818 | struct lpfc_vport *vport = (struct lpfc_vport *)shost->hostdata; | 4288 | struct lpfc_vport *vport = (struct lpfc_vport *)shost->hostdata; |
3819 | struct lpfc_hba *phba = vport->phba; | 4289 | struct lpfc_hba *phba = vport->phba; |
3820 | struct lpfc_vector_map_info *cpup; | 4290 | struct lpfc_vector_map_info *cpup; |
3821 | int idx, len = 0; | 4291 | int len = 0; |
3822 | 4292 | ||
3823 | if ((phba->sli_rev != LPFC_SLI_REV4) || | 4293 | if ((phba->sli_rev != LPFC_SLI_REV4) || |
3824 | (phba->intr_type != MSIX)) | 4294 | (phba->intr_type != MSIX)) |
@@ -3846,23 +4316,39 @@ lpfc_fcp_cpu_map_show(struct device *dev, struct device_attribute *attr, | |||
3846 | break; | 4316 | break; |
3847 | } | 4317 | } |
3848 | 4318 | ||
3849 | cpup = phba->sli4_hba.cpu_map; | 4319 | while (phba->sli4_hba.curr_disp_cpu < phba->sli4_hba.num_present_cpu) { |
3850 | for (idx = 0; idx < phba->sli4_hba.num_present_cpu; idx++) { | 4320 | cpup = &phba->sli4_hba.cpu_map[phba->sli4_hba.curr_disp_cpu]; |
4321 | |||
4322 | /* margin should fit in this and the truncated message */ | ||
3851 | if (cpup->irq == LPFC_VECTOR_MAP_EMPTY) | 4323 | if (cpup->irq == LPFC_VECTOR_MAP_EMPTY) |
3852 | len += snprintf(buf + len, PAGE_SIZE-len, | 4324 | len += snprintf(buf + len, PAGE_SIZE-len, |
3853 | "CPU %02d io_chan %02d " | 4325 | "CPU %02d io_chan %02d " |
3854 | "physid %d coreid %d\n", | 4326 | "physid %d coreid %d\n", |
3855 | idx, cpup->channel_id, cpup->phys_id, | 4327 | phba->sli4_hba.curr_disp_cpu, |
4328 | cpup->channel_id, cpup->phys_id, | ||
3856 | cpup->core_id); | 4329 | cpup->core_id); |
3857 | else | 4330 | else |
3858 | len += snprintf(buf + len, PAGE_SIZE-len, | 4331 | len += snprintf(buf + len, PAGE_SIZE-len, |
3859 | "CPU %02d io_chan %02d " | 4332 | "CPU %02d io_chan %02d " |
3860 | "physid %d coreid %d IRQ %d\n", | 4333 | "physid %d coreid %d IRQ %d\n", |
3861 | idx, cpup->channel_id, cpup->phys_id, | 4334 | phba->sli4_hba.curr_disp_cpu, |
4335 | cpup->channel_id, cpup->phys_id, | ||
3862 | cpup->core_id, cpup->irq); | 4336 | cpup->core_id, cpup->irq); |
3863 | 4337 | ||
3864 | cpup++; | 4338 | phba->sli4_hba.curr_disp_cpu++; |
4339 | |||
4340 | /* display max number of CPUs keeping some margin */ | ||
4341 | if (phba->sli4_hba.curr_disp_cpu < | ||
4342 | phba->sli4_hba.num_present_cpu && | ||
4343 | (len >= (PAGE_SIZE - 64))) { | ||
4344 | len += snprintf(buf + len, PAGE_SIZE-len, "more...\n"); | ||
4345 | break; | ||
4346 | } | ||
3865 | } | 4347 | } |
4348 | |||
4349 | if (phba->sli4_hba.curr_disp_cpu == phba->sli4_hba.num_present_cpu) | ||
4350 | phba->sli4_hba.curr_disp_cpu = 0; | ||
4351 | |||
3866 | return len; | 4352 | return len; |
3867 | } | 4353 | } |
3868 | 4354 | ||
@@ -4157,6 +4643,21 @@ LPFC_ATTR_R(enable_hba_reset, 1, 0, 1, "Enable HBA resets from the driver."); | |||
4157 | LPFC_ATTR_R(enable_hba_heartbeat, 0, 0, 1, "Enable HBA Heartbeat."); | 4643 | LPFC_ATTR_R(enable_hba_heartbeat, 0, 0, 1, "Enable HBA Heartbeat."); |
4158 | 4644 | ||
4159 | /* | 4645 | /* |
4646 | # lpfc_EnableXLane: Enable Express Lane Feature | ||
4647 | # 0x0 Express Lane Feature disabled | ||
4648 | # 0x1 Express Lane Feature enabled | ||
4649 | # Value range is [0,1]. Default value is 0. | ||
4650 | */ | ||
4651 | LPFC_ATTR_R(EnableXLane, 0, 0, 1, "Enable Express Lane Feature."); | ||
4652 | |||
4653 | /* | ||
4654 | # lpfc_XLanePriority: Define CS_CTL priority for Express Lane Feature | ||
4655 | # 0x0 - 0x7f = CS_CTL field in FC header (high 7 bits) | ||
4656 | # Value range is [0x0,0x7f]. Default value is 0 | ||
4657 | */ | ||
4658 | LPFC_ATTR_R(XLanePriority, 0, 0x0, 0x7f, "CS_CTL for Express Lane Feature."); | ||
4659 | |||
4660 | /* | ||
4160 | # lpfc_enable_bg: Enable BlockGuard (Emulex's Implementation of T10-DIF) | 4661 | # lpfc_enable_bg: Enable BlockGuard (Emulex's Implementation of T10-DIF) |
4161 | # 0 = BlockGuard disabled (default) | 4662 | # 0 = BlockGuard disabled (default) |
4162 | # 1 = BlockGuard enabled | 4663 | # 1 = BlockGuard enabled |
@@ -4317,6 +4818,13 @@ struct device_attribute *lpfc_hba_attrs[] = { | |||
4317 | &dev_attr_lpfc_soft_wwn_enable, | 4818 | &dev_attr_lpfc_soft_wwn_enable, |
4318 | &dev_attr_lpfc_enable_hba_reset, | 4819 | &dev_attr_lpfc_enable_hba_reset, |
4319 | &dev_attr_lpfc_enable_hba_heartbeat, | 4820 | &dev_attr_lpfc_enable_hba_heartbeat, |
4821 | &dev_attr_lpfc_EnableXLane, | ||
4822 | &dev_attr_lpfc_XLanePriority, | ||
4823 | &dev_attr_lpfc_xlane_lun, | ||
4824 | &dev_attr_lpfc_xlane_tgt, | ||
4825 | &dev_attr_lpfc_xlane_vpt, | ||
4826 | &dev_attr_lpfc_xlane_lun_state, | ||
4827 | &dev_attr_lpfc_xlane_lun_status, | ||
4320 | &dev_attr_lpfc_sg_seg_cnt, | 4828 | &dev_attr_lpfc_sg_seg_cnt, |
4321 | &dev_attr_lpfc_max_scsicmpl_time, | 4829 | &dev_attr_lpfc_max_scsicmpl_time, |
4322 | &dev_attr_lpfc_stat_data_ctrl, | 4830 | &dev_attr_lpfc_stat_data_ctrl, |
@@ -4335,6 +4843,7 @@ struct device_attribute *lpfc_hba_attrs[] = { | |||
4335 | &dev_attr_lpfc_dss, | 4843 | &dev_attr_lpfc_dss, |
4336 | &dev_attr_lpfc_sriov_hw_max_virtfn, | 4844 | &dev_attr_lpfc_sriov_hw_max_virtfn, |
4337 | &dev_attr_protocol, | 4845 | &dev_attr_protocol, |
4846 | &dev_attr_lpfc_xlane_supported, | ||
4338 | NULL, | 4847 | NULL, |
4339 | }; | 4848 | }; |
4340 | 4849 | ||
@@ -5296,11 +5805,20 @@ lpfc_get_cfgparam(struct lpfc_hba *phba) | |||
5296 | lpfc_fcp_io_channel_init(phba, lpfc_fcp_io_channel); | 5805 | lpfc_fcp_io_channel_init(phba, lpfc_fcp_io_channel); |
5297 | lpfc_enable_hba_reset_init(phba, lpfc_enable_hba_reset); | 5806 | lpfc_enable_hba_reset_init(phba, lpfc_enable_hba_reset); |
5298 | lpfc_enable_hba_heartbeat_init(phba, lpfc_enable_hba_heartbeat); | 5807 | lpfc_enable_hba_heartbeat_init(phba, lpfc_enable_hba_heartbeat); |
5808 | lpfc_EnableXLane_init(phba, lpfc_EnableXLane); | ||
5809 | if (phba->sli_rev != LPFC_SLI_REV4) | ||
5810 | phba->cfg_EnableXLane = 0; | ||
5811 | lpfc_XLanePriority_init(phba, lpfc_XLanePriority); | ||
5812 | memset(phba->cfg_oas_tgt_wwpn, 0, (8 * sizeof(uint8_t))); | ||
5813 | memset(phba->cfg_oas_vpt_wwpn, 0, (8 * sizeof(uint8_t))); | ||
5814 | phba->cfg_oas_lun_state = 0; | ||
5815 | phba->cfg_oas_lun_status = 0; | ||
5816 | phba->cfg_oas_flags = 0; | ||
5299 | lpfc_enable_bg_init(phba, lpfc_enable_bg); | 5817 | lpfc_enable_bg_init(phba, lpfc_enable_bg); |
5300 | if (phba->sli_rev == LPFC_SLI_REV4) | 5818 | if (phba->sli_rev == LPFC_SLI_REV4) |
5301 | phba->cfg_poll = 0; | 5819 | phba->cfg_poll = 0; |
5302 | else | 5820 | else |
5303 | phba->cfg_poll = lpfc_poll; | 5821 | phba->cfg_poll = lpfc_poll; |
5304 | phba->cfg_soft_wwnn = 0L; | 5822 | phba->cfg_soft_wwnn = 0L; |
5305 | phba->cfg_soft_wwpn = 0L; | 5823 | phba->cfg_soft_wwpn = 0L; |
5306 | lpfc_sg_seg_cnt_init(phba, lpfc_sg_seg_cnt); | 5824 | lpfc_sg_seg_cnt_init(phba, lpfc_sg_seg_cnt); |