| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * ibmvfc.c -- driver for IBM Power Virtual Fibre Channel Adapter |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Written By: Brian King <brking@linux.vnet.ibm.com>, IBM Corporation |
|---|
| 5 | 6 | * |
|---|
| 6 | 7 | * Copyright (C) IBM Corporation, 2008 |
|---|
| 7 | | - * |
|---|
| 8 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 9 | | - * it under the terms of the GNU General Public License as published by |
|---|
| 10 | | - * the Free Software Foundation; either version 2 of the License, or |
|---|
| 11 | | - * (at your option) any later version. |
|---|
| 12 | | - * |
|---|
| 13 | | - * This program is distributed in the hope that it will be useful, |
|---|
| 14 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 15 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 16 | | - * GNU General Public License for more details. |
|---|
| 17 | | - * |
|---|
| 18 | | - * You should have received a copy of the GNU General Public License |
|---|
| 19 | | - * along with this program; if not, write to the Free Software |
|---|
| 20 | | - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|---|
| 21 | | - * |
|---|
| 22 | 8 | */ |
|---|
| 23 | 9 | |
|---|
| 24 | 10 | #include <linux/module.h> |
|---|
| .. | .. |
|---|
| 139 | 125 | { IBMVFC_FC_FAILURE, IBMVFC_VENDOR_SPECIFIC, DID_ERROR, 1, 1, "vendor specific" }, |
|---|
| 140 | 126 | |
|---|
| 141 | 127 | { IBMVFC_FC_SCSI_ERROR, 0, DID_OK, 1, 0, "SCSI error" }, |
|---|
| 128 | + { IBMVFC_FC_SCSI_ERROR, IBMVFC_COMMAND_FAILED, DID_ERROR, 0, 1, "PRLI to device failed." }, |
|---|
| 142 | 129 | }; |
|---|
| 143 | 130 | |
|---|
| 144 | 131 | static void ibmvfc_npiv_login(struct ibmvfc_host *); |
|---|
| .. | .. |
|---|
| 146 | 133 | static void ibmvfc_tgt_send_plogi(struct ibmvfc_target *); |
|---|
| 147 | 134 | static void ibmvfc_tgt_query_target(struct ibmvfc_target *); |
|---|
| 148 | 135 | static void ibmvfc_npiv_logout(struct ibmvfc_host *); |
|---|
| 136 | +static void ibmvfc_tgt_implicit_logout_and_del(struct ibmvfc_target *); |
|---|
| 137 | +static void ibmvfc_tgt_move_login(struct ibmvfc_target *); |
|---|
| 149 | 138 | |
|---|
| 150 | 139 | static const char *unknown_error = "unknown error"; |
|---|
| 151 | 140 | |
|---|
| .. | .. |
|---|
| 426 | 415 | * @tgt: ibmvfc target struct |
|---|
| 427 | 416 | * @action: action to perform |
|---|
| 428 | 417 | * |
|---|
| 418 | + * Returns: |
|---|
| 419 | + * 0 if action changed / non-zero if not changed |
|---|
| 429 | 420 | **/ |
|---|
| 430 | | -static void ibmvfc_set_tgt_action(struct ibmvfc_target *tgt, |
|---|
| 421 | +static int ibmvfc_set_tgt_action(struct ibmvfc_target *tgt, |
|---|
| 431 | 422 | enum ibmvfc_target_action action) |
|---|
| 432 | 423 | { |
|---|
| 424 | + int rc = -EINVAL; |
|---|
| 425 | + |
|---|
| 433 | 426 | switch (tgt->action) { |
|---|
| 434 | | - case IBMVFC_TGT_ACTION_DEL_RPORT: |
|---|
| 435 | | - if (action == IBMVFC_TGT_ACTION_DELETED_RPORT) |
|---|
| 427 | + case IBMVFC_TGT_ACTION_LOGOUT_RPORT: |
|---|
| 428 | + if (action == IBMVFC_TGT_ACTION_LOGOUT_RPORT_WAIT || |
|---|
| 429 | + action == IBMVFC_TGT_ACTION_DEL_RPORT) { |
|---|
| 436 | 430 | tgt->action = action; |
|---|
| 431 | + rc = 0; |
|---|
| 432 | + } |
|---|
| 433 | + break; |
|---|
| 434 | + case IBMVFC_TGT_ACTION_LOGOUT_RPORT_WAIT: |
|---|
| 435 | + if (action == IBMVFC_TGT_ACTION_DEL_RPORT || |
|---|
| 436 | + action == IBMVFC_TGT_ACTION_DEL_AND_LOGOUT_RPORT) { |
|---|
| 437 | + tgt->action = action; |
|---|
| 438 | + rc = 0; |
|---|
| 439 | + } |
|---|
| 440 | + break; |
|---|
| 441 | + case IBMVFC_TGT_ACTION_LOGOUT_DELETED_RPORT: |
|---|
| 442 | + if (action == IBMVFC_TGT_ACTION_LOGOUT_RPORT) { |
|---|
| 443 | + tgt->action = action; |
|---|
| 444 | + rc = 0; |
|---|
| 445 | + } |
|---|
| 446 | + break; |
|---|
| 447 | + case IBMVFC_TGT_ACTION_DEL_AND_LOGOUT_RPORT: |
|---|
| 448 | + if (action == IBMVFC_TGT_ACTION_LOGOUT_DELETED_RPORT) { |
|---|
| 449 | + tgt->action = action; |
|---|
| 450 | + rc = 0; |
|---|
| 451 | + } |
|---|
| 452 | + break; |
|---|
| 453 | + case IBMVFC_TGT_ACTION_DEL_RPORT: |
|---|
| 454 | + if (action == IBMVFC_TGT_ACTION_DELETED_RPORT) { |
|---|
| 455 | + tgt->action = action; |
|---|
| 456 | + rc = 0; |
|---|
| 457 | + } |
|---|
| 458 | + break; |
|---|
| 437 | 459 | case IBMVFC_TGT_ACTION_DELETED_RPORT: |
|---|
| 438 | 460 | break; |
|---|
| 439 | 461 | default: |
|---|
| 440 | | - if (action == IBMVFC_TGT_ACTION_DEL_RPORT) |
|---|
| 441 | | - tgt->add_rport = 0; |
|---|
| 442 | 462 | tgt->action = action; |
|---|
| 463 | + rc = 0; |
|---|
| 443 | 464 | break; |
|---|
| 444 | 465 | } |
|---|
| 466 | + |
|---|
| 467 | + if (action >= IBMVFC_TGT_ACTION_LOGOUT_RPORT) |
|---|
| 468 | + tgt->add_rport = 0; |
|---|
| 469 | + |
|---|
| 470 | + return rc; |
|---|
| 445 | 471 | } |
|---|
| 446 | 472 | |
|---|
| 447 | 473 | /** |
|---|
| .. | .. |
|---|
| 538 | 564 | **/ |
|---|
| 539 | 565 | static void ibmvfc_reinit_host(struct ibmvfc_host *vhost) |
|---|
| 540 | 566 | { |
|---|
| 541 | | - if (vhost->action == IBMVFC_HOST_ACTION_NONE) { |
|---|
| 567 | + if (vhost->action == IBMVFC_HOST_ACTION_NONE && |
|---|
| 568 | + vhost->state == IBMVFC_ACTIVE) { |
|---|
| 542 | 569 | if (!ibmvfc_set_host_state(vhost, IBMVFC_INITIALIZING)) { |
|---|
| 543 | 570 | scsi_block_requests(vhost->host); |
|---|
| 544 | 571 | ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_QUERY); |
|---|
| .. | .. |
|---|
| 547 | 574 | vhost->reinit = 1; |
|---|
| 548 | 575 | |
|---|
| 549 | 576 | wake_up(&vhost->work_wait_q); |
|---|
| 577 | +} |
|---|
| 578 | + |
|---|
| 579 | +/** |
|---|
| 580 | + * ibmvfc_del_tgt - Schedule cleanup and removal of the target |
|---|
| 581 | + * @tgt: ibmvfc target struct |
|---|
| 582 | + * @job_step: job step to perform |
|---|
| 583 | + * |
|---|
| 584 | + **/ |
|---|
| 585 | +static void ibmvfc_del_tgt(struct ibmvfc_target *tgt) |
|---|
| 586 | +{ |
|---|
| 587 | + if (!ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_LOGOUT_RPORT)) |
|---|
| 588 | + tgt->job_step = ibmvfc_tgt_implicit_logout_and_del; |
|---|
| 589 | + wake_up(&tgt->vhost->work_wait_q); |
|---|
| 550 | 590 | } |
|---|
| 551 | 591 | |
|---|
| 552 | 592 | /** |
|---|
| .. | .. |
|---|
| 563 | 603 | ENTER; |
|---|
| 564 | 604 | scsi_block_requests(vhost->host); |
|---|
| 565 | 605 | list_for_each_entry(tgt, &vhost->targets, queue) |
|---|
| 566 | | - ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); |
|---|
| 606 | + ibmvfc_del_tgt(tgt); |
|---|
| 567 | 607 | ibmvfc_set_host_state(vhost, state); |
|---|
| 568 | 608 | ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_TGT_DEL); |
|---|
| 569 | 609 | vhost->events_to_log |= IBMVFC_AE_LINKDOWN; |
|---|
| .. | .. |
|---|
| 595 | 635 | memset(vhost->async_crq.msgs, 0, PAGE_SIZE); |
|---|
| 596 | 636 | vhost->async_crq.cur = 0; |
|---|
| 597 | 637 | |
|---|
| 598 | | - list_for_each_entry(tgt, &vhost->targets, queue) |
|---|
| 599 | | - ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); |
|---|
| 638 | + list_for_each_entry(tgt, &vhost->targets, queue) { |
|---|
| 639 | + if (vhost->client_migrated) |
|---|
| 640 | + tgt->need_login = 1; |
|---|
| 641 | + else |
|---|
| 642 | + ibmvfc_del_tgt(tgt); |
|---|
| 643 | + } |
|---|
| 644 | + |
|---|
| 600 | 645 | scsi_block_requests(vhost->host); |
|---|
| 601 | 646 | ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_INIT); |
|---|
| 602 | 647 | vhost->job_step = ibmvfc_npiv_login; |
|---|
| .. | .. |
|---|
| 1321 | 1366 | } |
|---|
| 1322 | 1367 | |
|---|
| 1323 | 1368 | /** |
|---|
| 1324 | | - * ibmvfc_map_sg_data - Maps dma for a scatterlist and initializes decriptor fields |
|---|
| 1369 | + * ibmvfc_map_sg_data - Maps dma for a scatterlist and initializes descriptor fields |
|---|
| 1325 | 1370 | * @scmd: struct scsi_cmnd with the scatterlist |
|---|
| 1326 | 1371 | * @evt: ibmvfc event struct |
|---|
| 1327 | 1372 | * @vfc_cmd: vfc_cmd that contains the memory descriptor |
|---|
| .. | .. |
|---|
| 1494 | 1539 | if (rsp->flags & FCP_RSP_LEN_VALID) |
|---|
| 1495 | 1540 | rsp_code = rsp->data.info.rsp_code; |
|---|
| 1496 | 1541 | |
|---|
| 1497 | | - scmd_printk(KERN_ERR, cmnd, "Command (%02X) failed: %s (%x:%x) " |
|---|
| 1542 | + scmd_printk(KERN_ERR, cmnd, "Command (%02X) : %s (%x:%x) " |
|---|
| 1498 | 1543 | "flags: %x fcp_rsp: %x, resid=%d, scsi_status: %x\n", |
|---|
| 1499 | | - cmnd->cmnd[0], err, vfc_cmd->status, vfc_cmd->error, |
|---|
| 1544 | + cmnd->cmnd[0], err, be16_to_cpu(vfc_cmd->status), be16_to_cpu(vfc_cmd->error), |
|---|
| 1500 | 1545 | rsp->flags, rsp_code, scsi_get_resid(cmnd), rsp->scsi_status); |
|---|
| 1501 | 1546 | } |
|---|
| 1502 | 1547 | |
|---|
| .. | .. |
|---|
| 1513 | 1558 | |
|---|
| 1514 | 1559 | list_for_each_entry(tgt, &vhost->targets, queue) { |
|---|
| 1515 | 1560 | if (rport == tgt->rport) { |
|---|
| 1516 | | - ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); |
|---|
| 1561 | + ibmvfc_del_tgt(tgt); |
|---|
| 1517 | 1562 | break; |
|---|
| 1518 | 1563 | } |
|---|
| 1519 | 1564 | } |
|---|
| .. | .. |
|---|
| 1843 | 1888 | port_id = (bsg_request->rqst_data.h_els.port_id[0] << 16) | |
|---|
| 1844 | 1889 | (bsg_request->rqst_data.h_els.port_id[1] << 8) | |
|---|
| 1845 | 1890 | bsg_request->rqst_data.h_els.port_id[2]; |
|---|
| 1891 | + fallthrough; |
|---|
| 1846 | 1892 | case FC_BSG_RPT_ELS: |
|---|
| 1847 | 1893 | fc_flags = IBMVFC_FC_ELS; |
|---|
| 1848 | 1894 | break; |
|---|
| .. | .. |
|---|
| 1851 | 1897 | port_id = (bsg_request->rqst_data.h_ct.port_id[0] << 16) | |
|---|
| 1852 | 1898 | (bsg_request->rqst_data.h_ct.port_id[1] << 8) | |
|---|
| 1853 | 1899 | bsg_request->rqst_data.h_ct.port_id[2]; |
|---|
| 1900 | + fallthrough; |
|---|
| 1854 | 1901 | case FC_BSG_RPT_CT: |
|---|
| 1855 | 1902 | fc_flags = IBMVFC_FC_CT_IU; |
|---|
| 1856 | 1903 | break; |
|---|
| .. | .. |
|---|
| 2022 | 2069 | sdev_printk(KERN_ERR, sdev, "%s reset failed: %s (%x:%x) " |
|---|
| 2023 | 2070 | "flags: %x fcp_rsp: %x, scsi_status: %x\n", desc, |
|---|
| 2024 | 2071 | ibmvfc_get_cmd_error(be16_to_cpu(rsp_iu.cmd.status), be16_to_cpu(rsp_iu.cmd.error)), |
|---|
| 2025 | | - rsp_iu.cmd.status, rsp_iu.cmd.error, fc_rsp->flags, rsp_code, |
|---|
| 2072 | + be16_to_cpu(rsp_iu.cmd.status), be16_to_cpu(rsp_iu.cmd.error), fc_rsp->flags, rsp_code, |
|---|
| 2026 | 2073 | fc_rsp->scsi_status); |
|---|
| 2027 | 2074 | rsp_rc = -EIO; |
|---|
| 2028 | 2075 | } else |
|---|
| .. | .. |
|---|
| 2381 | 2428 | sdev_printk(KERN_ERR, sdev, "Abort failed: %s (%x:%x) " |
|---|
| 2382 | 2429 | "flags: %x fcp_rsp: %x, scsi_status: %x\n", |
|---|
| 2383 | 2430 | ibmvfc_get_cmd_error(be16_to_cpu(rsp_iu.cmd.status), be16_to_cpu(rsp_iu.cmd.error)), |
|---|
| 2384 | | - rsp_iu.cmd.status, rsp_iu.cmd.error, fc_rsp->flags, rsp_code, |
|---|
| 2431 | + be16_to_cpu(rsp_iu.cmd.status), be16_to_cpu(rsp_iu.cmd.error), fc_rsp->flags, rsp_code, |
|---|
| 2385 | 2432 | fc_rsp->scsi_status); |
|---|
| 2386 | 2433 | rsp_rc = -EIO; |
|---|
| 2387 | 2434 | } else |
|---|
| .. | .. |
|---|
| 2549 | 2596 | struct ibmvfc_host *vhost = shost_priv(shost); |
|---|
| 2550 | 2597 | struct fc_rport *dev_rport; |
|---|
| 2551 | 2598 | struct scsi_device *sdev; |
|---|
| 2552 | | - unsigned long rc; |
|---|
| 2599 | + struct ibmvfc_target *tgt; |
|---|
| 2600 | + unsigned long rc, flags; |
|---|
| 2601 | + unsigned int found; |
|---|
| 2553 | 2602 | |
|---|
| 2554 | 2603 | ENTER; |
|---|
| 2555 | 2604 | shost_for_each_device(sdev, shost) { |
|---|
| .. | .. |
|---|
| 2563 | 2612 | |
|---|
| 2564 | 2613 | if (rc == FAILED) |
|---|
| 2565 | 2614 | ibmvfc_issue_fc_host_lip(shost); |
|---|
| 2615 | + |
|---|
| 2616 | + spin_lock_irqsave(shost->host_lock, flags); |
|---|
| 2617 | + found = 0; |
|---|
| 2618 | + list_for_each_entry(tgt, &vhost->targets, queue) { |
|---|
| 2619 | + if (tgt->scsi_id == rport->port_id) { |
|---|
| 2620 | + found++; |
|---|
| 2621 | + break; |
|---|
| 2622 | + } |
|---|
| 2623 | + } |
|---|
| 2624 | + |
|---|
| 2625 | + if (found && tgt->action == IBMVFC_TGT_ACTION_LOGOUT_DELETED_RPORT) { |
|---|
| 2626 | + /* |
|---|
| 2627 | + * If we get here, that means we previously attempted to send |
|---|
| 2628 | + * an implicit logout to the target but it failed, most likely |
|---|
| 2629 | + * due to I/O being pending, so we need to send it again |
|---|
| 2630 | + */ |
|---|
| 2631 | + ibmvfc_del_tgt(tgt); |
|---|
| 2632 | + ibmvfc_reinit_host(vhost); |
|---|
| 2633 | + } |
|---|
| 2634 | + |
|---|
| 2635 | + spin_unlock_irqrestore(shost->host_lock, flags); |
|---|
| 2566 | 2636 | LEAVE; |
|---|
| 2567 | 2637 | } |
|---|
| 2568 | 2638 | |
|---|
| .. | .. |
|---|
| 2697 | 2767 | if (tgt->need_login && be64_to_cpu(crq->event) == IBMVFC_AE_ELS_LOGO) |
|---|
| 2698 | 2768 | tgt->logo_rcvd = 1; |
|---|
| 2699 | 2769 | if (!tgt->need_login || be64_to_cpu(crq->event) == IBMVFC_AE_ELS_PLOGI) { |
|---|
| 2700 | | - ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); |
|---|
| 2770 | + ibmvfc_del_tgt(tgt); |
|---|
| 2701 | 2771 | ibmvfc_reinit_host(vhost); |
|---|
| 2702 | 2772 | } |
|---|
| 2703 | 2773 | } |
|---|
| .. | .. |
|---|
| 2755 | 2825 | ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_NONE); |
|---|
| 2756 | 2826 | if (crq->format == IBMVFC_PARTITION_MIGRATED) { |
|---|
| 2757 | 2827 | /* We need to re-setup the interpartition connection */ |
|---|
| 2758 | | - dev_info(vhost->dev, "Re-enabling adapter\n"); |
|---|
| 2828 | + dev_info(vhost->dev, "Partition migrated, Re-enabling adapter\n"); |
|---|
| 2759 | 2829 | vhost->client_migrated = 1; |
|---|
| 2830 | + |
|---|
| 2831 | + scsi_block_requests(vhost->host); |
|---|
| 2760 | 2832 | ibmvfc_purge_requests(vhost, DID_REQUEUE); |
|---|
| 2761 | | - ibmvfc_link_down(vhost, IBMVFC_LINK_DOWN); |
|---|
| 2833 | + ibmvfc_set_host_state(vhost, IBMVFC_LINK_DOWN); |
|---|
| 2762 | 2834 | ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_REENABLE); |
|---|
| 2763 | | - } else { |
|---|
| 2764 | | - dev_err(vhost->dev, "Virtual adapter failed (rc=%d)\n", crq->format); |
|---|
| 2835 | + wake_up(&vhost->work_wait_q); |
|---|
| 2836 | + } else if (crq->format == IBMVFC_PARTNER_FAILED || crq->format == IBMVFC_PARTNER_DEREGISTER) { |
|---|
| 2837 | + dev_err(vhost->dev, "Host partner adapter deregistered or failed (rc=%d)\n", crq->format); |
|---|
| 2765 | 2838 | ibmvfc_purge_requests(vhost, DID_ERROR); |
|---|
| 2766 | 2839 | ibmvfc_link_down(vhost, IBMVFC_LINK_DOWN); |
|---|
| 2767 | 2840 | ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_RESET); |
|---|
| 2841 | + } else { |
|---|
| 2842 | + dev_err(vhost->dev, "Received unknown transport event from partner (rc=%d)\n", crq->format); |
|---|
| 2768 | 2843 | } |
|---|
| 2769 | 2844 | return; |
|---|
| 2770 | 2845 | case IBMVFC_CRQ_CMD_RSP: |
|---|
| .. | .. |
|---|
| 3102 | 3177 | .this_id = -1, |
|---|
| 3103 | 3178 | .sg_tablesize = SG_ALL, |
|---|
| 3104 | 3179 | .max_sectors = IBMVFC_MAX_SECTORS, |
|---|
| 3105 | | - .use_clustering = ENABLE_CLUSTERING, |
|---|
| 3106 | 3180 | .shost_attrs = ibmvfc_attrs, |
|---|
| 3107 | 3181 | .track_queue_depth = 1, |
|---|
| 3108 | 3182 | }; |
|---|
| .. | .. |
|---|
| 3232 | 3306 | static void ibmvfc_init_tgt(struct ibmvfc_target *tgt, |
|---|
| 3233 | 3307 | void (*job_step) (struct ibmvfc_target *)) |
|---|
| 3234 | 3308 | { |
|---|
| 3235 | | - ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_INIT); |
|---|
| 3236 | | - tgt->job_step = job_step; |
|---|
| 3309 | + if (!ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_INIT)) |
|---|
| 3310 | + tgt->job_step = job_step; |
|---|
| 3237 | 3311 | wake_up(&tgt->vhost->work_wait_q); |
|---|
| 3238 | 3312 | } |
|---|
| 3239 | 3313 | |
|---|
| .. | .. |
|---|
| 3249 | 3323 | void (*job_step) (struct ibmvfc_target *)) |
|---|
| 3250 | 3324 | { |
|---|
| 3251 | 3325 | if (++tgt->init_retries > IBMVFC_MAX_TGT_INIT_RETRIES) { |
|---|
| 3252 | | - ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); |
|---|
| 3326 | + ibmvfc_del_tgt(tgt); |
|---|
| 3253 | 3327 | wake_up(&tgt->vhost->work_wait_q); |
|---|
| 3254 | 3328 | return 0; |
|---|
| 3255 | 3329 | } else |
|---|
| .. | .. |
|---|
| 3324 | 3398 | tgt->ids.roles |= FC_PORT_ROLE_FCP_INITIATOR; |
|---|
| 3325 | 3399 | tgt->add_rport = 1; |
|---|
| 3326 | 3400 | } else |
|---|
| 3327 | | - ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); |
|---|
| 3401 | + ibmvfc_del_tgt(tgt); |
|---|
| 3328 | 3402 | } else if (prli_rsp[index].retry) |
|---|
| 3329 | 3403 | ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_send_prli); |
|---|
| 3330 | 3404 | else |
|---|
| 3331 | | - ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); |
|---|
| 3405 | + ibmvfc_del_tgt(tgt); |
|---|
| 3332 | 3406 | } else |
|---|
| 3333 | | - ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); |
|---|
| 3407 | + ibmvfc_del_tgt(tgt); |
|---|
| 3334 | 3408 | break; |
|---|
| 3335 | 3409 | case IBMVFC_MAD_DRIVER_FAILED: |
|---|
| 3336 | 3410 | break; |
|---|
| .. | .. |
|---|
| 3347 | 3421 | else if (ibmvfc_retry_cmd(be16_to_cpu(rsp->status), be16_to_cpu(rsp->error))) |
|---|
| 3348 | 3422 | level += ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_send_prli); |
|---|
| 3349 | 3423 | else |
|---|
| 3350 | | - ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); |
|---|
| 3424 | + ibmvfc_del_tgt(tgt); |
|---|
| 3351 | 3425 | |
|---|
| 3352 | 3426 | tgt_log(tgt, level, "Process Login failed: %s (%x:%x) rc=0x%02X\n", |
|---|
| 3353 | 3427 | ibmvfc_get_cmd_error(be16_to_cpu(rsp->status), be16_to_cpu(rsp->error)), |
|---|
| 3354 | | - rsp->status, rsp->error, status); |
|---|
| 3428 | + be16_to_cpu(rsp->status), be16_to_cpu(rsp->error), status); |
|---|
| 3355 | 3429 | break; |
|---|
| 3356 | 3430 | } |
|---|
| 3357 | 3431 | |
|---|
| .. | .. |
|---|
| 3446 | 3520 | if (ibmvfc_retry_cmd(be16_to_cpu(rsp->status), be16_to_cpu(rsp->error))) |
|---|
| 3447 | 3521 | level += ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_send_plogi); |
|---|
| 3448 | 3522 | else |
|---|
| 3449 | | - ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); |
|---|
| 3523 | + ibmvfc_del_tgt(tgt); |
|---|
| 3450 | 3524 | |
|---|
| 3451 | 3525 | tgt_log(tgt, level, "Port Login failed: %s (%x:%x) %s (%x) %s (%x) rc=0x%02X\n", |
|---|
| 3452 | | - ibmvfc_get_cmd_error(be16_to_cpu(rsp->status), be16_to_cpu(rsp->error)), rsp->status, rsp->error, |
|---|
| 3453 | | - ibmvfc_get_fc_type(be16_to_cpu(rsp->fc_type)), rsp->fc_type, |
|---|
| 3454 | | - ibmvfc_get_ls_explain(be16_to_cpu(rsp->fc_explain)), rsp->fc_explain, status); |
|---|
| 3526 | + ibmvfc_get_cmd_error(be16_to_cpu(rsp->status), be16_to_cpu(rsp->error)), |
|---|
| 3527 | + be16_to_cpu(rsp->status), be16_to_cpu(rsp->error), |
|---|
| 3528 | + ibmvfc_get_fc_type(be16_to_cpu(rsp->fc_type)), be16_to_cpu(rsp->fc_type), |
|---|
| 3529 | + ibmvfc_get_ls_explain(be16_to_cpu(rsp->fc_explain)), be16_to_cpu(rsp->fc_explain), status); |
|---|
| 3455 | 3530 | break; |
|---|
| 3456 | 3531 | } |
|---|
| 3457 | 3532 | |
|---|
| .. | .. |
|---|
| 3526 | 3601 | break; |
|---|
| 3527 | 3602 | } |
|---|
| 3528 | 3603 | |
|---|
| 3529 | | - if (vhost->action == IBMVFC_HOST_ACTION_TGT_INIT) |
|---|
| 3530 | | - ibmvfc_init_tgt(tgt, ibmvfc_tgt_send_plogi); |
|---|
| 3531 | | - else if (vhost->action == IBMVFC_HOST_ACTION_QUERY_TGTS && |
|---|
| 3532 | | - tgt->scsi_id != tgt->new_scsi_id) |
|---|
| 3533 | | - ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); |
|---|
| 3604 | + ibmvfc_init_tgt(tgt, ibmvfc_tgt_send_plogi); |
|---|
| 3534 | 3605 | kref_put(&tgt->kref, ibmvfc_release_tgt); |
|---|
| 3535 | 3606 | wake_up(&vhost->work_wait_q); |
|---|
| 3607 | +} |
|---|
| 3608 | + |
|---|
| 3609 | +/** |
|---|
| 3610 | + * __ibmvfc_tgt_get_implicit_logout_evt - Allocate and init an event for implicit logout |
|---|
| 3611 | + * @tgt: ibmvfc target struct |
|---|
| 3612 | + * |
|---|
| 3613 | + * Returns: |
|---|
| 3614 | + * Allocated and initialized ibmvfc_event struct |
|---|
| 3615 | + **/ |
|---|
| 3616 | +static struct ibmvfc_event *__ibmvfc_tgt_get_implicit_logout_evt(struct ibmvfc_target *tgt, |
|---|
| 3617 | + void (*done) (struct ibmvfc_event *)) |
|---|
| 3618 | +{ |
|---|
| 3619 | + struct ibmvfc_implicit_logout *mad; |
|---|
| 3620 | + struct ibmvfc_host *vhost = tgt->vhost; |
|---|
| 3621 | + struct ibmvfc_event *evt; |
|---|
| 3622 | + |
|---|
| 3623 | + kref_get(&tgt->kref); |
|---|
| 3624 | + evt = ibmvfc_get_event(vhost); |
|---|
| 3625 | + ibmvfc_init_event(evt, done, IBMVFC_MAD_FORMAT); |
|---|
| 3626 | + evt->tgt = tgt; |
|---|
| 3627 | + mad = &evt->iu.implicit_logout; |
|---|
| 3628 | + memset(mad, 0, sizeof(*mad)); |
|---|
| 3629 | + mad->common.version = cpu_to_be32(1); |
|---|
| 3630 | + mad->common.opcode = cpu_to_be32(IBMVFC_IMPLICIT_LOGOUT); |
|---|
| 3631 | + mad->common.length = cpu_to_be16(sizeof(*mad)); |
|---|
| 3632 | + mad->old_scsi_id = cpu_to_be64(tgt->scsi_id); |
|---|
| 3633 | + return evt; |
|---|
| 3536 | 3634 | } |
|---|
| 3537 | 3635 | |
|---|
| 3538 | 3636 | /** |
|---|
| .. | .. |
|---|
| 3542 | 3640 | **/ |
|---|
| 3543 | 3641 | static void ibmvfc_tgt_implicit_logout(struct ibmvfc_target *tgt) |
|---|
| 3544 | 3642 | { |
|---|
| 3545 | | - struct ibmvfc_implicit_logout *mad; |
|---|
| 3546 | 3643 | struct ibmvfc_host *vhost = tgt->vhost; |
|---|
| 3547 | 3644 | struct ibmvfc_event *evt; |
|---|
| 3548 | 3645 | |
|---|
| 3549 | 3646 | if (vhost->discovery_threads >= disc_threads) |
|---|
| 3550 | 3647 | return; |
|---|
| 3551 | 3648 | |
|---|
| 3552 | | - kref_get(&tgt->kref); |
|---|
| 3553 | | - evt = ibmvfc_get_event(vhost); |
|---|
| 3554 | 3649 | vhost->discovery_threads++; |
|---|
| 3555 | | - ibmvfc_init_event(evt, ibmvfc_tgt_implicit_logout_done, IBMVFC_MAD_FORMAT); |
|---|
| 3556 | | - evt->tgt = tgt; |
|---|
| 3557 | | - mad = &evt->iu.implicit_logout; |
|---|
| 3558 | | - memset(mad, 0, sizeof(*mad)); |
|---|
| 3559 | | - mad->common.version = cpu_to_be32(1); |
|---|
| 3560 | | - mad->common.opcode = cpu_to_be32(IBMVFC_IMPLICIT_LOGOUT); |
|---|
| 3561 | | - mad->common.length = cpu_to_be16(sizeof(*mad)); |
|---|
| 3562 | | - mad->old_scsi_id = cpu_to_be64(tgt->scsi_id); |
|---|
| 3650 | + evt = __ibmvfc_tgt_get_implicit_logout_evt(tgt, |
|---|
| 3651 | + ibmvfc_tgt_implicit_logout_done); |
|---|
| 3563 | 3652 | |
|---|
| 3564 | 3653 | ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_INIT_WAIT); |
|---|
| 3565 | 3654 | if (ibmvfc_send_event(evt, vhost, default_timeout)) { |
|---|
| .. | .. |
|---|
| 3568 | 3657 | kref_put(&tgt->kref, ibmvfc_release_tgt); |
|---|
| 3569 | 3658 | } else |
|---|
| 3570 | 3659 | tgt_dbg(tgt, "Sent Implicit Logout\n"); |
|---|
| 3660 | +} |
|---|
| 3661 | + |
|---|
| 3662 | +/** |
|---|
| 3663 | + * ibmvfc_tgt_implicit_logout_and_del_done - Completion handler for Implicit Logout MAD |
|---|
| 3664 | + * @evt: ibmvfc event struct |
|---|
| 3665 | + * |
|---|
| 3666 | + **/ |
|---|
| 3667 | +static void ibmvfc_tgt_implicit_logout_and_del_done(struct ibmvfc_event *evt) |
|---|
| 3668 | +{ |
|---|
| 3669 | + struct ibmvfc_target *tgt = evt->tgt; |
|---|
| 3670 | + struct ibmvfc_host *vhost = evt->vhost; |
|---|
| 3671 | + struct ibmvfc_passthru_mad *mad = &evt->xfer_iu->passthru; |
|---|
| 3672 | + u32 status = be16_to_cpu(mad->common.status); |
|---|
| 3673 | + |
|---|
| 3674 | + vhost->discovery_threads--; |
|---|
| 3675 | + ibmvfc_free_event(evt); |
|---|
| 3676 | + |
|---|
| 3677 | + /* |
|---|
| 3678 | + * If our state is IBMVFC_HOST_OFFLINE, we could be unloading the |
|---|
| 3679 | + * driver in which case we need to free up all the targets. If we are |
|---|
| 3680 | + * not unloading, we will still go through a hard reset to get out of |
|---|
| 3681 | + * offline state, so there is no need to track the old targets in that |
|---|
| 3682 | + * case. |
|---|
| 3683 | + */ |
|---|
| 3684 | + if (status == IBMVFC_MAD_SUCCESS || vhost->state == IBMVFC_HOST_OFFLINE) |
|---|
| 3685 | + ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); |
|---|
| 3686 | + else |
|---|
| 3687 | + ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_AND_LOGOUT_RPORT); |
|---|
| 3688 | + |
|---|
| 3689 | + tgt_dbg(tgt, "Implicit Logout %s\n", (status == IBMVFC_MAD_SUCCESS) ? "succeeded" : "failed"); |
|---|
| 3690 | + kref_put(&tgt->kref, ibmvfc_release_tgt); |
|---|
| 3691 | + wake_up(&vhost->work_wait_q); |
|---|
| 3692 | +} |
|---|
| 3693 | + |
|---|
| 3694 | +/** |
|---|
| 3695 | + * ibmvfc_tgt_implicit_logout_and_del - Initiate an Implicit Logout for specified target |
|---|
| 3696 | + * @tgt: ibmvfc target struct |
|---|
| 3697 | + * |
|---|
| 3698 | + **/ |
|---|
| 3699 | +static void ibmvfc_tgt_implicit_logout_and_del(struct ibmvfc_target *tgt) |
|---|
| 3700 | +{ |
|---|
| 3701 | + struct ibmvfc_host *vhost = tgt->vhost; |
|---|
| 3702 | + struct ibmvfc_event *evt; |
|---|
| 3703 | + |
|---|
| 3704 | + if (!vhost->logged_in) { |
|---|
| 3705 | + ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); |
|---|
| 3706 | + return; |
|---|
| 3707 | + } |
|---|
| 3708 | + |
|---|
| 3709 | + if (vhost->discovery_threads >= disc_threads) |
|---|
| 3710 | + return; |
|---|
| 3711 | + |
|---|
| 3712 | + vhost->discovery_threads++; |
|---|
| 3713 | + evt = __ibmvfc_tgt_get_implicit_logout_evt(tgt, |
|---|
| 3714 | + ibmvfc_tgt_implicit_logout_and_del_done); |
|---|
| 3715 | + |
|---|
| 3716 | + ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_LOGOUT_RPORT_WAIT); |
|---|
| 3717 | + if (ibmvfc_send_event(evt, vhost, default_timeout)) { |
|---|
| 3718 | + vhost->discovery_threads--; |
|---|
| 3719 | + ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); |
|---|
| 3720 | + kref_put(&tgt->kref, ibmvfc_release_tgt); |
|---|
| 3721 | + } else |
|---|
| 3722 | + tgt_dbg(tgt, "Sent Implicit Logout\n"); |
|---|
| 3723 | +} |
|---|
| 3724 | + |
|---|
| 3725 | +/** |
|---|
| 3726 | + * ibmvfc_tgt_move_login_done - Completion handler for Move Login |
|---|
| 3727 | + * @evt: ibmvfc event struct |
|---|
| 3728 | + * |
|---|
| 3729 | + **/ |
|---|
| 3730 | +static void ibmvfc_tgt_move_login_done(struct ibmvfc_event *evt) |
|---|
| 3731 | +{ |
|---|
| 3732 | + struct ibmvfc_target *tgt = evt->tgt; |
|---|
| 3733 | + struct ibmvfc_host *vhost = evt->vhost; |
|---|
| 3734 | + struct ibmvfc_move_login *rsp = &evt->xfer_iu->move_login; |
|---|
| 3735 | + u32 status = be16_to_cpu(rsp->common.status); |
|---|
| 3736 | + int level = IBMVFC_DEFAULT_LOG_LEVEL; |
|---|
| 3737 | + |
|---|
| 3738 | + vhost->discovery_threads--; |
|---|
| 3739 | + ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE); |
|---|
| 3740 | + switch (status) { |
|---|
| 3741 | + case IBMVFC_MAD_SUCCESS: |
|---|
| 3742 | + tgt_dbg(tgt, "Move Login succeeded for old scsi_id: %llX\n", tgt->old_scsi_id); |
|---|
| 3743 | + tgt->ids.node_name = wwn_to_u64(rsp->service_parms.node_name); |
|---|
| 3744 | + tgt->ids.port_name = wwn_to_u64(rsp->service_parms.port_name); |
|---|
| 3745 | + tgt->ids.port_id = tgt->scsi_id; |
|---|
| 3746 | + memcpy(&tgt->service_parms, &rsp->service_parms, |
|---|
| 3747 | + sizeof(tgt->service_parms)); |
|---|
| 3748 | + memcpy(&tgt->service_parms_change, &rsp->service_parms_change, |
|---|
| 3749 | + sizeof(tgt->service_parms_change)); |
|---|
| 3750 | + ibmvfc_init_tgt(tgt, ibmvfc_tgt_send_prli); |
|---|
| 3751 | + break; |
|---|
| 3752 | + case IBMVFC_MAD_DRIVER_FAILED: |
|---|
| 3753 | + break; |
|---|
| 3754 | + case IBMVFC_MAD_CRQ_ERROR: |
|---|
| 3755 | + ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_move_login); |
|---|
| 3756 | + break; |
|---|
| 3757 | + case IBMVFC_MAD_FAILED: |
|---|
| 3758 | + default: |
|---|
| 3759 | + level += ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_move_login); |
|---|
| 3760 | + |
|---|
| 3761 | + tgt_log(tgt, level, |
|---|
| 3762 | + "Move Login failed: old scsi_id: %llX, flags:%x, vios_flags:%x, rc=0x%02X\n", |
|---|
| 3763 | + tgt->old_scsi_id, be32_to_cpu(rsp->flags), be16_to_cpu(rsp->vios_flags), |
|---|
| 3764 | + status); |
|---|
| 3765 | + break; |
|---|
| 3766 | + } |
|---|
| 3767 | + |
|---|
| 3768 | + kref_put(&tgt->kref, ibmvfc_release_tgt); |
|---|
| 3769 | + ibmvfc_free_event(evt); |
|---|
| 3770 | + wake_up(&vhost->work_wait_q); |
|---|
| 3771 | +} |
|---|
| 3772 | + |
|---|
| 3773 | + |
|---|
| 3774 | +/** |
|---|
| 3775 | + * ibmvfc_tgt_move_login - Initiate a move login for specified target |
|---|
| 3776 | + * @tgt: ibmvfc target struct |
|---|
| 3777 | + * |
|---|
| 3778 | + **/ |
|---|
| 3779 | +static void ibmvfc_tgt_move_login(struct ibmvfc_target *tgt) |
|---|
| 3780 | +{ |
|---|
| 3781 | + struct ibmvfc_host *vhost = tgt->vhost; |
|---|
| 3782 | + struct ibmvfc_move_login *move; |
|---|
| 3783 | + struct ibmvfc_event *evt; |
|---|
| 3784 | + |
|---|
| 3785 | + if (vhost->discovery_threads >= disc_threads) |
|---|
| 3786 | + return; |
|---|
| 3787 | + |
|---|
| 3788 | + kref_get(&tgt->kref); |
|---|
| 3789 | + evt = ibmvfc_get_event(vhost); |
|---|
| 3790 | + vhost->discovery_threads++; |
|---|
| 3791 | + ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_INIT_WAIT); |
|---|
| 3792 | + ibmvfc_init_event(evt, ibmvfc_tgt_move_login_done, IBMVFC_MAD_FORMAT); |
|---|
| 3793 | + evt->tgt = tgt; |
|---|
| 3794 | + move = &evt->iu.move_login; |
|---|
| 3795 | + memset(move, 0, sizeof(*move)); |
|---|
| 3796 | + move->common.version = cpu_to_be32(1); |
|---|
| 3797 | + move->common.opcode = cpu_to_be32(IBMVFC_MOVE_LOGIN); |
|---|
| 3798 | + move->common.length = cpu_to_be16(sizeof(*move)); |
|---|
| 3799 | + |
|---|
| 3800 | + move->old_scsi_id = cpu_to_be64(tgt->old_scsi_id); |
|---|
| 3801 | + move->new_scsi_id = cpu_to_be64(tgt->scsi_id); |
|---|
| 3802 | + move->wwpn = cpu_to_be64(tgt->wwpn); |
|---|
| 3803 | + move->node_name = cpu_to_be64(tgt->ids.node_name); |
|---|
| 3804 | + |
|---|
| 3805 | + if (ibmvfc_send_event(evt, vhost, default_timeout)) { |
|---|
| 3806 | + vhost->discovery_threads--; |
|---|
| 3807 | + ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); |
|---|
| 3808 | + kref_put(&tgt->kref, ibmvfc_release_tgt); |
|---|
| 3809 | + } else |
|---|
| 3810 | + tgt_dbg(tgt, "Sent Move Login for old scsi_id: %llX\n", tgt->old_scsi_id); |
|---|
| 3571 | 3811 | } |
|---|
| 3572 | 3812 | |
|---|
| 3573 | 3813 | /** |
|---|
| .. | .. |
|---|
| 3611 | 3851 | case IBMVFC_MAD_SUCCESS: |
|---|
| 3612 | 3852 | tgt_dbg(tgt, "ADISC succeeded\n"); |
|---|
| 3613 | 3853 | if (ibmvfc_adisc_needs_plogi(mad, tgt)) |
|---|
| 3614 | | - ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); |
|---|
| 3854 | + ibmvfc_del_tgt(tgt); |
|---|
| 3615 | 3855 | break; |
|---|
| 3616 | 3856 | case IBMVFC_MAD_DRIVER_FAILED: |
|---|
| 3617 | 3857 | break; |
|---|
| 3618 | 3858 | case IBMVFC_MAD_FAILED: |
|---|
| 3619 | 3859 | default: |
|---|
| 3620 | | - ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); |
|---|
| 3860 | + ibmvfc_del_tgt(tgt); |
|---|
| 3621 | 3861 | fc_reason = (be32_to_cpu(mad->fc_iu.response[1]) & 0x00ff0000) >> 16; |
|---|
| 3622 | 3862 | fc_explain = (be32_to_cpu(mad->fc_iu.response[1]) & 0x0000ff00) >> 8; |
|---|
| 3623 | 3863 | tgt_info(tgt, "ADISC failed: %s (%x:%x) %s (%x) %s (%x) rc=0x%02X\n", |
|---|
| 3624 | 3864 | ibmvfc_get_cmd_error(be16_to_cpu(mad->iu.status), be16_to_cpu(mad->iu.error)), |
|---|
| 3625 | | - mad->iu.status, mad->iu.error, |
|---|
| 3865 | + be16_to_cpu(mad->iu.status), be16_to_cpu(mad->iu.error), |
|---|
| 3626 | 3866 | ibmvfc_get_fc_type(fc_reason), fc_reason, |
|---|
| 3627 | 3867 | ibmvfc_get_ls_explain(fc_explain), fc_explain, status); |
|---|
| 3628 | 3868 | break; |
|---|
| .. | .. |
|---|
| 3810 | 4050 | switch (status) { |
|---|
| 3811 | 4051 | case IBMVFC_MAD_SUCCESS: |
|---|
| 3812 | 4052 | tgt_dbg(tgt, "Query Target succeeded\n"); |
|---|
| 3813 | | - tgt->new_scsi_id = be64_to_cpu(rsp->scsi_id); |
|---|
| 3814 | 4053 | if (be64_to_cpu(rsp->scsi_id) != tgt->scsi_id) |
|---|
| 3815 | | - ibmvfc_init_tgt(tgt, ibmvfc_tgt_implicit_logout); |
|---|
| 4054 | + ibmvfc_del_tgt(tgt); |
|---|
| 3816 | 4055 | else |
|---|
| 3817 | 4056 | ibmvfc_init_tgt(tgt, ibmvfc_tgt_adisc); |
|---|
| 3818 | 4057 | break; |
|---|
| .. | .. |
|---|
| 3826 | 4065 | if ((be16_to_cpu(rsp->status) & IBMVFC_FABRIC_MAPPED) == IBMVFC_FABRIC_MAPPED && |
|---|
| 3827 | 4066 | be16_to_cpu(rsp->error) == IBMVFC_UNABLE_TO_PERFORM_REQ && |
|---|
| 3828 | 4067 | be16_to_cpu(rsp->fc_explain) == IBMVFC_PORT_NAME_NOT_REG) |
|---|
| 3829 | | - ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); |
|---|
| 4068 | + ibmvfc_del_tgt(tgt); |
|---|
| 3830 | 4069 | else if (ibmvfc_retry_cmd(be16_to_cpu(rsp->status), be16_to_cpu(rsp->error))) |
|---|
| 3831 | 4070 | level += ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_query_target); |
|---|
| 3832 | 4071 | else |
|---|
| 3833 | | - ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); |
|---|
| 4072 | + ibmvfc_del_tgt(tgt); |
|---|
| 3834 | 4073 | |
|---|
| 3835 | 4074 | tgt_log(tgt, level, "Query Target failed: %s (%x:%x) %s (%x) %s (%x) rc=0x%02X\n", |
|---|
| 3836 | 4075 | ibmvfc_get_cmd_error(be16_to_cpu(rsp->status), be16_to_cpu(rsp->error)), |
|---|
| 3837 | | - rsp->status, rsp->error, ibmvfc_get_fc_type(be16_to_cpu(rsp->fc_type)), |
|---|
| 3838 | | - rsp->fc_type, ibmvfc_get_gs_explain(be16_to_cpu(rsp->fc_explain)), |
|---|
| 3839 | | - rsp->fc_explain, status); |
|---|
| 4076 | + be16_to_cpu(rsp->status), be16_to_cpu(rsp->error), |
|---|
| 4077 | + ibmvfc_get_fc_type(be16_to_cpu(rsp->fc_type)), be16_to_cpu(rsp->fc_type), |
|---|
| 4078 | + ibmvfc_get_gs_explain(be16_to_cpu(rsp->fc_explain)), be16_to_cpu(rsp->fc_explain), |
|---|
| 4079 | + status); |
|---|
| 3840 | 4080 | break; |
|---|
| 3841 | 4081 | } |
|---|
| 3842 | 4082 | |
|---|
| .. | .. |
|---|
| 3888 | 4128 | * Returns: |
|---|
| 3889 | 4129 | * 0 on success / other on failure |
|---|
| 3890 | 4130 | **/ |
|---|
| 3891 | | -static int ibmvfc_alloc_target(struct ibmvfc_host *vhost, u64 scsi_id) |
|---|
| 4131 | +static int ibmvfc_alloc_target(struct ibmvfc_host *vhost, |
|---|
| 4132 | + struct ibmvfc_discover_targets_entry *target) |
|---|
| 3892 | 4133 | { |
|---|
| 4134 | + struct ibmvfc_target *stgt = NULL; |
|---|
| 4135 | + struct ibmvfc_target *wtgt = NULL; |
|---|
| 3893 | 4136 | struct ibmvfc_target *tgt; |
|---|
| 3894 | 4137 | unsigned long flags; |
|---|
| 4138 | + u64 scsi_id = be32_to_cpu(target->scsi_id) & IBMVFC_DISC_TGT_SCSI_ID_MASK; |
|---|
| 4139 | + u64 wwpn = be64_to_cpu(target->wwpn); |
|---|
| 3895 | 4140 | |
|---|
| 4141 | + /* Look to see if we already have a target allocated for this SCSI ID or WWPN */ |
|---|
| 3896 | 4142 | spin_lock_irqsave(vhost->host->host_lock, flags); |
|---|
| 3897 | 4143 | list_for_each_entry(tgt, &vhost->targets, queue) { |
|---|
| 3898 | | - if (tgt->scsi_id == scsi_id) { |
|---|
| 3899 | | - if (tgt->need_login) |
|---|
| 3900 | | - ibmvfc_init_tgt(tgt, ibmvfc_tgt_implicit_logout); |
|---|
| 3901 | | - goto unlock_out; |
|---|
| 4144 | + if (tgt->wwpn == wwpn) { |
|---|
| 4145 | + wtgt = tgt; |
|---|
| 4146 | + break; |
|---|
| 3902 | 4147 | } |
|---|
| 4148 | + } |
|---|
| 4149 | + |
|---|
| 4150 | + list_for_each_entry(tgt, &vhost->targets, queue) { |
|---|
| 4151 | + if (tgt->scsi_id == scsi_id) { |
|---|
| 4152 | + stgt = tgt; |
|---|
| 4153 | + break; |
|---|
| 4154 | + } |
|---|
| 4155 | + } |
|---|
| 4156 | + |
|---|
| 4157 | + if (wtgt && !stgt) { |
|---|
| 4158 | + /* |
|---|
| 4159 | + * A WWPN target has moved and we still are tracking the old |
|---|
| 4160 | + * SCSI ID. The only way we should be able to get here is if |
|---|
| 4161 | + * we attempted to send an implicit logout for the old SCSI ID |
|---|
| 4162 | + * and it failed for some reason, such as there being I/O |
|---|
| 4163 | + * pending to the target. In this case, we will have already |
|---|
| 4164 | + * deleted the rport from the FC transport so we do a move |
|---|
| 4165 | + * login, which works even with I/O pending, as it will cancel |
|---|
| 4166 | + * any active commands. |
|---|
| 4167 | + */ |
|---|
| 4168 | + if (wtgt->action == IBMVFC_TGT_ACTION_LOGOUT_DELETED_RPORT) { |
|---|
| 4169 | + /* |
|---|
| 4170 | + * Do a move login here. The old target is no longer |
|---|
| 4171 | + * known to the transport layer We don't use the |
|---|
| 4172 | + * normal ibmvfc_set_tgt_action to set this, as we |
|---|
| 4173 | + * don't normally want to allow this state change. |
|---|
| 4174 | + */ |
|---|
| 4175 | + wtgt->old_scsi_id = wtgt->scsi_id; |
|---|
| 4176 | + wtgt->scsi_id = scsi_id; |
|---|
| 4177 | + wtgt->action = IBMVFC_TGT_ACTION_INIT; |
|---|
| 4178 | + ibmvfc_init_tgt(wtgt, ibmvfc_tgt_move_login); |
|---|
| 4179 | + goto unlock_out; |
|---|
| 4180 | + } else { |
|---|
| 4181 | + tgt_err(wtgt, "Unexpected target state: %d, %p\n", |
|---|
| 4182 | + wtgt->action, wtgt->rport); |
|---|
| 4183 | + } |
|---|
| 4184 | + } else if (stgt) { |
|---|
| 4185 | + if (tgt->need_login) |
|---|
| 4186 | + ibmvfc_init_tgt(tgt, ibmvfc_tgt_implicit_logout); |
|---|
| 4187 | + goto unlock_out; |
|---|
| 3903 | 4188 | } |
|---|
| 3904 | 4189 | spin_unlock_irqrestore(vhost->host->host_lock, flags); |
|---|
| 3905 | 4190 | |
|---|
| 3906 | 4191 | tgt = mempool_alloc(vhost->tgt_pool, GFP_NOIO); |
|---|
| 3907 | 4192 | memset(tgt, 0, sizeof(*tgt)); |
|---|
| 3908 | 4193 | tgt->scsi_id = scsi_id; |
|---|
| 3909 | | - tgt->new_scsi_id = scsi_id; |
|---|
| 4194 | + tgt->wwpn = wwpn; |
|---|
| 3910 | 4195 | tgt->vhost = vhost; |
|---|
| 3911 | 4196 | tgt->need_login = 1; |
|---|
| 3912 | | - tgt->cancel_key = vhost->task_set++; |
|---|
| 3913 | 4197 | timer_setup(&tgt->timer, ibmvfc_adisc_timeout, 0); |
|---|
| 3914 | 4198 | kref_init(&tgt->kref); |
|---|
| 3915 | 4199 | ibmvfc_init_tgt(tgt, ibmvfc_tgt_implicit_logout); |
|---|
| 3916 | 4200 | spin_lock_irqsave(vhost->host->host_lock, flags); |
|---|
| 4201 | + tgt->cancel_key = vhost->task_set++; |
|---|
| 3917 | 4202 | list_add_tail(&tgt->queue, &vhost->targets); |
|---|
| 3918 | 4203 | |
|---|
| 3919 | 4204 | unlock_out: |
|---|
| .. | .. |
|---|
| 3933 | 4218 | int i, rc; |
|---|
| 3934 | 4219 | |
|---|
| 3935 | 4220 | for (i = 0, rc = 0; !rc && i < vhost->num_targets; i++) |
|---|
| 3936 | | - rc = ibmvfc_alloc_target(vhost, |
|---|
| 3937 | | - be32_to_cpu(vhost->disc_buf->scsi_id[i]) & |
|---|
| 3938 | | - IBMVFC_DISC_TGT_SCSI_ID_MASK); |
|---|
| 4221 | + rc = ibmvfc_alloc_target(vhost, &vhost->disc_buf[i]); |
|---|
| 3939 | 4222 | |
|---|
| 3940 | 4223 | return rc; |
|---|
| 3941 | 4224 | } |
|---|
| .. | .. |
|---|
| 3962 | 4245 | level += ibmvfc_retry_host_init(vhost); |
|---|
| 3963 | 4246 | ibmvfc_log(vhost, level, "Discover Targets failed: %s (%x:%x)\n", |
|---|
| 3964 | 4247 | ibmvfc_get_cmd_error(be16_to_cpu(rsp->status), be16_to_cpu(rsp->error)), |
|---|
| 3965 | | - rsp->status, rsp->error); |
|---|
| 4248 | + be16_to_cpu(rsp->status), be16_to_cpu(rsp->error)); |
|---|
| 3966 | 4249 | break; |
|---|
| 3967 | 4250 | case IBMVFC_MAD_DRIVER_FAILED: |
|---|
| 3968 | 4251 | break; |
|---|
| .. | .. |
|---|
| 3995 | 4278 | mad->bufflen = cpu_to_be32(vhost->disc_buf_sz); |
|---|
| 3996 | 4279 | mad->buffer.va = cpu_to_be64(vhost->disc_buf_dma); |
|---|
| 3997 | 4280 | mad->buffer.len = cpu_to_be32(vhost->disc_buf_sz); |
|---|
| 4281 | + mad->flags = cpu_to_be32(IBMVFC_DISC_TGT_PORT_ID_WWPN_LIST); |
|---|
| 3998 | 4282 | ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_INIT_WAIT); |
|---|
| 3999 | 4283 | |
|---|
| 4000 | 4284 | if (!ibmvfc_send_event(evt, vhost, default_timeout)) |
|---|
| .. | .. |
|---|
| 4027 | 4311 | ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD); |
|---|
| 4028 | 4312 | ibmvfc_log(vhost, level, "NPIV Login failed: %s (%x:%x)\n", |
|---|
| 4029 | 4313 | ibmvfc_get_cmd_error(be16_to_cpu(rsp->status), be16_to_cpu(rsp->error)), |
|---|
| 4030 | | - rsp->status, rsp->error); |
|---|
| 4314 | + be16_to_cpu(rsp->status), be16_to_cpu(rsp->error)); |
|---|
| 4031 | 4315 | ibmvfc_free_event(evt); |
|---|
| 4032 | 4316 | return; |
|---|
| 4033 | 4317 | case IBMVFC_MAD_CRQ_ERROR: |
|---|
| 4034 | 4318 | ibmvfc_retry_host_init(vhost); |
|---|
| 4319 | + fallthrough; |
|---|
| 4035 | 4320 | case IBMVFC_MAD_DRIVER_FAILED: |
|---|
| 4036 | 4321 | ibmvfc_free_event(evt); |
|---|
| 4037 | 4322 | return; |
|---|
| .. | .. |
|---|
| 4198 | 4483 | } |
|---|
| 4199 | 4484 | |
|---|
| 4200 | 4485 | /** |
|---|
| 4486 | + * ibmvfc_dev_logo_to_do - Is there target logout work to do? |
|---|
| 4487 | + * @vhost: ibmvfc host struct |
|---|
| 4488 | + * |
|---|
| 4489 | + * Returns: |
|---|
| 4490 | + * 1 if work to do / 0 if not |
|---|
| 4491 | + **/ |
|---|
| 4492 | +static int ibmvfc_dev_logo_to_do(struct ibmvfc_host *vhost) |
|---|
| 4493 | +{ |
|---|
| 4494 | + struct ibmvfc_target *tgt; |
|---|
| 4495 | + |
|---|
| 4496 | + list_for_each_entry(tgt, &vhost->targets, queue) { |
|---|
| 4497 | + if (tgt->action == IBMVFC_TGT_ACTION_LOGOUT_RPORT || |
|---|
| 4498 | + tgt->action == IBMVFC_TGT_ACTION_LOGOUT_RPORT_WAIT) |
|---|
| 4499 | + return 1; |
|---|
| 4500 | + } |
|---|
| 4501 | + return 0; |
|---|
| 4502 | +} |
|---|
| 4503 | + |
|---|
| 4504 | +/** |
|---|
| 4201 | 4505 | * __ibmvfc_work_to_do - Is there task level work to do? (no locking) |
|---|
| 4202 | 4506 | * @vhost: ibmvfc host struct |
|---|
| 4203 | 4507 | * |
|---|
| .. | .. |
|---|
| 4226 | 4530 | if (tgt->action == IBMVFC_TGT_ACTION_INIT_WAIT) |
|---|
| 4227 | 4531 | return 0; |
|---|
| 4228 | 4532 | return 1; |
|---|
| 4533 | + case IBMVFC_HOST_ACTION_TGT_DEL: |
|---|
| 4534 | + case IBMVFC_HOST_ACTION_TGT_DEL_FAILED: |
|---|
| 4535 | + if (vhost->discovery_threads == disc_threads) |
|---|
| 4536 | + return 0; |
|---|
| 4537 | + list_for_each_entry(tgt, &vhost->targets, queue) |
|---|
| 4538 | + if (tgt->action == IBMVFC_TGT_ACTION_LOGOUT_RPORT) |
|---|
| 4539 | + return 1; |
|---|
| 4540 | + list_for_each_entry(tgt, &vhost->targets, queue) |
|---|
| 4541 | + if (tgt->action == IBMVFC_TGT_ACTION_LOGOUT_RPORT_WAIT) |
|---|
| 4542 | + return 0; |
|---|
| 4543 | + return 1; |
|---|
| 4229 | 4544 | case IBMVFC_HOST_ACTION_LOGO: |
|---|
| 4230 | 4545 | case IBMVFC_HOST_ACTION_INIT: |
|---|
| 4231 | 4546 | case IBMVFC_HOST_ACTION_ALLOC_TGTS: |
|---|
| 4232 | | - case IBMVFC_HOST_ACTION_TGT_DEL: |
|---|
| 4233 | | - case IBMVFC_HOST_ACTION_TGT_DEL_FAILED: |
|---|
| 4234 | 4547 | case IBMVFC_HOST_ACTION_QUERY: |
|---|
| 4235 | 4548 | case IBMVFC_HOST_ACTION_RESET: |
|---|
| 4236 | 4549 | case IBMVFC_HOST_ACTION_REENABLE: |
|---|
| .. | .. |
|---|
| 4300 | 4613 | fc_remote_port_delete(rport); |
|---|
| 4301 | 4614 | del_timer_sync(&tgt->timer); |
|---|
| 4302 | 4615 | kref_put(&tgt->kref, ibmvfc_release_tgt); |
|---|
| 4616 | + return; |
|---|
| 4617 | + } else if (rport && tgt->action == IBMVFC_TGT_ACTION_DEL_AND_LOGOUT_RPORT) { |
|---|
| 4618 | + tgt_dbg(tgt, "Deleting rport with outstanding I/O\n"); |
|---|
| 4619 | + ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_LOGOUT_DELETED_RPORT); |
|---|
| 4620 | + tgt->rport = NULL; |
|---|
| 4621 | + spin_unlock_irqrestore(vhost->host->host_lock, flags); |
|---|
| 4622 | + fc_remote_port_delete(rport); |
|---|
| 4303 | 4623 | return; |
|---|
| 4304 | 4624 | } else if (rport && tgt->action == IBMVFC_TGT_ACTION_DELETED_RPORT) { |
|---|
| 4305 | 4625 | spin_unlock_irqrestore(vhost->host->host_lock, flags); |
|---|
| .. | .. |
|---|
| 4419 | 4739 | case IBMVFC_HOST_ACTION_TGT_DEL: |
|---|
| 4420 | 4740 | case IBMVFC_HOST_ACTION_TGT_DEL_FAILED: |
|---|
| 4421 | 4741 | list_for_each_entry(tgt, &vhost->targets, queue) { |
|---|
| 4742 | + if (tgt->action == IBMVFC_TGT_ACTION_LOGOUT_RPORT) { |
|---|
| 4743 | + tgt->job_step(tgt); |
|---|
| 4744 | + break; |
|---|
| 4745 | + } |
|---|
| 4746 | + } |
|---|
| 4747 | + |
|---|
| 4748 | + if (ibmvfc_dev_logo_to_do(vhost)) { |
|---|
| 4749 | + spin_unlock_irqrestore(vhost->host->host_lock, flags); |
|---|
| 4750 | + return; |
|---|
| 4751 | + } |
|---|
| 4752 | + |
|---|
| 4753 | + list_for_each_entry(tgt, &vhost->targets, queue) { |
|---|
| 4422 | 4754 | if (tgt->action == IBMVFC_TGT_ACTION_DEL_RPORT) { |
|---|
| 4423 | 4755 | tgt_dbg(tgt, "Deleting rport\n"); |
|---|
| 4424 | 4756 | rport = tgt->rport; |
|---|
| .. | .. |
|---|
| 4430 | 4762 | fc_remote_port_delete(rport); |
|---|
| 4431 | 4763 | del_timer_sync(&tgt->timer); |
|---|
| 4432 | 4764 | kref_put(&tgt->kref, ibmvfc_release_tgt); |
|---|
| 4765 | + return; |
|---|
| 4766 | + } else if (tgt->action == IBMVFC_TGT_ACTION_DEL_AND_LOGOUT_RPORT) { |
|---|
| 4767 | + tgt_dbg(tgt, "Deleting rport with I/O outstanding\n"); |
|---|
| 4768 | + rport = tgt->rport; |
|---|
| 4769 | + tgt->rport = NULL; |
|---|
| 4770 | + ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_LOGOUT_DELETED_RPORT); |
|---|
| 4771 | + spin_unlock_irqrestore(vhost->host->host_lock, flags); |
|---|
| 4772 | + if (rport) |
|---|
| 4773 | + fc_remote_port_delete(rport); |
|---|
| 4433 | 4774 | return; |
|---|
| 4434 | 4775 | } |
|---|
| 4435 | 4776 | } |
|---|
| .. | .. |
|---|
| 4663 | 5004 | goto free_sg_pool; |
|---|
| 4664 | 5005 | } |
|---|
| 4665 | 5006 | |
|---|
| 4666 | | - vhost->disc_buf_sz = sizeof(vhost->disc_buf->scsi_id[0]) * max_targets; |
|---|
| 5007 | + vhost->disc_buf_sz = sizeof(*vhost->disc_buf) * max_targets; |
|---|
| 4667 | 5008 | vhost->disc_buf = dma_alloc_coherent(dev, vhost->disc_buf_sz, |
|---|
| 4668 | 5009 | &vhost->disc_buf_dma, GFP_KERNEL); |
|---|
| 4669 | 5010 | |
|---|