From patchwork Wed Dec 20 06:56:23 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Madhani, Himanshu" X-Patchwork-Id: 10125085 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 5B8FA6019C for ; Wed, 20 Dec 2017 06:57:39 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 4A49D2964F for ; Wed, 20 Dec 2017 06:57:39 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 3EBFB29652; Wed, 20 Dec 2017 06:57:39 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 7514229649 for ; Wed, 20 Dec 2017 06:57:36 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932503AbdLTG5f (ORCPT ); Wed, 20 Dec 2017 01:57:35 -0500 Received: from mail-co1nam03on0059.outbound.protection.outlook.com ([104.47.40.59]:39605 "EHLO NAM03-CO1-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S932458AbdLTG5R (ORCPT ); Wed, 20 Dec 2017 01:57:17 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=CAVIUMNETWORKS.onmicrosoft.com; s=selector1-cavium-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version; bh=N6As4r6TrfmGLUsuWlY481u1D0rWKoirmqcDhRDGN38=; b=aFdvdWJ+eLfDt3nlu2jWo7iIXScZhLUoZkUSXOsNmWarvRgtWN3yb2bnoSL3qrFoFZ0WCToAlBVvqj8XhvPgu6bPSYm6rzg1YHO/Iib8VK3sADCEWXX6atCM4CIEAe9bwrgTYcv+dSFvLqQEknUHdelEwO/Az+2oSzT9jo58sMg= Received: from CO2PR07CA0077.namprd07.prod.outlook.com (10.174.192.45) by CY1PR0701MB1947.namprd07.prod.outlook.com (10.163.141.156) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P256) id 15.20.345.14; Wed, 20 Dec 2017 06:57:14 +0000 Received: from BN1AFFO11FD043.protection.gbl (2a01:111:f400:7c10::154) by CO2PR07CA0077.outlook.office365.com (2603:10b6:100::45) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384) id 15.20.345.14 via Frontend Transport; Wed, 20 Dec 2017 06:57:14 +0000 Authentication-Results: spf=permerror (sender IP is 50.232.66.26) smtp.mailfrom=cavium.com; vger.kernel.org; dkim=none (message not signed) header.d=none; vger.kernel.org; dmarc=none action=none header.from=cavium.com; Received-SPF: PermError (protection.outlook.com: domain of cavium.com used an invalid SPF mechanism) Received: from CAEXCH02.caveonetworks.com (50.232.66.26) by BN1AFFO11FD043.mail.protection.outlook.com (10.58.52.190) with Microsoft SMTP Server (version=TLS1_0, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA_P384) id 15.20.302.6 via Frontend Transport; Wed, 20 Dec 2017 06:57:00 +0000 Received: from dut1171.mv.qlogic.com (172.29.51.171) by CAEXCH02.caveonetworks.com (10.17.4.29) with Microsoft SMTP Server id 14.2.347.0; Tue, 19 Dec 2017 22:56:49 -0800 Received: from dut1171.mv.qlogic.com (localhost [127.0.0.1]) by dut1171.mv.qlogic.com (8.14.7/8.14.7) with ESMTP id vBK6unD3021634; Tue, 19 Dec 2017 22:56:49 -0800 Received: (from root@localhost) by dut1171.mv.qlogic.com (8.14.7/8.14.7/Submit) id vBK6unp6021633; Tue, 19 Dec 2017 22:56:49 -0800 From: Himanshu Madhani To: , CC: , Subject: [PATCH 22/43] qla2xxx: Add switch command to simplify fabric discovery Date: Tue, 19 Dec 2017 22:56:23 -0800 Message-ID: <20171220065644.21511-23-himanshu.madhani@cavium.com> X-Mailer: git-send-email 2.12.0 In-Reply-To: <20171220065644.21511-1-himanshu.madhani@cavium.com> References: <20171220065644.21511-1-himanshu.madhani@cavium.com> MIME-Version: 1.0 X-EOPAttributedMessage: 0 X-Forefront-Antispam-Report: CIP:50.232.66.26; IPV:NLI; CTRY:US; EFV:NLI; SFV:NSPM; SFS:(10009020)(346002)(396003)(39860400002)(376002)(39380400002)(2980300002)(448002)(199004)(40224003)(189003)(76176011)(50466002)(69596002)(478600001)(1076002)(72206003)(48376002)(87636003)(36756003)(356003)(85326001)(80596001)(59450400001)(106466001)(51416003)(53946003)(575784001)(305945005)(86362001)(4326008)(54906003)(2906002)(8936002)(50226002)(81156014)(81166006)(8676002)(2950100002)(6666003)(16586007)(316002)(42186006)(47776003)(110136005)(5660300001)(579004)(559001); DIR:OUT; SFP:1101; SCL:1; SRVR:CY1PR0701MB1947; H:CAEXCH02.caveonetworks.com; FPR:; SPF:PermError; PTR:50-232-66-26-static.hfc.comcastbusiness.net; A:1; MX:1; LANG:en; X-Microsoft-Exchange-Diagnostics: 1; BN1AFFO11FD043; 1:wTEYOyhIxUItA57UHC9n3w+W+Mzq/c+PhsKNJX4NTKUhOAxIPPMk88JOls/5M7h66aMElPDk0XhFf7S7DoDRKMzP24rTOHftyY68bQ6Z582J7W9qC44VUbJPOKimAJRt X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: 228816a8-d1d1-43ae-8dca-08d54776de97 X-Microsoft-Antispam: UriScan:; BCL:0; PCL:0; RULEID:(5600026)(4604075)(4534020)(4602075)(4627115)(201703031133081)(201702281549075)(2017052603307)(7153060); SRVR:CY1PR0701MB1947; X-Microsoft-Exchange-Diagnostics: 1; CY1PR0701MB1947; 3:oxdSrGFpRqBi/0xtRnggbfj0U4u2oj71HfV4WN6FJU7ZgtV9yMgRRxs2jZtSAhqstxZ+YPg1nJBX9O8XyaYAtFX1zJ38tNw5ArM8e3pDsKGm5urU+i8C6h5jr48JjJFZ7ZUtkZatMV+1arecidJgPC/PTcHN2rS6BlH+FzI2HWeBJTTEGL5fd089FEXyZAVQlYtkUIgY7XKgTQreVhtYhU4F+Q8bymGDfQZ8Yb8dePNMGxHQySBTHbzEikDtZ+3wxUr1ppa3oOLLSKB47nehfg+RjFsGjQJcYLhhNV6X7irrRTk/5kpUZ8tM9G31obXMHYiLnha2NT5YFLpEas3fWjwsexQbUPzIfF1TM/7/qH4=; 25:Cl7FAQxuC8GKw2D12WlZyzgWMwUMBhvGbzh8cUCnvH/EP6peIvbkoCbWFf6s3+BqgM0jQk9w+YXiskiYdNZ/BBFyhqQRLOx/mEQhoJVYglD/ZMtjqN0OjeJCS57dO51EZtIzqN7obBFdzqlqfhKwBZDAnfpPd6hGm+b4WL7lErm4CAhr1ET6gGFIrC4puzCk2caLWBwYUSPeV96XCzT+8X8x+2G71pA3k5IYfcvcgTL2hBPx8+1LBjGGBZ6XB9ajuBz0Yg75T8U+74UIM7A48Iw+GXk/XJhDCId5D7+mq8Dl4eH9dz5x1I0xftbC+V1rOhjCcAtzMK6QVtwIjamOJHFhh+rE31KGv45omwkyqfc= X-MS-TrafficTypeDiagnostic: CY1PR0701MB1947: X-Microsoft-Exchange-Diagnostics: 1; CY1PR0701MB1947; 31:H+9chb0kD/BYsJjf/kOfX85oDOQbdNufhuqLgiMNuRjSg7mTLwzPojmsJUZAz2FOMtbd09Q9e5WXIKostcEBabZVl4jeQJj7hDxyOrnRjzoBvXVdrcwyeflIbM6nB3fvayb1GKXa94m6JxGpoC5Bl1Y5CXDMvI5qBkg27y1l/kwGm+uwlbPcyucAWJPXh4gXJCy9VVCtyWwsn3oJ/vD3oivmcy6dckErLvHlfult44s=; 20:A0iugauOmsuS72WVBinngRwQNbCGVlrPRAvwZ5HJA+aKvEFVsoI61pgNtoAIZvBncG0yB/tIaUTdRUU4Nfx2/0/kAHDyz2t0babacDxuA0b5c/KONZTC+mmYF3q8Hwm5HvR6LNy7Sjzp9Ap8jd1orzPY92IqomkRr+FedqzgJPHoXgP9uKRz+leujcGOXK46831Kyy61BamhM95AyEpbOtXAsl+Kl8dnnwZS2mANPUxl387oiL8E//wmFeW1JfXy8D8w5o9X8Ur5T1uXxLxZ9VJhakLIScUGp43xtr8xK7VyNA2ifYIToMfj1fY9ATNRq4bYWZMfzhRHU7BsUSfTWLrO4600qXSSl40ax+tsgsVMRJ5b1E5acxl3udPWQc/jbNJtdbHM7to2BDVCqUrk6tZt3GJPrv6OsgYx4kM02JmWdUGNk2AaliI5rjkh2KbWrjo+i6aqmKfSXr1ju5m8P0vOo1b3Afk/wIh/eTDff3m+1QZn+QziUEi3OtmUBGju X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:(209352067349851); X-Exchange-Antispam-Report-CFA-Test: BCL:0; PCL:0; RULEID:(6040470)(2401047)(5005006)(8121501046)(10201501046)(3231023)(93006095)(93001095)(3002001)(6041268)(20161123558120)(20161123562045)(20161123564045)(20161123560045)(201703131423095)(201702281528075)(20161123555045)(201703061421075)(201703061406153)(6072148)(201708071742011); SRVR:CY1PR0701MB1947; BCL:0; PCL:0; RULEID:(100000803101)(100110400095); SRVR:CY1PR0701MB1947; X-Microsoft-Exchange-Diagnostics: 1; CY1PR0701MB1947; 4:VDmAYqbe8hugU2Au5QoqygdUekoCKb9+OJvQK/YjkXh1ARw20RKGaW4s4dA8prZEXQNmJ2tX4t5C7YftVFiYQ7Ubm2CxDd7d1StYUD9zOr9OXvEkLa/OMagzPxuibRCTZNc9ffoUQDmkQBzfaDIhXxZoowQTIuAp0aofBDJeT0rodYcokkv7XWQSbqS+ZjxUYrB19oapWPGobZTHPQKIGF/3eNYb4hrnF6Nv7cGfU0x1leQi20oTwETJ8mPo/RbbfQwcJrN1n6E6OCvWAKYffr9+sHZsJdDuznz6IMdksGvHpXsaY2wIySlmKtZL5tvm X-Forefront-PRVS: 0527DFA348 X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1; CY1PR0701MB1947; 23:cA5P2sRXxq8A9gfHsk3vbFBYZsCfgF2ZATCjelv?= =?us-ascii?Q?/WZgKIv2dnZJWvujCHowBS+upzor2PYEgjJjyohe6TQQ6kQJnpXvR/xrE5Pr?= =?us-ascii?Q?o0++PrgtBhljPHUgtbb4ExiC2KmE7dKNn/T+egxHdcOU9mBPOZ4f0AfaSDK6?= =?us-ascii?Q?SFBAXapshchTl61rL6GqVA+1Fr2ZR3MB2QNHIR5bchJwSo1sJf7msM8XOkwk?= =?us-ascii?Q?Zg+Fu34L4BwE9scWHVg1GplJ8ySjOC9zs1bsnkcGA0rbGxHcPAs8IreBy4AR?= =?us-ascii?Q?9e+Eiq/WMBMGQVA0X/7HsdpcdWZa2Mbg/kQCOHKCO4ex67dR4JjHEGdL7cTe?= =?us-ascii?Q?4JfhVCvPcruI6Taw/7DxOUuZGsSBe4vrbOJUs5cgejS3U0hFfrv51aiJBCMe?= =?us-ascii?Q?Os8rGn5ZPkfIxaJD6DTCF0BcjWJFjfLnyGqzVTop3xVEoCkyjgYqY/TaTB0s?= =?us-ascii?Q?NiWH/Z9xmhjXZBPjN7Lv87PQWzWLNkKv0Uujof5TehMMWNT0+aEbyEtFdccS?= =?us-ascii?Q?Io8w7BQywjCjgL+FLcXQSAPsZut4G/BC0qZZrK0JN8si4NkmsisuE/4cvK+8?= =?us-ascii?Q?aRVcEgJ39KwVw7iKVHdzp7YLsJcMGufZ+tTS3lghGZ6ZfVR9yuXe2AorsvVF?= =?us-ascii?Q?B65WCbsbW26g9jQkGaAz6fBK2TBySK1yv81kbaFIMN9t8oa/GBDNKGlaOiRP?= =?us-ascii?Q?G9jjf/RfPFoqZ8zNwOb19VKoFmsfzYC0gXUIyDyGOcL4q6vNMx4RWrGpMUVG?= =?us-ascii?Q?n9N0w4BI3l+DuDZq+CFto+WlEuB9ulgSEvsxt4RxG9XU0vO7vlFAYxXPYz7P?= =?us-ascii?Q?tccE8MnG5r8HWH+WSG9MGdQZv05qj5J/b+NJKP0J4Ee3+dQqiTm/sgpLdUl4?= =?us-ascii?Q?TScJzw7jPmSTtatRM9R092T1SHq+ZtZFnxYyghx8tBY+QcJmqipkadEqvCsc?= =?us-ascii?Q?6fPaDWpDY6cpJ8RXR3SQha0IWBEuTyjeqnRVNIFjyLl1uvh6LNqTlMeGmUlJ?= =?us-ascii?Q?UVgJ31qpX9zcXYPB4Q56Wg6oUAwTSEPOIRw6rxiASq2ZmxqpPTjAK8H4yoyF?= =?us-ascii?Q?/P9TA3x4j6zvo9Zd3EJxsdw1WrxOEmEW5AEOuiJBDe8Q/0zQqhn0tiKK5E4O?= =?us-ascii?Q?R0mb7av6dpsI=3D?= X-Microsoft-Exchange-Diagnostics: 1; CY1PR0701MB1947; 6:w9JNf9AID0cSOirQ66ykF8GASaSPK1vrkT8Gs1TJb5JqsVqpWBP3IrKszHGwFlSXdXsc03MM9t5cjtgJlBEQN26thG8DHuXsZ7BHAIakHZnnCeOF79y5LWnH0qMrW2NtFdgaNj4jAmX1T5tIgltsQ9kOcxwNIGKPnq1VbqtYsftvz42VfWwWu99ehiCC5kdw1WxmMhDRMNFtRn4zPpQ5NyE1yNcPSpdIcju0wnOzP1K+WGYlXig8JBqbG1mxP6cIxNIuPyFSObW/ZNdOrNPnnL8U9+PBE6OmsjxHQ/9B0PULrUyfJKoWVaK1fy6aUQ6tLgmjuMtO9xKTaTbmI67ll7RWUIyJjAGv9hM+gBsJrXQ=; 5:1QHwhAp1lXHCL3dZWvr4YOsVU1LhvU7YmmJnpvzhdvl4ga5P1PMS9ew9QslhI+QcZKOST0aLCsWGI6njiK9Feca9RKkfMCox+SaXgGrNZ28i9ixE0d765mdjbYBA5WdCN5pbVf7+DqbJJr+peAwcHKhm0XPA21FnC5QPmWk9vgc=; 24:S2rUJeyhNVwcP06SM1jdLwqTbSvvb8QIzYp6Lres4wFppJSZH5e7pFG7gAxOzWE0gQmfgzeOi6Qto1BToDaxHPFhy0u9DnkO4rHIjefYV3I=; 7:ey1OsWVvdxxEeB7XuzZzYJQvchrkwUSdf8n+IMGa6qV+QGCr1/gx1eoGnCzQKh98cu5DVHcF7S7PSHGicKSOYloxD3G96ftsy9rlQAfTsUIAaFXms6KjasFm+ZySLV2KdFl8QRKRN0ReKDMaX77KCg6/MhojJaw8orGgZ0i7Wf9Kqk6ndVzby19BqDG//UTu/qrsTC0wKR0rh3Sc/oUvTbfloKWsVozwjzrcn7NlNY3rbb1HAMl9nLkS+AaCQ8IB SpamDiagnosticOutput: 1:99 SpamDiagnosticMetadata: NSPM X-OriginatorOrg: cavium.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 20 Dec 2017 06:57:00.4612 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 228816a8-d1d1-43ae-8dca-08d54776de97 X-MS-Exchange-CrossTenant-Id: 711e4ccf-2e9b-4bcf-a551-4094005b6194 X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=711e4ccf-2e9b-4bcf-a551-4094005b6194; Ip=[50.232.66.26]; Helo=[CAEXCH02.caveonetworks.com] X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: CY1PR0701MB1947 Sender: linux-scsi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Quinn Tran - add "async" gpn_ft, gnn_ft, gfpn_id, gnn_id switch commands. - For 8G and newer adapters, use async commands when it comes to fabric scan to reduce bottle neck. Signed-off-by: Quinn Tran Signed-off-by: Himanshu Madhani --- drivers/scsi/qla2xxx/qla_attr.c | 2 + drivers/scsi/qla2xxx/qla_def.h | 73 +++- drivers/scsi/qla2xxx/qla_gbl.h | 17 +- drivers/scsi/qla2xxx/qla_gs.c | 711 +++++++++++++++++++++++++++++++++++++- drivers/scsi/qla2xxx/qla_init.c | 309 +++++++++++------ drivers/scsi/qla2xxx/qla_mbx.c | 5 +- drivers/scsi/qla2xxx/qla_os.c | 47 ++- drivers/scsi/qla2xxx/qla_target.c | 62 +++- drivers/scsi/qla2xxx/qla_target.h | 2 +- 9 files changed, 1105 insertions(+), 123 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index 9ce28c4f9812..b360df9936ff 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -2170,6 +2170,8 @@ qla24xx_vport_delete(struct fc_vport *fc_vport) dma_free_coherent(&ha->pdev->dev, vha->gnl.size, vha->gnl.l, vha->gnl.ldma); + vfree(vha->scan.l); + if (vha->qpair && vha->qpair->vp_idx == vha->vp_idx) { if (qla2xxx_delete_qpair(vha, vha->qpair) != QLA_SUCCESS) ql_log(ql_log_warn, vha, 0x7087, diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 749f3e457346..3042697b92ae 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -490,6 +490,7 @@ enum { SPCN_GPSC, SPCN_GPNID, SPCN_GPNFT, + SPCN_GNNFT, SPCN_GNNID, SPCN_GFPNID, SPCN_LOGIN, @@ -2315,11 +2316,13 @@ struct ct_sns_desc { enum discovery_state { DSC_DELETED, + DSC_GNN_ID, DSC_GID_PN, DSC_GNL, DSC_LOGIN_PEND, DSC_LOGIN_FAILED, DSC_GPDB, + DSC_GFPN_ID, DSC_GPSC, DSC_UPD_FCPORT, DSC_LOGIN_COMPLETE, @@ -2349,8 +2352,9 @@ enum fcport_mgt_event { FCME_GPDB_DONE, FCME_GPNID_DONE, FCME_GFFID_DONE, - FCME_DELETE_DONE, FCME_ADISC_DONE, + FCME_GNNID_DONE, + FCME_GFPNID_DONE, }; enum rscn_addr_format { @@ -2383,6 +2387,7 @@ typedef struct fc_port { unsigned int login_pause:1; unsigned int login_succ:1; unsigned int query:1; + unsigned int id_changed:1; struct work_struct nvme_del_work; struct completion nvme_del_done; @@ -2530,6 +2535,11 @@ static const char * const port_state_str[] = { #define GA_NXT_REQ_SIZE (16 + 4) #define GA_NXT_RSP_SIZE (16 + 620) +#define GPN_FT_CMD 0x172 +#define GPN_FT_REQ_SIZE (16 + 4) +#define GNN_FT_CMD 0x173 +#define GNN_FT_REQ_SIZE (16 + 4) + #define GID_PT_CMD 0x1A1 #define GID_PT_REQ_SIZE (16 + 4) @@ -2785,6 +2795,13 @@ struct ct_sns_req { } port_id; struct { + uint8_t reserved; + uint8_t domain; + uint8_t area; + uint8_t port_type; + } gpn_ft; + + struct { uint8_t port_type; uint8_t domain; uint8_t area; @@ -2897,6 +2914,27 @@ struct ct_sns_gid_pt_data { uint8_t port_id[3]; }; +/* It's the same for both GPN_FT and GNN_FT */ +struct ct_sns_gpnft_rsp { + struct { + struct ct_cmd_hdr header; + uint16_t response; + uint16_t residual; + uint8_t fragment_id; + uint8_t reason_code; + uint8_t explanation_code; + uint8_t vendor_unique; + }; + /* Assume the largest number of targets for the union */ + struct ct_sns_gpn_ft_data { + u8 control_byte; + u8 port_id[3]; + u32 reserved; + u8 port_name[8]; + } entries[1]; +}; + +/* CT command response */ struct ct_sns_rsp { struct ct_rsp_hdr header; @@ -2972,6 +3010,24 @@ struct ct_sns_pkt { } p; }; +struct ct_sns_gpnft_pkt { + union { + struct ct_sns_req req; + struct ct_sns_gpnft_rsp rsp; + } p; +}; + +struct fab_scan_rp { + port_id_t id; + u8 port_name[8]; + u8 node_name[8]; +}; + +struct fab_scan { + struct fab_scan_rp *l; + u32 size; +}; + /* * SNS command structures -- for 2200 compatibility. */ @@ -3189,6 +3245,11 @@ enum qla_work_type { QLA_EVT_RELOGIN, QLA_EVT_ASYNC_PRLO, QLA_EVT_ASYNC_PRLO_DONE, + QLA_EVT_GPNFT, + QLA_EVT_GPNFT_DONE, + QLA_EVT_GNNFT_DONE, + QLA_EVT_GNNID, + QLA_EVT_GFPNID, }; @@ -3230,7 +3291,9 @@ struct qla_work_evt { struct { port_id_t id; u8 port_name[8]; + u8 node_name[8]; void *pla; + u8 fc4_type; } new_sess; struct { /*Get PDB, Get Speed, update fcport, gnl, gidpn */ fc_port_t *fcport; @@ -3241,6 +3304,9 @@ struct qla_work_evt { u8 iocb[IOCB_SIZE]; int type; } nack; + struct { + u8 fc4_type; + } gpnft; } u; }; @@ -3796,6 +3862,8 @@ struct qla_hw_data { (IS_QLA81XX(ha) || IS_QLA83XX(ha) || IS_QLA27XX(ha)) #define IS_EXLOGIN_OFFLD_CAPABLE(ha) \ (IS_QLA25XX(ha) || IS_QLA81XX(ha) || IS_QLA83XX(ha) || IS_QLA27XX(ha)) +#define USE_ASYNC_SCAN(ha) (IS_QLA25XX(ha) || IS_QLA81XX(ha) ||\ + IS_QLA83XX(ha) || IS_QLA27XX(ha)) /* HBA serial number */ uint8_t serial0; @@ -3878,7 +3946,7 @@ struct qla_hw_data { int exchoffld_size; int exchoffld_count; - void *swl; + void *swl; /* These are used by mailbox operations. */ uint16_t mailbox_out[MAILBOX_REGISTER_COUNT]; @@ -4340,6 +4408,7 @@ typedef struct scsi_qla_host { uint8_t n2n_port_name[WWN_SIZE]; uint16_t n2n_id; struct list_head gpnid_list; + struct fab_scan scan; } scsi_qla_host_t; struct qla27xx_image_status { diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index 2e0907994579..43799e8dc68a 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -105,8 +105,8 @@ int qla24xx_async_gpdb(struct scsi_qla_host *, fc_port_t *, u8); int qla24xx_async_prli(struct scsi_qla_host *, fc_port_t *); int qla24xx_async_notify_ack(scsi_qla_host_t *, fc_port_t *, struct imm_ntfy_from_isp *, int); -int qla24xx_post_newsess_work(struct scsi_qla_host *, port_id_t *, u8 *, - void *); +int qla24xx_post_newsess_work(struct scsi_qla_host *, port_id_t *, u8 *, u8*, + void *, u8); int qla24xx_fcport_handle_login(struct scsi_qla_host *, fc_port_t *); int qla24xx_detect_sfp(scsi_qla_host_t *vha); int qla24xx_post_gpdb_work(struct scsi_qla_host *, fc_port_t *, u8); @@ -655,10 +655,21 @@ void qla24xx_handle_gpnid_event(scsi_qla_host_t *, struct event_arg *); int qla24xx_post_gpsc_work(struct scsi_qla_host *, fc_port_t *); int qla24xx_async_gpsc(scsi_qla_host_t *, fc_port_t *); +void qla24xx_handle_gpsc_event(scsi_qla_host_t *, struct event_arg *); int qla2x00_mgmt_svr_login(scsi_qla_host_t *); -void qla24xx_handle_gffid_event(scsi_qla_host_t *vha, struct event_arg *ea); +void qla24xx_handle_gffid_event(scsi_qla_host_t *, struct event_arg *); int qla24xx_async_gffid(scsi_qla_host_t *vha, fc_port_t *fcport); const char *sp_to_str(uint16_t); +int qla24xx_async_gpnft(scsi_qla_host_t *, u8); +void qla24xx_async_gpnft_done(scsi_qla_host_t *, srb_t *); +void qla24xx_async_gnnft_done(scsi_qla_host_t *, srb_t *); +int qla24xx_async_gnnid(scsi_qla_host_t *, fc_port_t *); +void qla24xx_handle_gnnid_event(scsi_qla_host_t *, struct event_arg *); +int qla24xx_post_gnnid_work(struct scsi_qla_host *, fc_port_t *); +int qla24xx_post_gfpnid_work(struct scsi_qla_host *, fc_port_t *); +int qla24xx_async_gfpnid(scsi_qla_host_t *, fc_port_t *); +void qla24xx_handle_gfpnid_event(scsi_qla_host_t *vha, struct event_arg *ea); + /* * Global Function Prototypes in qla_attr.c source file. */ diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c index 22702a8f5ce6..643ce1578cbe 100644 --- a/drivers/scsi/qla2xxx/qla_gs.c +++ b/drivers/scsi/qla2xxx/qla_gs.c @@ -2841,6 +2841,9 @@ void qla24xx_handle_gidpn_event(scsi_qla_host_t *vha, struct event_arg *ea) "%s %8phC login state %d\n", __func__, fcport->port_name, fcport->fw_login_state); + if (fcport->disc_state == DSC_DELETE_PEND) + return; + if (ea->sp->gen2 != fcport->login_gen) { /* PLOGI/PRLI/LOGO came in while cmd was out.*/ ql_dbg(ql_dbg_disc, vha, 0x201e, @@ -2859,7 +2862,21 @@ void qla24xx_handle_gidpn_event(scsi_qla_host_t *vha, struct event_arg *ea) /* cable plugged into the same place */ switch (vha->host->active_mode) { case MODE_TARGET: - /* NOOP. let the other guy login to us.*/ + if (fcport->fw_login_state == + DSC_LS_PRLI_COMP) { + u16 data[2]; + /* + * Late RSCN was delivered. + * Remote port already login'ed. + */ + ql_dbg(ql_dbg_disc, vha, 0x201f, + "%s %d %8phC post adisc\n", + __func__, __LINE__, + fcport->port_name); + data[0] = data[1] = 0; + qla2x00_post_async_adisc_work( + vha, fcport, data); + } break; case MODE_INITIATOR: case MODE_DUAL: @@ -2885,6 +2902,7 @@ void qla24xx_handle_gidpn_event(scsi_qla_host_t *vha, struct event_arg *ea) } } else { /* fcport->d_id.b24 != ea->id.b24 */ fcport->d_id.b24 = ea->id.b24; + fcport->id_changed = 1; if (fcport->deleted != QLA_SESS_DELETED) { ql_dbg(ql_dbg_disc, vha, 0x2021, "%s %d %8phC post del sess\n", @@ -3054,6 +3072,38 @@ int qla24xx_post_gpsc_work(struct scsi_qla_host *vha, fc_port_t *fcport) return qla2x00_post_work(vha, e); } +void qla24xx_handle_gpsc_event(scsi_qla_host_t *vha, struct event_arg *ea) +{ + struct fc_port *fcport = ea->fcport; + + ql_dbg(ql_dbg_disc, vha, 0x20d8, + "%s %8phC DS %d LS %d rscn %d|%d login %d|%d lid %d\n", + __func__, fcport->port_name, fcport->disc_state, + fcport->fw_login_state, fcport->last_rscn_gen, fcport->rscn_gen, + fcport->last_login_gen, fcport->login_gen, + fcport->loop_id); + + if (fcport->disc_state == DSC_DELETE_PEND) + return; + + if (ea->sp->gen2 != fcport->login_gen) { + /* target side must have changed it. */ + ql_dbg(ql_dbg_disc, vha, 0x20d3, + "%s %8phC generation changed rscn %d|%d login %d|%d\n", + __func__, fcport->port_name, fcport->last_rscn_gen, + fcport->rscn_gen, fcport->last_login_gen, + fcport->login_gen); + return; + } else if (ea->sp->gen1 != fcport->rscn_gen) { + ql_dbg(ql_dbg_disc, vha, 0x20d4, "%s %d %8phC post gidpn\n", + __func__, __LINE__, fcport->port_name); + qla24xx_post_gidpn_work(vha, fcport); + return; + } + + qla24xx_post_upd_fcport_work(vha, ea->fcport); +} + static void qla24xx_async_gpsc_sp_done(void *s, int res) { struct srb *sp = s; @@ -3120,6 +3170,7 @@ static void qla24xx_async_gpsc_sp_done(void *s, int res) ea.event = FCME_GPSC_DONE; ea.rc = res; ea.fcport = fcport; + ea.sp = sp; qla2x00_fcport_event_handler(vha, &ea); sp->free(sp); @@ -3350,7 +3401,7 @@ void qla24xx_handle_gpnid_event(scsi_qla_host_t *vha, struct event_arg *ea) "%s %d %8phC post new sess\n", __func__, __LINE__, ea->port_name); qla24xx_post_newsess_work(vha, &ea->id, - ea->port_name, NULL); + ea->port_name, NULL, NULL, FC4_TYPE_UNKNOWN); } } } @@ -3640,3 +3691,659 @@ int qla24xx_async_gffid(scsi_qla_host_t *vha, fc_port_t *fcport) fcport->flags &= ~FCF_ASYNC_SENT; return rval; } + +/* GPN_FT + GNN_FT*/ +static int qla2x00_is_a_vp(scsi_qla_host_t *vha, u64 wwn) +{ + struct qla_hw_data *ha = vha->hw; + scsi_qla_host_t *vp; + unsigned long flags; + u64 twwn; + int rc = 0; + + if (!ha->num_vhosts) + return 0; + + spin_lock_irqsave(&ha->vport_slock, flags); + list_for_each_entry(vp, &ha->vp_list, list) { + twwn = wwn_to_u64(vp->port_name); + if (wwn == twwn) { + rc = 1; + break; + } + } + spin_unlock_irqrestore(&ha->vport_slock, flags); + + return rc; +} + +void qla24xx_async_gnnft_done(scsi_qla_host_t *vha, srb_t *sp) +{ + fc_port_t *fcport; + u32 i, rc; + bool found; + u8 fc4type = sp->gen2; + struct fab_scan_rp *rp; + + ql_dbg(ql_dbg_disc, vha, 0xffff, + "%s enter\n", __func__); + + if (sp->gen1 != vha->hw->base_qpair->chip_reset) { + ql_dbg(ql_dbg_disc, vha, 0xffff, + "%s scan stop due to chip reset %x/%x\n", + sp->name, sp->gen1, vha->hw->base_qpair->chip_reset); + goto out; + } + + rc = sp->rc; + if (rc) { + ql_dbg(ql_dbg_disc, vha, 0xffff, + "GPNFT failed. FC4type %x. Rescanning.\n", + fc4type); + set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags); + goto out; + } + + list_for_each_entry(fcport, &vha->vp_fcports, list) + fcport->scan_state = QLA_FCPORT_SCAN; + + for (i = 0; i < vha->hw->max_fibre_devices; i++) { + u64 wwn; + + rp = &vha->scan.l[i]; + found = false; + + wwn = wwn_to_u64(rp->port_name); + if (wwn == 0) + continue; + + if (!memcmp(rp->port_name, vha->port_name, WWN_SIZE)) + continue; + + /* Bypass reserved domain fields. */ + if ((rp->id.b.domain & 0xf0) == 0xf0) + continue; + + /* Bypass virtual ports of the same host. */ + if (qla2x00_is_a_vp(vha, wwn)) + continue; + + list_for_each_entry(fcport, &vha->vp_fcports, list) { + if (memcmp(rp->port_name, fcport->port_name, WWN_SIZE)) + continue; + fcport->scan_state = QLA_FCPORT_FOUND; + fcport->d_id.b24 = rp->id.b24; + found = true; + /* + * If device was not a fabric device before. + */ + if ((fcport->flags & FCF_FABRIC_DEVICE) == 0) { + qla2x00_clear_loop_id(fcport); + fcport->flags |= FCF_FABRIC_DEVICE; + } + break; + } + + if (!found) { + ql_dbg(ql_dbg_disc, vha, 0xffff, + "%s %d %8phC post new sess\n", + __func__, __LINE__, rp->port_name); + qla24xx_post_newsess_work(vha, &rp->id, rp->port_name, + rp->node_name, NULL, fc4type); + } + } + + /* + * Logout all previous fabric dev marked lost, except FCP2 devices. + */ + list_for_each_entry(fcport, &vha->vp_fcports, list) { + if ((fcport->flags & FCF_FABRIC_DEVICE) == 0) + continue; + + if (fcport->scan_state == QLA_FCPORT_SCAN) { + if ((qla_dual_mode_enabled(vha) || + qla_ini_mode_enabled(vha)) && + atomic_read(&fcport->state) == FCS_ONLINE) { + qla2x00_mark_device_lost(vha, fcport, + ql2xplogiabsentdevice, 0); + if (fcport->loop_id != FC_NO_LOOP_ID && + (fcport->flags & FCF_FCP2_DEVICE) == 0 && + fcport->port_type != FCT_INITIATOR && + fcport->port_type != FCT_BROADCAST) { + ql_dbg(ql_dbg_disc, vha, 0x20f0, + "%s %d %8phC post del sess\n", + __func__, __LINE__, + fcport->port_name); + + qlt_schedule_sess_for_deletion_lock + (fcport); + continue; + } + } + } + + if (fcport->scan_state == QLA_FCPORT_FOUND) + qla24xx_fcport_handle_login(vha, fcport); + } + +out: + /* re-use gpnid_done to free resource */ + qla24xx_async_gpnid_done(vha, sp); +} + +static void qla2x00_async_gpnft_gnnft_sp_done(void *s, int res) +{ + struct srb *sp = s; + struct scsi_qla_host *vha = sp->vha; + struct qla_work_evt *e; + struct ct_sns_req *ct_req = + (struct ct_sns_req *)sp->u.iocb_cmd.u.ctarg.req; + struct ct_sns_gpnft_rsp *ct_rsp = + (struct ct_sns_gpnft_rsp *)sp->u.iocb_cmd.u.ctarg.rsp; + struct ct_sns_gpn_ft_data *d = &ct_rsp->entries[0]; + struct fab_scan_rp *rp; + int i, j, k; + u16 cmd = be16_to_cpu(ct_req->command); + + /* gen2 field is holding the fc4type */ + ql_dbg(ql_dbg_disc, vha, 0xffff, + "Async done-%s res %x FC4Type %x\n", + sp->name, res, sp->gen2); + + if (!res) { + port_id_t id; + u64 wwn; + + j = 0; + for (i = 0; i < vha->hw->max_fibre_devices; i++) { + d = &ct_rsp->entries[i]; + + id.b.rsvd_1 = 0; + id.b.domain = d->port_id[0]; + id.b.area = d->port_id[1]; + id.b.al_pa = d->port_id[2]; + wwn = wwn_to_u64(d->port_name); + + if (id.b24 == 0 || wwn == 0) + continue; + + if (cmd == GPN_FT_CMD) { + rp = &vha->scan.l[j]; + rp->id = id; + memcpy(rp->port_name, d->port_name, 8); + j++; + } else {/* GNN_FT_CMD */ + for (k = 0; k < vha->hw->max_fibre_devices; + k++) { + rp = &vha->scan.l[k]; + if (id.b24 == rp->id.b24) { + memcpy(rp->node_name, + d->port_name, 8); + break; + } + } + } + } + } + + if (cmd == GPN_FT_CMD) + e = qla2x00_alloc_work(vha, QLA_EVT_GPNFT_DONE); + else + e = qla2x00_alloc_work(vha, QLA_EVT_GNNFT_DONE); + if (!e) { + /* please ignore kernel warning. Otherwise, we have mem leak. */ + if (sp->u.iocb_cmd.u.ctarg.req) { + dma_free_coherent(&vha->hw->pdev->dev, + sizeof(struct ct_sns_pkt), + sp->u.iocb_cmd.u.ctarg.req, + sp->u.iocb_cmd.u.ctarg.req_dma); + sp->u.iocb_cmd.u.ctarg.req = NULL; + } + if (sp->u.iocb_cmd.u.ctarg.rsp) { + dma_free_coherent(&vha->hw->pdev->dev, + sizeof(struct ct_sns_pkt), + sp->u.iocb_cmd.u.ctarg.rsp, + sp->u.iocb_cmd.u.ctarg.rsp_dma); + sp->u.iocb_cmd.u.ctarg.rsp = NULL; + } + + ql_dbg(ql_dbg_disc, vha, 0xffff, + "Async done-%s unable to alloc work element\n", + sp->name); + sp->free(sp); + set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags); + return; + } + + sp->rc = res; + e->u.iosb.sp = sp; + + qla2x00_post_work(vha, e); +} + +/* + * Get WWNN list for fc4_type + * + * It is assumed the same SRB is re-used from GPNFT to avoid + * mem free & re-alloc + */ +static int qla24xx_async_gnnft(scsi_qla_host_t *vha, struct srb *sp, + u8 fc4_type) +{ + int rval = QLA_FUNCTION_FAILED; + struct ct_sns_req *ct_req; + struct ct_sns_pkt *ct_sns; + + if (!vha->flags.online) + goto done_free_sp; + + if (!sp->u.iocb_cmd.u.ctarg.req || !sp->u.iocb_cmd.u.ctarg.rsp) { + ql_log(ql_log_warn, vha, 0xffff, + "%s: req %p rsp %p are not setup\n", + __func__, sp->u.iocb_cmd.u.ctarg.req, + sp->u.iocb_cmd.u.ctarg.rsp); + WARN_ON(1); + goto done_free_sp; + } + sp->type = SRB_CT_PTHRU_CMD; + sp->name = sp_to_str(SPCN_GNNFT); + sp->gen1 = vha->hw->base_qpair->chip_reset; + sp->gen2 = fc4_type; + qla2x00_init_timer(sp, qla2x00_get_async_timeout(vha) + 2); + + memset(sp->u.iocb_cmd.u.ctarg.rsp, 0, sp->u.iocb_cmd.u.ctarg.rsp_size); + memset(sp->u.iocb_cmd.u.ctarg.req, 0, sp->u.iocb_cmd.u.ctarg.req_size); + + ct_sns = (struct ct_sns_pkt *)sp->u.iocb_cmd.u.ctarg.req; + /* CT_IU preamble */ + ct_req = qla2x00_prep_ct_req(ct_sns, GNN_FT_CMD, + sp->u.iocb_cmd.u.ctarg.rsp_size); + + /* GPN_FT req */ + ct_req->req.gpn_ft.port_type = fc4_type; + + sp->u.iocb_cmd.u.ctarg.req_size = GNN_FT_REQ_SIZE; + sp->u.iocb_cmd.u.ctarg.nport_handle = NPH_SNS; + + sp->u.iocb_cmd.timeout = qla2x00_async_iocb_timeout; + sp->done = qla2x00_async_gpnft_gnnft_sp_done; + + rval = qla2x00_start_sp(sp); + if (rval != QLA_SUCCESS) + goto done_free_sp; + + ql_dbg(ql_dbg_disc, vha, 0xffff, + "Async-%s hdl=%x FC4Type %x.\n", sp->name, + sp->handle, ct_req->req.gpn_ft.port_type); + return rval; + +done_free_sp: + if (sp->u.iocb_cmd.u.ctarg.req) { + dma_free_coherent(&vha->hw->pdev->dev, + sizeof(struct ct_sns_pkt), + sp->u.iocb_cmd.u.ctarg.req, + sp->u.iocb_cmd.u.ctarg.req_dma); + sp->u.iocb_cmd.u.ctarg.req = NULL; + } + if (sp->u.iocb_cmd.u.ctarg.rsp) { + dma_free_coherent(&vha->hw->pdev->dev, + sizeof(struct ct_sns_pkt), + sp->u.iocb_cmd.u.ctarg.rsp, + sp->u.iocb_cmd.u.ctarg.rsp_dma); + sp->u.iocb_cmd.u.ctarg.rsp = NULL; + } + + sp->free(sp); + + return rval; +} /* GNNFT */ + +void qla24xx_async_gpnft_done(scsi_qla_host_t *vha, srb_t *sp) +{ + ql_dbg(ql_dbg_disc, vha, 0xffff, + "%s enter\n", __func__); + del_timer(&sp->u.iocb_cmd.timer); + qla24xx_async_gnnft(vha, sp, sp->gen2); +} + +/* Get WWPN list for certain fc4_type */ +int qla24xx_async_gpnft(scsi_qla_host_t *vha, u8 fc4_type) +{ + int rval = QLA_FUNCTION_FAILED; + struct ct_sns_req *ct_req; + srb_t *sp; + struct ct_sns_pkt *ct_sns; + u32 rspsz; + + if (!vha->flags.online) + return rval; + + sp = qla2x00_get_sp(vha, NULL, GFP_KERNEL); + if (!sp) + return rval; + + + sp->type = SRB_CT_PTHRU_CMD; + sp->name = sp_to_str(SPCN_GPNFT); + sp->gen1 = vha->hw->base_qpair->chip_reset; + sp->gen2 = fc4_type; + qla2x00_init_timer(sp, qla2x00_get_async_timeout(vha) + 2); + + sp->u.iocb_cmd.u.ctarg.req = dma_zalloc_coherent(&vha->hw->pdev->dev, + sizeof(struct ct_sns_pkt), &sp->u.iocb_cmd.u.ctarg.req_dma, + GFP_KERNEL); + if (!sp->u.iocb_cmd.u.ctarg.req) { + ql_log(ql_log_warn, vha, 0xffff, + "Failed to allocate ct_sns request.\n"); + goto done_free_sp; + } + + rspsz = sizeof(struct ct_sns_gpnft_rsp) + + ((vha->hw->max_fibre_devices - 1) * + sizeof(struct ct_sns_gpn_ft_data)); + + sp->u.iocb_cmd.u.ctarg.rsp = dma_zalloc_coherent(&vha->hw->pdev->dev, + rspsz, &sp->u.iocb_cmd.u.ctarg.rsp_dma, GFP_KERNEL); + if (!sp->u.iocb_cmd.u.ctarg.rsp) { + ql_log(ql_log_warn, vha, 0xffff, + "Failed to allocate ct_sns request.\n"); + goto done_free_sp; + } + + memset(vha->scan.l, 0, vha->scan.size); + + ct_sns = (struct ct_sns_pkt *)sp->u.iocb_cmd.u.ctarg.req; + /* CT_IU preamble */ + ct_req = qla2x00_prep_ct_req(ct_sns, GPN_FT_CMD, rspsz); + + /* GPN_FT req */ + ct_req->req.gpn_ft.port_type = fc4_type; + + sp->u.iocb_cmd.u.ctarg.req_size = GPN_FT_REQ_SIZE; + sp->u.iocb_cmd.u.ctarg.rsp_size = rspsz; + sp->u.iocb_cmd.u.ctarg.nport_handle = NPH_SNS; + + sp->u.iocb_cmd.timeout = qla2x00_async_iocb_timeout; + sp->done = qla2x00_async_gpnft_gnnft_sp_done; + + rval = qla2x00_start_sp(sp); + if (rval != QLA_SUCCESS) + goto done_free_sp; + + ql_dbg(ql_dbg_disc, vha, 0xffff, + "Async-%s hdl=%x FC4Type %x.\n", sp->name, + sp->handle, ct_req->req.gpn_ft.port_type); + return rval; + +done_free_sp: + if (sp->u.iocb_cmd.u.ctarg.req) { + dma_free_coherent(&vha->hw->pdev->dev, + sizeof(struct ct_sns_pkt), + sp->u.iocb_cmd.u.ctarg.req, + sp->u.iocb_cmd.u.ctarg.req_dma); + sp->u.iocb_cmd.u.ctarg.req = NULL; + } + if (sp->u.iocb_cmd.u.ctarg.rsp) { + dma_free_coherent(&vha->hw->pdev->dev, + sizeof(struct ct_sns_pkt), + sp->u.iocb_cmd.u.ctarg.rsp, + sp->u.iocb_cmd.u.ctarg.rsp_dma); + sp->u.iocb_cmd.u.ctarg.rsp = NULL; + } + + sp->free(sp); + + return rval; +} + +/* GNN_ID */ +void qla24xx_handle_gnnid_event(scsi_qla_host_t *vha, struct event_arg *ea) +{ + qla24xx_post_gnl_work(vha, ea->fcport); +} + +static void qla2x00_async_gnnid_sp_done(void *s, int res) +{ + struct srb *sp = s; + struct scsi_qla_host *vha = sp->vha; + fc_port_t *fcport = sp->fcport; + u8 *node_name = fcport->ct_desc.ct_sns->p.rsp.rsp.gnn_id.node_name; + struct event_arg ea; + u64 wwnn; + + fcport->flags &= ~FCF_ASYNC_SENT; + wwnn = wwn_to_u64(node_name); + if (wwnn) + memcpy(fcport->node_name, node_name, WWN_SIZE); + + memset(&ea, 0, sizeof(ea)); + ea.fcport = fcport; + ea.sp = sp; + ea.rc = res; + ea.event = FCME_GNNID_DONE; + + ql_dbg(ql_dbg_disc, vha, 0x204f, + "Async done-%s res %x, WWPN %8phC %8phC\n", + sp->name, res, fcport->port_name, fcport->node_name); + + qla2x00_fcport_event_handler(vha, &ea); + + sp->free(sp); +} + +int qla24xx_async_gnnid(scsi_qla_host_t *vha, fc_port_t *fcport) +{ + int rval = QLA_FUNCTION_FAILED; + struct ct_sns_req *ct_req; + srb_t *sp; + + if (!vha->flags.online) + goto done; + + fcport->flags |= FCF_ASYNC_SENT; + fcport->disc_state = DSC_GNN_ID; + sp = qla2x00_get_sp(vha, fcport, GFP_ATOMIC); + if (!sp) + goto done; + + sp->type = SRB_CT_PTHRU_CMD; + sp->name = sp_to_str(SPCN_GNNID); + sp->gen1 = fcport->rscn_gen; + sp->gen2 = fcport->login_gen; + + qla2x00_init_timer(sp, qla2x00_get_async_timeout(vha) + 2); + + /* CT_IU preamble */ + ct_req = qla2x00_prep_ct_req(fcport->ct_desc.ct_sns, GNN_ID_CMD, + GNN_ID_RSP_SIZE); + + /* GNN_ID req */ + ct_req->req.port_id.port_id[0] = fcport->d_id.b.domain; + ct_req->req.port_id.port_id[1] = fcport->d_id.b.area; + ct_req->req.port_id.port_id[2] = fcport->d_id.b.al_pa; + + + /* req & rsp use the same buffer */ + sp->u.iocb_cmd.u.ctarg.req = fcport->ct_desc.ct_sns; + sp->u.iocb_cmd.u.ctarg.req_dma = fcport->ct_desc.ct_sns_dma; + sp->u.iocb_cmd.u.ctarg.rsp = fcport->ct_desc.ct_sns; + sp->u.iocb_cmd.u.ctarg.rsp_dma = fcport->ct_desc.ct_sns_dma; + sp->u.iocb_cmd.u.ctarg.req_size = GNN_ID_REQ_SIZE; + sp->u.iocb_cmd.u.ctarg.rsp_size = GNN_ID_RSP_SIZE; + sp->u.iocb_cmd.u.ctarg.nport_handle = NPH_SNS; + + sp->u.iocb_cmd.timeout = qla2x00_async_iocb_timeout; + sp->done = qla2x00_async_gnnid_sp_done; + + rval = qla2x00_start_sp(sp); + if (rval != QLA_SUCCESS) + goto done_free_sp; + ql_dbg(ql_dbg_disc, vha, 0xffff, + "Async-%s - %8phC hdl=%x loopid=%x portid %06x.\n", + sp->name, fcport->port_name, + sp->handle, fcport->loop_id, fcport->d_id.b24); + return rval; + +done_free_sp: + sp->free(sp); +done: + fcport->flags &= ~FCF_ASYNC_SENT; + return rval; +} + +int qla24xx_post_gnnid_work(struct scsi_qla_host *vha, fc_port_t *fcport) +{ + struct qla_work_evt *e; + int ls; + + ls = atomic_read(&vha->loop_state); + if (((ls != LOOP_READY) && (ls != LOOP_UP)) || + test_bit(UNLOADING, &vha->dpc_flags)) + return 0; + + e = qla2x00_alloc_work(vha, QLA_EVT_GNNID); + if (!e) + return QLA_FUNCTION_FAILED; + + e->u.fcport.fcport = fcport; + return qla2x00_post_work(vha, e); +} + +/* GPFN_ID */ +void qla24xx_handle_gfpnid_event(scsi_qla_host_t *vha, struct event_arg *ea) +{ + fc_port_t *fcport = ea->fcport; + + ql_dbg(ql_dbg_disc, vha, 0xffff, + "%s %d %8phC post gpsc fcp_cnt %d\n", + __func__, __LINE__, fcport->port_name, + vha->fcport_count); + + if (fcport->disc_state == DSC_DELETE_PEND) + return; + + if (ea->sp->gen2 != fcport->login_gen) { + /* target side must have changed it. */ + ql_dbg(ql_dbg_disc, vha, 0x20d3, + "%s %8phC generation changed rscn %d|%d login %d|%d\n", + __func__, fcport->port_name, fcport->last_rscn_gen, + fcport->rscn_gen, fcport->last_login_gen, + fcport->login_gen); + return; + } else if (ea->sp->gen1 != fcport->rscn_gen) { + ql_dbg(ql_dbg_disc, vha, 0x20d4, "%s %d %8phC post gidpn\n", + __func__, __LINE__, fcport->port_name); + qla24xx_post_gidpn_work(vha, fcport); + return; + } + + qla24xx_post_gpsc_work(vha, fcport); +} + +static void qla2x00_async_gfpnid_sp_done(void *s, int res) +{ + struct srb *sp = s; + struct scsi_qla_host *vha = sp->vha; + fc_port_t *fcport = sp->fcport; + u8 *fpn = fcport->ct_desc.ct_sns->p.rsp.rsp.gfpn_id.port_name; + struct event_arg ea; + u64 wwn; + + fcport->flags &= ~FCF_ASYNC_SENT; + wwn = wwn_to_u64(fpn); + if (wwn) + memcpy(fcport->fabric_port_name, fpn, WWN_SIZE); + + memset(&ea, 0, sizeof(ea)); + ea.fcport = fcport; + ea.sp = sp; + ea.rc = res; + ea.event = FCME_GFPNID_DONE; + + ql_dbg(ql_dbg_disc, vha, 0x204f, + "Async done-%s res %x, WWPN %8phC %8phC\n", + sp->name, res, fcport->port_name, fcport->fabric_port_name); + + qla2x00_fcport_event_handler(vha, &ea); + + sp->free(sp); +} + +int qla24xx_async_gfpnid(scsi_qla_host_t *vha, fc_port_t *fcport) +{ + int rval = QLA_FUNCTION_FAILED; + struct ct_sns_req *ct_req; + srb_t *sp; + + if (!vha->flags.online) + goto done; + + fcport->flags |= FCF_ASYNC_SENT; + fcport->disc_state = DSC_GFPN_ID; + sp = qla2x00_get_sp(vha, fcport, GFP_ATOMIC); + if (!sp) + goto done; + + sp->type = SRB_CT_PTHRU_CMD; + sp->name = sp_to_str(SPCN_GFPNID); + sp->gen1 = fcport->rscn_gen; + sp->gen2 = fcport->login_gen; + + qla2x00_init_timer(sp, qla2x00_get_async_timeout(vha) + 2); + + /* CT_IU preamble */ + ct_req = qla2x00_prep_ct_req(fcport->ct_desc.ct_sns, GFPN_ID_CMD, + GFPN_ID_RSP_SIZE); + + /* GFPN_ID req */ + ct_req->req.port_id.port_id[0] = fcport->d_id.b.domain; + ct_req->req.port_id.port_id[1] = fcport->d_id.b.area; + ct_req->req.port_id.port_id[2] = fcport->d_id.b.al_pa; + + + /* req & rsp use the same buffer */ + sp->u.iocb_cmd.u.ctarg.req = fcport->ct_desc.ct_sns; + sp->u.iocb_cmd.u.ctarg.req_dma = fcport->ct_desc.ct_sns_dma; + sp->u.iocb_cmd.u.ctarg.rsp = fcport->ct_desc.ct_sns; + sp->u.iocb_cmd.u.ctarg.rsp_dma = fcport->ct_desc.ct_sns_dma; + sp->u.iocb_cmd.u.ctarg.req_size = GFPN_ID_REQ_SIZE; + sp->u.iocb_cmd.u.ctarg.rsp_size = GFPN_ID_RSP_SIZE; + sp->u.iocb_cmd.u.ctarg.nport_handle = NPH_SNS; + + sp->u.iocb_cmd.timeout = qla2x00_async_iocb_timeout; + sp->done = qla2x00_async_gfpnid_sp_done; + + rval = qla2x00_start_sp(sp); + if (rval != QLA_SUCCESS) + goto done_free_sp; + + ql_dbg(ql_dbg_disc, vha, 0xffff, + "Async-%s - %8phC hdl=%x loopid=%x portid %06x.\n", + sp->name, fcport->port_name, + sp->handle, fcport->loop_id, fcport->d_id.b24); + return rval; + +done_free_sp: + sp->free(sp); +done: + fcport->flags &= ~FCF_ASYNC_SENT; + return rval; +} + +int qla24xx_post_gfpnid_work(struct scsi_qla_host *vha, fc_port_t *fcport) +{ + struct qla_work_evt *e; + int ls; + + ls = atomic_read(&vha->loop_state); + if (((ls != LOOP_READY) && (ls != LOOP_UP)) || + test_bit(UNLOADING, &vha->dpc_flags)) + return 0; + + e = qla2x00_alloc_work(vha, QLA_EVT_GFPNID); + if (!e) + return QLA_FUNCTION_FAILED; + + e->u.fcport.fcport = fcport; + return qla2x00_post_work(vha, e); +} diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index b4a96c80853f..cdcd84278fd0 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -41,7 +41,7 @@ static void qla24xx_handle_plogi_done_event(struct scsi_qla_host *, struct event_arg *); static void qla24xx_handle_prli_done_event(struct scsi_qla_host *, struct event_arg *); -static void qla24xx_handle_gpdb_event(scsi_qla_host_t *, struct event_arg *); +static void __qla24xx_handle_gpdb_event(scsi_qla_host_t *, struct event_arg *); /* SRB Extensions ---------------------------------------------------------- */ @@ -187,9 +187,11 @@ qla2x00_async_login(struct scsi_qla_host *vha, fc_port_t *fcport, fcport->flags |= FCF_ASYNC_SENT; fcport->logout_completed = 0; - + fcport->disc_state = DSC_LOGIN_PEND; sp->type = SRB_LOGIN_CMD; sp->name = sp_to_str(SPCN_LOGIN); + sp->gen1 = fcport->rscn_gen; + sp->gen2 = fcport->login_gen; qla2x00_init_timer(sp, qla2x00_get_async_timeout(vha) + 2); lio = &sp->u.iocb_cmd; @@ -336,7 +338,36 @@ qla2x00_async_prlo(struct scsi_qla_host *vha, fc_port_t *fcport) static void qla24xx_handle_adisc_event(scsi_qla_host_t *vha, struct event_arg *ea) { - qla24xx_handle_gpdb_event(vha, ea); + if (ea->rc) { + ql_dbg(ql_dbg_disc, vha, 0x2066, + "%s %8phC: adisc fail: post delete\n", + __func__, ea->fcport->port_name); + qlt_schedule_sess_for_deletion(ea->fcport, 1); + return; + } + ql_dbg(ql_dbg_disc, vha, 0x20d2, + "%s %8phC DS %d LS %d\n", __func__, ea->fcport->port_name, + ea->fcport->disc_state, ea->fcport->fw_login_state); + + if (ea->fcport->disc_state == DSC_DELETE_PEND) + return; + + if (ea->sp->gen2 != ea->fcport->login_gen) { + /* target side must have changed it. */ + ql_dbg(ql_dbg_disc, vha, 0x20d3, + "%s %8phC generation changed rscn %d|%d login %d|%d\n", + __func__, ea->fcport->port_name, ea->fcport->last_rscn_gen, + ea->fcport->rscn_gen, ea->fcport->last_login_gen, + ea->fcport->login_gen); + return; + } else if (ea->sp->gen1 != ea->fcport->rscn_gen) { + ql_dbg(ql_dbg_disc, vha, 0x20d4, "%s %d %8phC post gidpn\n", + __func__, __LINE__, ea->fcport->port_name); + qla24xx_post_gidpn_work(vha, ea->fcport); + return; + } + + __qla24xx_handle_gpdb_event(vha, ea); } static void @@ -412,10 +443,14 @@ static void qla24xx_handle_gnl_done_event(scsi_qla_host_t *vha, u16 i, n, found = 0, loop_id; port_id_t id; u64 wwn; - u8 opt = 0, current_login_state; + u16 data[2]; + u8 current_login_state; fcport = ea->fcport; + if (fcport->disc_state == DSC_DELETE_PEND) + return; + if (ea->rc) { /* rval */ if (fcport->login_retry == 0) { fcport->login_retry = vha->hw->login_retry_count; @@ -509,8 +544,14 @@ static void qla24xx_handle_gnl_done_event(scsi_qla_host_t *vha, ql_dbg(ql_dbg_disc, vha, 0x20e4, "%s %d %8phC post gpdb\n", __func__, __LINE__, fcport->port_name); - opt = PDO_FORCE_ADISC; - qla24xx_post_gpdb_work(vha, fcport, opt); + + if ((e->prli_svc_param_word_3[0] & BIT_4) == 0) + fcport->port_type = FCT_INITIATOR; + else + fcport->port_type = FCT_TARGET; + + data[0] = data[1] = 0; + qla2x00_post_async_adisc_work(vha, fcport, data); break; case DSC_LS_PORT_UNAVAIL: default: @@ -575,6 +616,7 @@ qla24xx_async_gnl_sp_done(void *s, int res) struct get_name_list_extended *e; u64 wwn; struct list_head h; + bool found = false; ql_dbg(ql_dbg_disc, vha, 0x20e7, "Async done-%s res %x mb[1]=%x mb[2]=%x \n", @@ -624,6 +666,38 @@ qla24xx_async_gnl_sp_done(void *s, int res) qla2x00_fcport_event_handler(vha, &ea); } + /* create new fcport if fw has knowledge of new sessions */ + for (i = 0; i < n; i++) { + port_id_t id; + u64 wwnn; + + e = &vha->gnl.l[i]; + wwn = wwn_to_u64(e->port_name); + + found = false; + list_for_each_entry_safe(fcport, tf, &vha->vp_fcports, list) { + if (!memcmp((u8 *)&wwn, fcport->port_name, + WWN_SIZE)) { + found = true; + break; + } + } + + id.b.domain = e->port_id[0]; + id.b.area = e->port_id[1]; + id.b.al_pa = e->port_id[2]; + id.b.rsvd_1 = 0; + + if (!found && wwn && !IS_SW_RESV_ADDR(id)) { + ql_dbg(ql_dbg_disc, vha, 0x2065, + "%s %d %8phC post new sess\n", + __func__, __LINE__, (u8 *)&wwn); + wwnn = wwn_to_u64(e->node_name); + qla24xx_post_newsess_work(vha, &id, (u8 *)&wwn, + (u8 *)&wwnn, NULL, FC4_TYPE_UNKNOWN); + } + } + spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags); sp->free(sp); @@ -718,10 +792,8 @@ void qla24xx_async_gpdb_sp_done(void *s, int res) struct srb *sp = s; struct scsi_qla_host *vha = sp->vha; struct qla_hw_data *ha = vha->hw; - struct port_database_24xx *pd; fc_port_t *fcport = sp->fcport; u16 *mb = sp->u.iocb_cmd.u.mbx.in_mb; - int rval = QLA_SUCCESS; struct event_arg ea; ql_dbg(ql_dbg_disc, vha, 0x20db, @@ -730,19 +802,8 @@ void qla24xx_async_gpdb_sp_done(void *s, int res) fcport->flags &= ~FCF_ASYNC_SENT; - if (res) { - rval = res; - goto gpd_error_out; - } - - pd = (struct port_database_24xx *)sp->u.iocb_cmd.u.mbx.in; - - rval = __qla24xx_parse_gpdb(vha, fcport, pd); - -gpd_error_out: memset(&ea, 0, sizeof(ea)); ea.event = FCME_GPDB_DONE; - ea.rc = rval; ea.fcport = fcport; ea.sp = sp; @@ -937,41 +998,10 @@ int qla24xx_async_gpdb(struct scsi_qla_host *vha, fc_port_t *fcport, u8 opt) } static -void qla24xx_handle_gpdb_event(scsi_qla_host_t *vha, struct event_arg *ea) +void __qla24xx_handle_gpdb_event(scsi_qla_host_t *vha, struct event_arg *ea) { - int rval = ea->rc; - fc_port_t *fcport = ea->fcport; unsigned long flags; - fcport->flags &= ~FCF_ASYNC_SENT; - - ql_dbg(ql_dbg_disc, vha, 0x20d2, - "%s %8phC DS %d LS %d rval %d\n", __func__, fcport->port_name, - fcport->disc_state, fcport->fw_login_state, rval); - - if (ea->sp->gen2 != fcport->login_gen) { - /* target side must have changed it. */ - ql_dbg(ql_dbg_disc, vha, 0x20d3, - "%s %8phC generation changed rscn %d|%d login %d|%d \n", - __func__, fcport->port_name, fcport->last_rscn_gen, - fcport->rscn_gen, fcport->last_login_gen, - fcport->login_gen); - set_bit(RELOGIN_NEEDED, &vha->dpc_flags); - return; - } else if (ea->sp->gen1 != fcport->rscn_gen) { - ql_dbg(ql_dbg_disc, vha, 0x20d4, "%s %d %8phC post gidpn\n", - __func__, __LINE__, fcport->port_name); - qla24xx_post_gidpn_work(vha, fcport); - return; - } - - if (rval != QLA_SUCCESS) { - ql_dbg(ql_dbg_disc, vha, 0x20d5, "%s %d %8phC post del sess\n", - __func__, __LINE__, fcport->port_name); - qlt_schedule_sess_for_deletion_lock(fcport); - return; - } - spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags); ea->fcport->login_gen++; ea->fcport->deleted = 0; @@ -985,32 +1015,81 @@ void qla24xx_handle_gpdb_event(scsi_qla_host_t *vha, struct event_arg *ea) !vha->hw->flags.gpsc_supported) { ql_dbg(ql_dbg_disc, vha, 0x20d6, "%s %d %8phC post upd_fcport fcp_cnt %d\n", - __func__, __LINE__, fcport->port_name, + __func__, __LINE__, ea->fcport->port_name, vha->fcport_count); - qla24xx_post_upd_fcport_work(vha, fcport); + qla24xx_post_upd_fcport_work(vha, ea->fcport); } else { - ql_dbg(ql_dbg_disc, vha, 0x20d7, - "%s %d %8phC post gpsc fcp_cnt %d\n", - __func__, __LINE__, fcport->port_name, - vha->fcport_count); - - qla24xx_post_gpsc_work(vha, fcport); + if (ea->fcport->id_changed) { + ea->fcport->id_changed = 0; + ql_dbg(ql_dbg_disc, vha, 0x20d7, + "%s %d %8phC post gfpnid fcp_cnt %d\n", + __func__, __LINE__, ea->fcport->port_name, + vha->fcport_count); + qla24xx_post_gfpnid_work(vha, ea->fcport); + } else { + ql_dbg(ql_dbg_disc, vha, 0x20d7, + "%s %d %8phC post gpsc fcp_cnt %d\n", + __func__, __LINE__, ea->fcport->port_name, + vha->fcport_count); + qla24xx_post_gpsc_work(vha, ea->fcport); + } } } else if (ea->fcport->login_succ) { /* * We have an existing session. A late RSCN delivery * must have triggered the session to be re-validate. - * session is still valid. + * Session is still valid. */ ql_dbg(ql_dbg_disc, vha, 0x20d6, "%s %d %8phC session revalidate success\n", - __func__, __LINE__, fcport->port_name); - fcport->disc_state = DSC_LOGIN_COMPLETE; + __func__, __LINE__, ea->fcport->port_name); + ea->fcport->disc_state = DSC_LOGIN_COMPLETE; } spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags); -} /* gpdb event */ +} +static +void qla24xx_handle_gpdb_event(scsi_qla_host_t *vha, struct event_arg *ea) +{ + int rval = ea->rc; + fc_port_t *fcport = ea->fcport; + struct port_database_24xx *pd; + struct srb *sp = ea->sp; + + pd = (struct port_database_24xx *)sp->u.iocb_cmd.u.mbx.in; + + fcport->flags &= ~FCF_ASYNC_SENT; + + ql_dbg(ql_dbg_disc, vha, 0x20d2, + "%s %8phC DS %d LS %d rval %d\n", __func__, fcport->port_name, + fcport->disc_state, pd->current_login_state, rval); + + if (fcport->disc_state == DSC_DELETE_PEND) + return; + + switch (pd->current_login_state) { + case PDS_PRLI_COMPLETE: + __qla24xx_parse_gpdb(vha, fcport, pd); + break; + case PDS_PLOGI_PENDING: + case PDS_PLOGI_COMPLETE: + case PDS_PRLI_PENDING: + case PDS_PRLI2_PENDING: + ql_dbg(ql_dbg_disc, vha, 0x20d5, "%s %d %8phC relogin needed\n", + __func__, __LINE__, fcport->port_name); + set_bit(RELOGIN_NEEDED, &vha->dpc_flags); + return; + case PDS_LOGO_PENDING: + case PDS_PORT_UNAVAILABLE: + default: + ql_dbg(ql_dbg_disc, vha, 0x20d5, "%s %d %8phC post del sess\n", + __func__, __LINE__, fcport->port_name); + qlt_schedule_sess_for_deletion_lock(fcport); + return; + } + __qla24xx_handle_gpdb_event(vha, ea); +} /* gpdb event */ static void qla_chk_n2n_b4_login(struct scsi_qla_host *vha, fc_port_t *fcport) { @@ -1051,21 +1130,21 @@ static void qla_chk_n2n_b4_login(struct scsi_qla_host *vha, fc_port_t *fcport) int qla24xx_fcport_handle_login(struct scsi_qla_host *vha, fc_port_t *fcport) { u16 data[2]; - if (fcport->login_retry == 0) - return 0; - - if (fcport->scan_state != QLA_FCPORT_FOUND) - return 0; + u64 wwn; ql_dbg(ql_dbg_disc, vha, 0x20d8, - "%s %8phC DS %d LS %d P %d fl %x confl %p rscn %d|%d login %d|%d retry %d lid %d\n", + "%s %8phC DS %d LS %d P %d fl %x confl %p rscn %d|%d login %d|%d retry %d lid %d scan %d\n", __func__, fcport->port_name, fcport->disc_state, fcport->fw_login_state, fcport->login_pause, fcport->flags, fcport->conflict, fcport->last_rscn_gen, fcport->rscn_gen, fcport->last_login_gen, fcport->login_gen, fcport->login_retry, - fcport->loop_id); + fcport->loop_id, fcport->scan_state); - fcport->login_retry--; + if (fcport->login_retry == 0) + return 0; + + if (fcport->scan_state != QLA_FCPORT_FOUND) + return 0; if ((fcport->fw_login_state == DSC_LS_PLOGI_PEND) || (fcport->fw_login_state == DSC_LS_PRLI_PEND)) @@ -1087,9 +1166,17 @@ int qla24xx_fcport_handle_login(struct scsi_qla_host *vha, fc_port_t *fcport) return 0; } + fcport->login_retry--; + switch (fcport->disc_state) { case DSC_DELETED: - if (fcport->loop_id == FC_NO_LOOP_ID) { + wwn = wwn_to_u64(fcport->node_name); + if (wwn == 0) { + ql_dbg(ql_dbg_disc, vha, 0xffff, + "%s %d %8phC post GNNID\n", + __func__, __LINE__, fcport->port_name); + qla24xx_post_gnnid_work(vha, fcport); + } else if (fcport->loop_id == FC_NO_LOOP_ID) { ql_dbg(ql_dbg_disc, vha, 0x20bd, "%s %d %8phC post gnl\n", __func__, __LINE__, fcport->port_name); @@ -1160,7 +1247,7 @@ void qla24xx_handle_rscn_event(fc_port_t *fcport, struct event_arg *ea) } int qla24xx_post_newsess_work(struct scsi_qla_host *vha, port_id_t *id, - u8 *port_name, void *pla) + u8 *port_name, u8 *node_name, void *pla, u8 fc4_type) { struct qla_work_evt *e; e = qla2x00_alloc_work(vha, QLA_EVT_NEW_SESS); @@ -1169,37 +1256,15 @@ int qla24xx_post_newsess_work(struct scsi_qla_host *vha, port_id_t *id, e->u.new_sess.id = *id; e->u.new_sess.pla = pla; + e->u.new_sess.fc4_type = fc4_type; memcpy(e->u.new_sess.port_name, port_name, WWN_SIZE); + if (node_name) + memcpy(e->u.new_sess.node_name, node_name, WWN_SIZE); return qla2x00_post_work(vha, e); } static -int qla24xx_handle_delete_done_event(scsi_qla_host_t *vha, - struct event_arg *ea) -{ - fc_port_t *fcport = ea->fcport; - - if (test_bit(UNLOADING, &vha->dpc_flags)) - return 0; - - switch (vha->host->active_mode) { - case MODE_INITIATOR: - case MODE_DUAL: - if (fcport->scan_state == QLA_FCPORT_FOUND) - qla24xx_fcport_handle_login(vha, fcport); - break; - - case MODE_TARGET: - default: - /* no-op */ - break; - } - - return 0; -} - -static void qla24xx_handle_relogin_event(scsi_qla_host_t *vha, struct event_arg *ea) { @@ -1264,6 +1329,7 @@ void qla2x00_fcport_event_handler(scsi_qla_host_t *vha, struct event_arg *ea) case FCME_GIDPN_DONE: case FCME_GPSC_DONE: case FCME_GPNID_DONE: + case FCME_GNNID_DONE: if (test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags) || test_bit(LOOP_RESYNC_ACTIVE, &vha->dpc_flags)) return; @@ -1340,7 +1406,7 @@ void qla2x00_fcport_event_handler(scsi_qla_host_t *vha, struct event_arg *ea) qla24xx_handle_gnl_done_event(vha, ea); break; case FCME_GPSC_DONE: - qla24xx_post_upd_fcport_work(vha, ea->fcport); + qla24xx_handle_gpsc_event(vha, ea); break; case FCME_PLOGI_DONE: /* Initiator side sent LLIOCB */ qla24xx_handle_plogi_done_event(vha, ea); @@ -1357,12 +1423,15 @@ void qla2x00_fcport_event_handler(scsi_qla_host_t *vha, struct event_arg *ea) case FCME_GFFID_DONE: qla24xx_handle_gffid_event(vha, ea); break; - case FCME_DELETE_DONE: - qla24xx_handle_delete_done_event(vha, ea); - break; case FCME_ADISC_DONE: qla24xx_handle_adisc_event(vha, ea); break; + case FCME_GNNID_DONE: + qla24xx_handle_gnnid_event(vha, ea); + break; + case FCME_GFPNID_DONE: + qla24xx_handle_gfpnid_event(vha, ea); + break; default: BUG_ON(1); break; @@ -1571,6 +1640,33 @@ qla24xx_handle_plogi_done_event(struct scsi_qla_host *vha, struct event_arg *ea) u16 lid; struct fc_port *conflict_fcport; unsigned long flags; + struct fc_port *fcport = ea->fcport; + + if ((fcport->fw_login_state == DSC_LS_PLOGI_PEND) || + (fcport->fw_login_state == DSC_LS_PRLI_PEND)) { + ql_dbg(ql_dbg_disc, vha, 0x20ea, + "%s %d %8phC Remote is trying to login\n", + __func__, __LINE__, fcport->port_name); + return; + } + + if (fcport->disc_state == DSC_DELETE_PEND) + return; + + if (ea->sp->gen2 != fcport->login_gen) { + /* target side must have changed it. */ + ql_dbg(ql_dbg_disc, vha, 0x20d3, + "%s %8phC generation changed rscn %d|%d login %d|%d\n", + __func__, fcport->port_name, fcport->last_rscn_gen, + fcport->rscn_gen, fcport->last_login_gen, + fcport->login_gen); + return; + } else if (ea->sp->gen1 != fcport->rscn_gen) { + ql_dbg(ql_dbg_disc, vha, 0x20d4, "%s %d %8phC post gidpn\n", + __func__, __LINE__, fcport->port_name); + qla24xx_post_gidpn_work(vha, fcport); + return; + } switch (ea->data[0]) { case MBS_COMMAND_COMPLETE: @@ -5163,7 +5259,14 @@ qla2x00_configure_fabric(scsi_qla_host_t *vha) * will be newer than discovery_gen. */ qlt_do_generation_tick(vha, &discovery_gen); - rval = qla2x00_find_all_fabric_devs(vha); + if (USE_ASYNC_SCAN(ha)) { + rval = QLA_SUCCESS; + rval = qla24xx_async_gpnft(vha, FC4_TYPE_FCP_SCSI); + if (rval) + set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags); + } else { + rval = qla2x00_find_all_fabric_devs(vha); + } if (rval != QLA_SUCCESS) break; } while (0); diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index acf6c7c0f2c8..68587e631f60 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -3905,7 +3905,10 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha, id.b.area = rptid_entry->u.f2.remote_nport_id[1]; id.b.domain = rptid_entry->u.f2.remote_nport_id[2]; qla24xx_post_newsess_work(vha, &id, - rptid_entry->u.f2.port_name, NULL); + rptid_entry->u.f2.port_name, + rptid_entry->u.f2.node_name, + NULL, + FC4_TYPE_UNKNOWN); } } } diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 4e7763848d81..cab39a6d9776 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -3628,6 +3628,8 @@ qla2x00_remove_one(struct pci_dev *pdev) dma_free_coherent(&ha->pdev->dev, base_vha->gnl.size, base_vha->gnl.l, base_vha->gnl.ldma); + vfree(base_vha->scan.l); + if (IS_QLAFX00(ha)) qlafx00_driver_shutdown(base_vha, 20); @@ -4576,6 +4578,18 @@ struct scsi_qla_host *qla2x00_create_host(struct scsi_host_template *sht, return NULL; } + /* todo: what about ext login? */ + vha->scan.size = ha->max_fibre_devices * sizeof(struct fab_scan_rp); + vha->scan.l = vmalloc(vha->scan.size); + if (!vha->scan.l) { + ql_log(ql_log_fatal, vha, 0xd04a, + "Alloc failed for scan database.\n"); + dma_free_coherent(&ha->pdev->dev, vha->gnl.size, + vha->gnl.l, vha->gnl.ldma); + scsi_remove_host(vha->host); + return NULL; + } + sprintf(vha->host_str, "%s_%ld", QLA2XXX_DRIVER_NAME, vha->host_no); ql_dbg(ql_dbg_init, vha, 0x0041, "Allocated the host=%p hw=%p vha=%p dev_name=%s", @@ -4749,6 +4763,7 @@ void qla24xx_create_new_sess(struct scsi_qla_host *vha, struct qla_work_evt *e) struct qlt_plogi_ack_t *pla = (struct qlt_plogi_ack_t *)e->u.new_sess.pla; uint8_t free_fcport = 0; + u64 wwn; ql_dbg(ql_dbg_disc, vha, 0xffff, "%s %d %8phC enter\n", @@ -4774,9 +4789,10 @@ void qla24xx_create_new_sess(struct scsi_qla_host *vha, struct qla_work_evt *e) fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL); if (fcport) { fcport->d_id = e->u.new_sess.id; - fcport->scan_state = QLA_FCPORT_FOUND; fcport->flags |= FCF_FABRIC_DEVICE; fcport->fw_login_state = DSC_LS_PLOGI_PEND; + if (e->u.new_sess.fc4_type == FC4_TYPE_FCP_SCSI) + fcport->fc4_type = FC4_TYPE_FCP_SCSI; memcpy(fcport->port_name, e->u.new_sess.port_name, WWN_SIZE); @@ -4791,7 +4807,7 @@ void qla24xx_create_new_sess(struct scsi_qla_host *vha, struct qla_work_evt *e) } spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags); - /* search again to make sure one else got ahead */ + /* search again to make sure no one else got ahead */ tfcp = qla2x00_find_fcport_by_wwpn(vha, e->u.new_sess.port_name, 1); if (tfcp) { @@ -4818,6 +4834,10 @@ void qla24xx_create_new_sess(struct scsi_qla_host *vha, struct qla_work_evt *e) if (N2N_TOPO(vha->hw)) fcport->flags &= ~FCF_FABRIC_DEVICE; + fcport->id_changed = 1; + fcport->scan_state = QLA_FCPORT_FOUND; + memcpy(fcport->node_name, e->u.new_sess.node_name, WWN_SIZE); + if (pla) { if (pla->iocb.u.isp24.status_subcode == ELS_PRLI) { u16 wd3_lo; @@ -4870,7 +4890,13 @@ void qla24xx_create_new_sess(struct scsi_qla_host *vha, struct qla_work_evt *e) } } spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags); - qla24xx_async_gnl(vha, fcport); + + wwn = wwn_to_u64(fcport->node_name); + + if (!wwn) + qla24xx_async_gnnid(vha, fcport); + else + qla24xx_async_gnl(vha, fcport); } } @@ -4969,6 +4995,21 @@ qla2x00_do_work(struct scsi_qla_host *vha) qla2x00_async_prlo_done(vha, e->u.logio.fcport, e->u.logio.data); break; + case QLA_EVT_GPNFT: + qla24xx_async_gpnft(vha, e->u.gpnft.fc4_type); + break; + case QLA_EVT_GPNFT_DONE: + qla24xx_async_gpnft_done(vha, e->u.iosb.sp); + break; + case QLA_EVT_GNNFT_DONE: + qla24xx_async_gnnft_done(vha, e->u.iosb.sp); + break; + case QLA_EVT_GNNID: + qla24xx_async_gnnid(vha, e->u.fcport.fcport); + break; + case QLA_EVT_GFPNID: + qla24xx_async_gfpnid(vha, e->u.fcport.fcport); + break; } if (e->flags & QLA_EVT_FLAG_FREE) kfree(e); diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c index 002fe05dd344..48e0a12dca61 100644 --- a/drivers/scsi/qla2xxx/qla_target.c +++ b/drivers/scsi/qla2xxx/qla_target.c @@ -969,7 +969,6 @@ static void qlt_free_session_done(struct work_struct *work) struct qla_hw_data *ha = vha->hw; unsigned long flags; bool logout_started = false; - struct event_arg ea; scsi_qla_host_t *base_vha; struct qlt_plogi_ack_t *own = sess->plogi_link[QLT_PLOGI_LINK_SAME_WWN]; @@ -1121,11 +1120,18 @@ static void qlt_free_session_done(struct work_struct *work) if (test_bit(PFLG_DRIVER_REMOVING, &base_vha->pci_flags)) return; - if (!tgt || !tgt->tgt_stop) { - memset(&ea, 0, sizeof(ea)); - ea.event = FCME_DELETE_DONE; - ea.fcport = sess; - qla2x00_fcport_event_handler(vha, &ea); + if ((!tgt || !tgt->tgt_stop) && !LOOP_TRANSITION(vha)) { + switch (vha->host->active_mode) { + case MODE_INITIATOR: + case MODE_DUAL: + set_bit(RELOGIN_NEEDED, &vha->dpc_flags); + qla2xxx_wake_dpc(vha); + break; + case MODE_TARGET: + default: + /* no-op */ + break; + } } } @@ -4337,6 +4343,7 @@ static int qlt_handle_cmd_for_atio(struct scsi_qla_host *vha, struct fc_port *sess; struct qla_tgt_cmd *cmd; unsigned long flags; + port_id_t id; if (unlikely(tgt->tgt_stop)) { ql_dbg(ql_dbg_io, vha, 0x3061, @@ -4344,6 +4351,12 @@ static int qlt_handle_cmd_for_atio(struct scsi_qla_host *vha, return -EFAULT; } + id.b.al_pa = atio->u.isp24.fcp_hdr.s_id[2]; + id.b.area = atio->u.isp24.fcp_hdr.s_id[1]; + id.b.domain = atio->u.isp24.fcp_hdr.s_id[0]; + if (IS_SW_RESV_ADDR(id)) + return -EBUSY; + sess = ha->tgt.tgt_ops->find_sess_by_s_id(vha, atio->u.isp24.fcp_hdr.s_id); if (unlikely(!sess)) { struct qla_tgt_sess_op *op = kzalloc(sizeof(struct qla_tgt_sess_op), @@ -4758,8 +4771,16 @@ static int qlt_handle_login(struct scsi_qla_host *vha, ql_dbg(ql_dbg_disc, vha, 0xffff, "%s %d %8phC post new sess\n", __func__, __LINE__, iocb->u.isp24.port_name); - qla24xx_post_newsess_work(vha, &port_id, - iocb->u.isp24.port_name, pla); + if (iocb->u.isp24.status_subcode == ELS_PLOGI) + qla24xx_post_newsess_work(vha, &port_id, + iocb->u.isp24.port_name, + iocb->u.isp24.u.plogi.node_name, + pla, FC4_TYPE_UNKNOWN); + else + qla24xx_post_newsess_work(vha, &port_id, + iocb->u.isp24.port_name, NULL, + pla, FC4_TYPE_UNKNOWN); + goto out; } @@ -4888,6 +4909,11 @@ static int qlt_24xx_handle_els(struct scsi_qla_host *vha, break; } + if (IS_SW_RESV_ADDR(port_id)) { + res = 1; + break; + } + wd3_lo = le16_to_cpu(iocb->u.isp24.u.prli.wd3_lo); if (wwn) { @@ -4915,12 +4941,32 @@ static int qlt_24xx_handle_els(struct scsi_qla_host *vha, } if (sess != NULL) { + bool delete = false; spin_lock_irqsave(&tgt->ha->tgt.sess_lock, flags); switch (sess->fw_login_state) { + case DSC_LS_PLOGI_PEND: case DSC_LS_PLOGI_COMP: case DSC_LS_PRLI_COMP: break; default: + delete = true; + break; + } + + switch (sess->disc_state) { + case DSC_LOGIN_PEND: + case DSC_GPDB: + case DSC_GPSC: + case DSC_UPD_FCPORT: + case DSC_LOGIN_COMPLETE: + case DSC_ADISC: + delete = false; + break; + default: + break; + } + + if (delete) { spin_unlock_irqrestore(&tgt->ha->tgt.sess_lock, flags); /* diff --git a/drivers/scsi/qla2xxx/qla_target.h b/drivers/scsi/qla2xxx/qla_target.h index 588c8bcf1192..dc11b83700c1 100644 --- a/drivers/scsi/qla2xxx/qla_target.h +++ b/drivers/scsi/qla2xxx/qla_target.h @@ -994,7 +994,7 @@ struct qla_tgt_prm { /* Check for Switch reserved address */ #define IS_SW_RESV_ADDR(_s_id) \ - ((_s_id.b.domain == 0xff) && (_s_id.b.area == 0xfc)) + ((_s_id.b.domain == 0xff) && ((_s_id.b.area & 0xf0) == 0xf0)) #define QLA_TGT_XMIT_DATA 1 #define QLA_TGT_XMIT_STATUS 2