18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * linux/drivers/scsi/esas2r/esas2r_disc.c 38c2ecf20Sopenharmony_ci * esas2r device discovery routines 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2001-2013 ATTO Technology, Inc. 68c2ecf20Sopenharmony_ci * (mailto:linuxdrivers@attotech.com) 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 98c2ecf20Sopenharmony_ci/* 108c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or modify 118c2ecf20Sopenharmony_ci * it under the terms of the GNU General Public License as published by 128c2ecf20Sopenharmony_ci * the Free Software Foundation; version 2 of the License. 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * This program is distributed in the hope that it will be useful, 158c2ecf20Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 168c2ecf20Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 178c2ecf20Sopenharmony_ci * GNU General Public License for more details. 188c2ecf20Sopenharmony_ci * 198c2ecf20Sopenharmony_ci * NO WARRANTY 208c2ecf20Sopenharmony_ci * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR 218c2ecf20Sopenharmony_ci * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT 228c2ecf20Sopenharmony_ci * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, 238c2ecf20Sopenharmony_ci * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is 248c2ecf20Sopenharmony_ci * solely responsible for determining the appropriateness of using and 258c2ecf20Sopenharmony_ci * distributing the Program and assumes all risks associated with its 268c2ecf20Sopenharmony_ci * exercise of rights under this Agreement, including but not limited to 278c2ecf20Sopenharmony_ci * the risks and costs of program errors, damage to or loss of data, 288c2ecf20Sopenharmony_ci * programs or equipment, and unavailability or interruption of operations. 298c2ecf20Sopenharmony_ci * 308c2ecf20Sopenharmony_ci * DISCLAIMER OF LIABILITY 318c2ecf20Sopenharmony_ci * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY 328c2ecf20Sopenharmony_ci * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 338c2ecf20Sopenharmony_ci * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND 348c2ecf20Sopenharmony_ci * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 358c2ecf20Sopenharmony_ci * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 368c2ecf20Sopenharmony_ci * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED 378c2ecf20Sopenharmony_ci * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES 388c2ecf20Sopenharmony_ci * 398c2ecf20Sopenharmony_ci * You should have received a copy of the GNU General Public License 408c2ecf20Sopenharmony_ci * along with this program; if not, write to the Free Software 418c2ecf20Sopenharmony_ci * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 428c2ecf20Sopenharmony_ci */ 438c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci#include "esas2r.h" 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci/* Miscellaneous internal discovery routines */ 488c2ecf20Sopenharmony_cistatic void esas2r_disc_abort(struct esas2r_adapter *a, 498c2ecf20Sopenharmony_ci struct esas2r_request *rq); 508c2ecf20Sopenharmony_cistatic bool esas2r_disc_continue(struct esas2r_adapter *a, 518c2ecf20Sopenharmony_ci struct esas2r_request *rq); 528c2ecf20Sopenharmony_cistatic void esas2r_disc_fix_curr_requests(struct esas2r_adapter *a); 538c2ecf20Sopenharmony_cistatic u32 esas2r_disc_get_phys_addr(struct esas2r_sg_context *sgc, u64 *addr); 548c2ecf20Sopenharmony_cistatic bool esas2r_disc_start_request(struct esas2r_adapter *a, 558c2ecf20Sopenharmony_ci struct esas2r_request *rq); 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci/* Internal discovery routines that process the states */ 588c2ecf20Sopenharmony_cistatic bool esas2r_disc_block_dev_scan(struct esas2r_adapter *a, 598c2ecf20Sopenharmony_ci struct esas2r_request *rq); 608c2ecf20Sopenharmony_cistatic void esas2r_disc_block_dev_scan_cb(struct esas2r_adapter *a, 618c2ecf20Sopenharmony_ci struct esas2r_request *rq); 628c2ecf20Sopenharmony_cistatic bool esas2r_disc_dev_add(struct esas2r_adapter *a, 638c2ecf20Sopenharmony_ci struct esas2r_request *rq); 648c2ecf20Sopenharmony_cistatic bool esas2r_disc_dev_remove(struct esas2r_adapter *a, 658c2ecf20Sopenharmony_ci struct esas2r_request *rq); 668c2ecf20Sopenharmony_cistatic bool esas2r_disc_part_info(struct esas2r_adapter *a, 678c2ecf20Sopenharmony_ci struct esas2r_request *rq); 688c2ecf20Sopenharmony_cistatic void esas2r_disc_part_info_cb(struct esas2r_adapter *a, 698c2ecf20Sopenharmony_ci struct esas2r_request *rq); 708c2ecf20Sopenharmony_cistatic bool esas2r_disc_passthru_dev_info(struct esas2r_adapter *a, 718c2ecf20Sopenharmony_ci struct esas2r_request *rq); 728c2ecf20Sopenharmony_cistatic void esas2r_disc_passthru_dev_info_cb(struct esas2r_adapter *a, 738c2ecf20Sopenharmony_ci struct esas2r_request *rq); 748c2ecf20Sopenharmony_cistatic bool esas2r_disc_passthru_dev_addr(struct esas2r_adapter *a, 758c2ecf20Sopenharmony_ci struct esas2r_request *rq); 768c2ecf20Sopenharmony_cistatic void esas2r_disc_passthru_dev_addr_cb(struct esas2r_adapter *a, 778c2ecf20Sopenharmony_ci struct esas2r_request *rq); 788c2ecf20Sopenharmony_cistatic bool esas2r_disc_raid_grp_info(struct esas2r_adapter *a, 798c2ecf20Sopenharmony_ci struct esas2r_request *rq); 808c2ecf20Sopenharmony_cistatic void esas2r_disc_raid_grp_info_cb(struct esas2r_adapter *a, 818c2ecf20Sopenharmony_ci struct esas2r_request *rq); 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_civoid esas2r_disc_initialize(struct esas2r_adapter *a) 848c2ecf20Sopenharmony_ci{ 858c2ecf20Sopenharmony_ci struct esas2r_sas_nvram *nvr = a->nvram; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci esas2r_trace_enter(); 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci clear_bit(AF_DISC_IN_PROG, &a->flags); 908c2ecf20Sopenharmony_ci clear_bit(AF2_DEV_SCAN, &a->flags2); 918c2ecf20Sopenharmony_ci clear_bit(AF2_DEV_CNT_OK, &a->flags2); 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci a->disc_start_time = jiffies_to_msecs(jiffies); 948c2ecf20Sopenharmony_ci a->disc_wait_time = nvr->dev_wait_time * 1000; 958c2ecf20Sopenharmony_ci a->disc_wait_cnt = nvr->dev_wait_count; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci if (a->disc_wait_cnt > ESAS2R_MAX_TARGETS) 988c2ecf20Sopenharmony_ci a->disc_wait_cnt = ESAS2R_MAX_TARGETS; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci /* 1018c2ecf20Sopenharmony_ci * If we are doing chip reset or power management processing, always 1028c2ecf20Sopenharmony_ci * wait for devices. use the NVRAM device count if it is greater than 1038c2ecf20Sopenharmony_ci * previously discovered devices. 1048c2ecf20Sopenharmony_ci */ 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci esas2r_hdebug("starting discovery..."); 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci a->general_req.interrupt_cx = NULL; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci if (test_bit(AF_CHPRST_DETECTED, &a->flags) || 1118c2ecf20Sopenharmony_ci test_bit(AF_POWER_MGT, &a->flags)) { 1128c2ecf20Sopenharmony_ci if (a->prev_dev_cnt == 0) { 1138c2ecf20Sopenharmony_ci /* Don't bother waiting if there is nothing to wait 1148c2ecf20Sopenharmony_ci * for. 1158c2ecf20Sopenharmony_ci */ 1168c2ecf20Sopenharmony_ci a->disc_wait_time = 0; 1178c2ecf20Sopenharmony_ci } else { 1188c2ecf20Sopenharmony_ci /* 1198c2ecf20Sopenharmony_ci * Set the device wait count to what was previously 1208c2ecf20Sopenharmony_ci * found. We don't care if the user only configured 1218c2ecf20Sopenharmony_ci * a time because we know the exact count to wait for. 1228c2ecf20Sopenharmony_ci * There is no need to honor the user's wishes to 1238c2ecf20Sopenharmony_ci * always wait the full time. 1248c2ecf20Sopenharmony_ci */ 1258c2ecf20Sopenharmony_ci a->disc_wait_cnt = a->prev_dev_cnt; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci /* 1288c2ecf20Sopenharmony_ci * bump the minimum wait time to 15 seconds since the 1298c2ecf20Sopenharmony_ci * default is 3 (system boot or the boot driver usually 1308c2ecf20Sopenharmony_ci * buys us more time). 1318c2ecf20Sopenharmony_ci */ 1328c2ecf20Sopenharmony_ci if (a->disc_wait_time < 15000) 1338c2ecf20Sopenharmony_ci a->disc_wait_time = 15000; 1348c2ecf20Sopenharmony_ci } 1358c2ecf20Sopenharmony_ci } 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci esas2r_trace("disc wait count: %d", a->disc_wait_cnt); 1388c2ecf20Sopenharmony_ci esas2r_trace("disc wait time: %d", a->disc_wait_time); 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci if (a->disc_wait_time == 0) 1418c2ecf20Sopenharmony_ci esas2r_disc_check_complete(a); 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci esas2r_trace_exit(); 1448c2ecf20Sopenharmony_ci} 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_civoid esas2r_disc_start_waiting(struct esas2r_adapter *a) 1478c2ecf20Sopenharmony_ci{ 1488c2ecf20Sopenharmony_ci unsigned long flags; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci spin_lock_irqsave(&a->mem_lock, flags); 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci if (a->disc_ctx.disc_evt) 1538c2ecf20Sopenharmony_ci esas2r_disc_start_port(a); 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&a->mem_lock, flags); 1568c2ecf20Sopenharmony_ci} 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_civoid esas2r_disc_check_for_work(struct esas2r_adapter *a) 1598c2ecf20Sopenharmony_ci{ 1608c2ecf20Sopenharmony_ci struct esas2r_request *rq = &a->general_req; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci /* service any pending interrupts first */ 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci esas2r_polled_interrupt(a); 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci /* 1678c2ecf20Sopenharmony_ci * now, interrupt processing may have queued up a discovery event. go 1688c2ecf20Sopenharmony_ci * see if we have one to start. we couldn't start it in the ISR since 1698c2ecf20Sopenharmony_ci * polled discovery would cause a deadlock. 1708c2ecf20Sopenharmony_ci */ 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci esas2r_disc_start_waiting(a); 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci if (rq->interrupt_cx == NULL) 1758c2ecf20Sopenharmony_ci return; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci if (rq->req_stat == RS_STARTED 1788c2ecf20Sopenharmony_ci && rq->timeout <= RQ_MAX_TIMEOUT) { 1798c2ecf20Sopenharmony_ci /* wait for the current discovery request to complete. */ 1808c2ecf20Sopenharmony_ci esas2r_wait_request(a, rq); 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci if (rq->req_stat == RS_TIMEOUT) { 1838c2ecf20Sopenharmony_ci esas2r_disc_abort(a, rq); 1848c2ecf20Sopenharmony_ci esas2r_local_reset_adapter(a); 1858c2ecf20Sopenharmony_ci return; 1868c2ecf20Sopenharmony_ci } 1878c2ecf20Sopenharmony_ci } 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci if (rq->req_stat == RS_PENDING 1908c2ecf20Sopenharmony_ci || rq->req_stat == RS_STARTED) 1918c2ecf20Sopenharmony_ci return; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci esas2r_disc_continue(a, rq); 1948c2ecf20Sopenharmony_ci} 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_civoid esas2r_disc_check_complete(struct esas2r_adapter *a) 1978c2ecf20Sopenharmony_ci{ 1988c2ecf20Sopenharmony_ci unsigned long flags; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci esas2r_trace_enter(); 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci /* check to see if we should be waiting for devices */ 2038c2ecf20Sopenharmony_ci if (a->disc_wait_time) { 2048c2ecf20Sopenharmony_ci u32 currtime = jiffies_to_msecs(jiffies); 2058c2ecf20Sopenharmony_ci u32 time = currtime - a->disc_start_time; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci /* 2088c2ecf20Sopenharmony_ci * Wait until the device wait time is exhausted or the device 2098c2ecf20Sopenharmony_ci * wait count is satisfied. 2108c2ecf20Sopenharmony_ci */ 2118c2ecf20Sopenharmony_ci if (time < a->disc_wait_time 2128c2ecf20Sopenharmony_ci && (esas2r_targ_db_get_tgt_cnt(a) < a->disc_wait_cnt 2138c2ecf20Sopenharmony_ci || a->disc_wait_cnt == 0)) { 2148c2ecf20Sopenharmony_ci /* After three seconds of waiting, schedule a scan. */ 2158c2ecf20Sopenharmony_ci if (time >= 3000 2168c2ecf20Sopenharmony_ci && !test_and_set_bit(AF2_DEV_SCAN, &a->flags2)) { 2178c2ecf20Sopenharmony_ci spin_lock_irqsave(&a->mem_lock, flags); 2188c2ecf20Sopenharmony_ci esas2r_disc_queue_event(a, DCDE_DEV_SCAN); 2198c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&a->mem_lock, flags); 2208c2ecf20Sopenharmony_ci } 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci esas2r_trace_exit(); 2238c2ecf20Sopenharmony_ci return; 2248c2ecf20Sopenharmony_ci } 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci /* 2278c2ecf20Sopenharmony_ci * We are done waiting...we think. Adjust the wait time to 2288c2ecf20Sopenharmony_ci * consume events after the count is met. 2298c2ecf20Sopenharmony_ci */ 2308c2ecf20Sopenharmony_ci if (!test_and_set_bit(AF2_DEV_CNT_OK, &a->flags2)) 2318c2ecf20Sopenharmony_ci a->disc_wait_time = time + 3000; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci /* If we haven't done a full scan yet, do it now. */ 2348c2ecf20Sopenharmony_ci if (!test_and_set_bit(AF2_DEV_SCAN, &a->flags2)) { 2358c2ecf20Sopenharmony_ci spin_lock_irqsave(&a->mem_lock, flags); 2368c2ecf20Sopenharmony_ci esas2r_disc_queue_event(a, DCDE_DEV_SCAN); 2378c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&a->mem_lock, flags); 2388c2ecf20Sopenharmony_ci esas2r_trace_exit(); 2398c2ecf20Sopenharmony_ci return; 2408c2ecf20Sopenharmony_ci } 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci /* 2438c2ecf20Sopenharmony_ci * Now, if there is still time left to consume events, continue 2448c2ecf20Sopenharmony_ci * waiting. 2458c2ecf20Sopenharmony_ci */ 2468c2ecf20Sopenharmony_ci if (time < a->disc_wait_time) { 2478c2ecf20Sopenharmony_ci esas2r_trace_exit(); 2488c2ecf20Sopenharmony_ci return; 2498c2ecf20Sopenharmony_ci } 2508c2ecf20Sopenharmony_ci } else { 2518c2ecf20Sopenharmony_ci if (!test_and_set_bit(AF2_DEV_SCAN, &a->flags2)) { 2528c2ecf20Sopenharmony_ci spin_lock_irqsave(&a->mem_lock, flags); 2538c2ecf20Sopenharmony_ci esas2r_disc_queue_event(a, DCDE_DEV_SCAN); 2548c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&a->mem_lock, flags); 2558c2ecf20Sopenharmony_ci } 2568c2ecf20Sopenharmony_ci } 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci /* We want to stop waiting for devices. */ 2598c2ecf20Sopenharmony_ci a->disc_wait_time = 0; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci if (test_bit(AF_DISC_POLLED, &a->flags) && 2628c2ecf20Sopenharmony_ci test_bit(AF_DISC_IN_PROG, &a->flags)) { 2638c2ecf20Sopenharmony_ci /* 2648c2ecf20Sopenharmony_ci * Polled discovery is still pending so continue the active 2658c2ecf20Sopenharmony_ci * discovery until it is done. At that point, we will stop 2668c2ecf20Sopenharmony_ci * polled discovery and transition to interrupt driven 2678c2ecf20Sopenharmony_ci * discovery. 2688c2ecf20Sopenharmony_ci */ 2698c2ecf20Sopenharmony_ci } else { 2708c2ecf20Sopenharmony_ci /* 2718c2ecf20Sopenharmony_ci * Done waiting for devices. Note that we get here immediately 2728c2ecf20Sopenharmony_ci * after deferred waiting completes because that is interrupt 2738c2ecf20Sopenharmony_ci * driven; i.e. There is no transition. 2748c2ecf20Sopenharmony_ci */ 2758c2ecf20Sopenharmony_ci esas2r_disc_fix_curr_requests(a); 2768c2ecf20Sopenharmony_ci clear_bit(AF_DISC_PENDING, &a->flags); 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci /* 2798c2ecf20Sopenharmony_ci * We have deferred target state changes until now because we 2808c2ecf20Sopenharmony_ci * don't want to report any removals (due to the first arrival) 2818c2ecf20Sopenharmony_ci * until the device wait time expires. 2828c2ecf20Sopenharmony_ci */ 2838c2ecf20Sopenharmony_ci set_bit(AF_PORT_CHANGE, &a->flags); 2848c2ecf20Sopenharmony_ci } 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci esas2r_trace_exit(); 2878c2ecf20Sopenharmony_ci} 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_civoid esas2r_disc_queue_event(struct esas2r_adapter *a, u8 disc_evt) 2908c2ecf20Sopenharmony_ci{ 2918c2ecf20Sopenharmony_ci struct esas2r_disc_context *dc = &a->disc_ctx; 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci esas2r_trace_enter(); 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci esas2r_trace("disc_event: %d", disc_evt); 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci /* Initialize the discovery context */ 2988c2ecf20Sopenharmony_ci dc->disc_evt |= disc_evt; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci /* 3018c2ecf20Sopenharmony_ci * Don't start discovery before or during polled discovery. if we did, 3028c2ecf20Sopenharmony_ci * we would have a deadlock if we are in the ISR already. 3038c2ecf20Sopenharmony_ci */ 3048c2ecf20Sopenharmony_ci if (!test_bit(AF_CHPRST_PENDING, &a->flags) && 3058c2ecf20Sopenharmony_ci !test_bit(AF_DISC_POLLED, &a->flags)) 3068c2ecf20Sopenharmony_ci esas2r_disc_start_port(a); 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci esas2r_trace_exit(); 3098c2ecf20Sopenharmony_ci} 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_cibool esas2r_disc_start_port(struct esas2r_adapter *a) 3128c2ecf20Sopenharmony_ci{ 3138c2ecf20Sopenharmony_ci struct esas2r_request *rq = &a->general_req; 3148c2ecf20Sopenharmony_ci struct esas2r_disc_context *dc = &a->disc_ctx; 3158c2ecf20Sopenharmony_ci bool ret; 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci esas2r_trace_enter(); 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci if (test_bit(AF_DISC_IN_PROG, &a->flags)) { 3208c2ecf20Sopenharmony_ci esas2r_trace_exit(); 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci return false; 3238c2ecf20Sopenharmony_ci } 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci /* If there is a discovery waiting, process it. */ 3268c2ecf20Sopenharmony_ci if (dc->disc_evt) { 3278c2ecf20Sopenharmony_ci if (test_bit(AF_DISC_POLLED, &a->flags) 3288c2ecf20Sopenharmony_ci && a->disc_wait_time == 0) { 3298c2ecf20Sopenharmony_ci /* 3308c2ecf20Sopenharmony_ci * We are doing polled discovery, but we no longer want 3318c2ecf20Sopenharmony_ci * to wait for devices. Stop polled discovery and 3328c2ecf20Sopenharmony_ci * transition to interrupt driven discovery. 3338c2ecf20Sopenharmony_ci */ 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci esas2r_trace_exit(); 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci return false; 3388c2ecf20Sopenharmony_ci } 3398c2ecf20Sopenharmony_ci } else { 3408c2ecf20Sopenharmony_ci /* Discovery is complete. */ 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci esas2r_hdebug("disc done"); 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci set_bit(AF_PORT_CHANGE, &a->flags); 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci esas2r_trace_exit(); 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci return false; 3498c2ecf20Sopenharmony_ci } 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci /* Handle the discovery context */ 3528c2ecf20Sopenharmony_ci esas2r_trace("disc_evt: %d", dc->disc_evt); 3538c2ecf20Sopenharmony_ci set_bit(AF_DISC_IN_PROG, &a->flags); 3548c2ecf20Sopenharmony_ci dc->flags = 0; 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci if (test_bit(AF_DISC_POLLED, &a->flags)) 3578c2ecf20Sopenharmony_ci dc->flags |= DCF_POLLED; 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci rq->interrupt_cx = dc; 3608c2ecf20Sopenharmony_ci rq->req_stat = RS_SUCCESS; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci /* Decode the event code */ 3638c2ecf20Sopenharmony_ci if (dc->disc_evt & DCDE_DEV_SCAN) { 3648c2ecf20Sopenharmony_ci dc->disc_evt &= ~DCDE_DEV_SCAN; 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci dc->flags |= DCF_DEV_SCAN; 3678c2ecf20Sopenharmony_ci dc->state = DCS_BLOCK_DEV_SCAN; 3688c2ecf20Sopenharmony_ci } else if (dc->disc_evt & DCDE_DEV_CHANGE) { 3698c2ecf20Sopenharmony_ci dc->disc_evt &= ~DCDE_DEV_CHANGE; 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci dc->flags |= DCF_DEV_CHANGE; 3728c2ecf20Sopenharmony_ci dc->state = DCS_DEV_RMV; 3738c2ecf20Sopenharmony_ci } 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci /* Continue interrupt driven discovery */ 3768c2ecf20Sopenharmony_ci if (!test_bit(AF_DISC_POLLED, &a->flags)) 3778c2ecf20Sopenharmony_ci ret = esas2r_disc_continue(a, rq); 3788c2ecf20Sopenharmony_ci else 3798c2ecf20Sopenharmony_ci ret = true; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci esas2r_trace_exit(); 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci return ret; 3848c2ecf20Sopenharmony_ci} 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_cistatic bool esas2r_disc_continue(struct esas2r_adapter *a, 3878c2ecf20Sopenharmony_ci struct esas2r_request *rq) 3888c2ecf20Sopenharmony_ci{ 3898c2ecf20Sopenharmony_ci struct esas2r_disc_context *dc = 3908c2ecf20Sopenharmony_ci (struct esas2r_disc_context *)rq->interrupt_cx; 3918c2ecf20Sopenharmony_ci bool rslt; 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci /* Device discovery/removal */ 3948c2ecf20Sopenharmony_ci while (dc->flags & (DCF_DEV_CHANGE | DCF_DEV_SCAN)) { 3958c2ecf20Sopenharmony_ci rslt = false; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci switch (dc->state) { 3988c2ecf20Sopenharmony_ci case DCS_DEV_RMV: 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci rslt = esas2r_disc_dev_remove(a, rq); 4018c2ecf20Sopenharmony_ci break; 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci case DCS_DEV_ADD: 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci rslt = esas2r_disc_dev_add(a, rq); 4068c2ecf20Sopenharmony_ci break; 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci case DCS_BLOCK_DEV_SCAN: 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci rslt = esas2r_disc_block_dev_scan(a, rq); 4118c2ecf20Sopenharmony_ci break; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci case DCS_RAID_GRP_INFO: 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci rslt = esas2r_disc_raid_grp_info(a, rq); 4168c2ecf20Sopenharmony_ci break; 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci case DCS_PART_INFO: 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci rslt = esas2r_disc_part_info(a, rq); 4218c2ecf20Sopenharmony_ci break; 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci case DCS_PT_DEV_INFO: 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci rslt = esas2r_disc_passthru_dev_info(a, rq); 4268c2ecf20Sopenharmony_ci break; 4278c2ecf20Sopenharmony_ci case DCS_PT_DEV_ADDR: 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci rslt = esas2r_disc_passthru_dev_addr(a, rq); 4308c2ecf20Sopenharmony_ci break; 4318c2ecf20Sopenharmony_ci case DCS_DISC_DONE: 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci dc->flags &= ~(DCF_DEV_CHANGE | DCF_DEV_SCAN); 4348c2ecf20Sopenharmony_ci break; 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci default: 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci esas2r_bugon(); 4398c2ecf20Sopenharmony_ci dc->state = DCS_DISC_DONE; 4408c2ecf20Sopenharmony_ci break; 4418c2ecf20Sopenharmony_ci } 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci if (rslt) 4448c2ecf20Sopenharmony_ci return true; 4458c2ecf20Sopenharmony_ci } 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci /* Discovery is done...for now. */ 4488c2ecf20Sopenharmony_ci rq->interrupt_cx = NULL; 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci if (!test_bit(AF_DISC_PENDING, &a->flags)) 4518c2ecf20Sopenharmony_ci esas2r_disc_fix_curr_requests(a); 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci clear_bit(AF_DISC_IN_PROG, &a->flags); 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci /* Start the next discovery. */ 4568c2ecf20Sopenharmony_ci return esas2r_disc_start_port(a); 4578c2ecf20Sopenharmony_ci} 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_cistatic bool esas2r_disc_start_request(struct esas2r_adapter *a, 4608c2ecf20Sopenharmony_ci struct esas2r_request *rq) 4618c2ecf20Sopenharmony_ci{ 4628c2ecf20Sopenharmony_ci unsigned long flags; 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci /* Set the timeout to a minimum value. */ 4658c2ecf20Sopenharmony_ci if (rq->timeout < ESAS2R_DEFAULT_TMO) 4668c2ecf20Sopenharmony_ci rq->timeout = ESAS2R_DEFAULT_TMO; 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci /* 4698c2ecf20Sopenharmony_ci * Override the request type to distinguish discovery requests. If we 4708c2ecf20Sopenharmony_ci * end up deferring the request, esas2r_disc_local_start_request() 4718c2ecf20Sopenharmony_ci * will be called to restart it. 4728c2ecf20Sopenharmony_ci */ 4738c2ecf20Sopenharmony_ci rq->req_type = RT_DISC_REQ; 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci spin_lock_irqsave(&a->queue_lock, flags); 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci if (!test_bit(AF_CHPRST_PENDING, &a->flags) && 4788c2ecf20Sopenharmony_ci !test_bit(AF_FLASHING, &a->flags)) 4798c2ecf20Sopenharmony_ci esas2r_disc_local_start_request(a, rq); 4808c2ecf20Sopenharmony_ci else 4818c2ecf20Sopenharmony_ci list_add_tail(&rq->req_list, &a->defer_list); 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&a->queue_lock, flags); 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci return true; 4868c2ecf20Sopenharmony_ci} 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_civoid esas2r_disc_local_start_request(struct esas2r_adapter *a, 4898c2ecf20Sopenharmony_ci struct esas2r_request *rq) 4908c2ecf20Sopenharmony_ci{ 4918c2ecf20Sopenharmony_ci esas2r_trace_enter(); 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci list_add_tail(&rq->req_list, &a->active_list); 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci esas2r_start_vda_request(a, rq); 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci esas2r_trace_exit(); 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci return; 5008c2ecf20Sopenharmony_ci} 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_cistatic void esas2r_disc_abort(struct esas2r_adapter *a, 5038c2ecf20Sopenharmony_ci struct esas2r_request *rq) 5048c2ecf20Sopenharmony_ci{ 5058c2ecf20Sopenharmony_ci struct esas2r_disc_context *dc = 5068c2ecf20Sopenharmony_ci (struct esas2r_disc_context *)rq->interrupt_cx; 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci esas2r_trace_enter(); 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci /* abort the current discovery */ 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci dc->state = DCS_DISC_DONE; 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci esas2r_trace_exit(); 5158c2ecf20Sopenharmony_ci} 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_cistatic bool esas2r_disc_block_dev_scan(struct esas2r_adapter *a, 5188c2ecf20Sopenharmony_ci struct esas2r_request *rq) 5198c2ecf20Sopenharmony_ci{ 5208c2ecf20Sopenharmony_ci struct esas2r_disc_context *dc = 5218c2ecf20Sopenharmony_ci (struct esas2r_disc_context *)rq->interrupt_cx; 5228c2ecf20Sopenharmony_ci bool rslt; 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci esas2r_trace_enter(); 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci esas2r_rq_init_request(rq, a); 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci esas2r_build_mgt_req(a, 5298c2ecf20Sopenharmony_ci rq, 5308c2ecf20Sopenharmony_ci VDAMGT_DEV_SCAN, 5318c2ecf20Sopenharmony_ci 0, 5328c2ecf20Sopenharmony_ci 0, 5338c2ecf20Sopenharmony_ci 0, 5348c2ecf20Sopenharmony_ci NULL); 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci rq->comp_cb = esas2r_disc_block_dev_scan_cb; 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci rq->timeout = 30000; 5398c2ecf20Sopenharmony_ci rq->interrupt_cx = dc; 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci rslt = esas2r_disc_start_request(a, rq); 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci esas2r_trace_exit(); 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci return rslt; 5468c2ecf20Sopenharmony_ci} 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_cistatic void esas2r_disc_block_dev_scan_cb(struct esas2r_adapter *a, 5498c2ecf20Sopenharmony_ci struct esas2r_request *rq) 5508c2ecf20Sopenharmony_ci{ 5518c2ecf20Sopenharmony_ci struct esas2r_disc_context *dc = 5528c2ecf20Sopenharmony_ci (struct esas2r_disc_context *)rq->interrupt_cx; 5538c2ecf20Sopenharmony_ci unsigned long flags; 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci esas2r_trace_enter(); 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci spin_lock_irqsave(&a->mem_lock, flags); 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci if (rq->req_stat == RS_SUCCESS) 5608c2ecf20Sopenharmony_ci dc->scan_gen = rq->func_rsp.mgt_rsp.scan_generation; 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci dc->state = DCS_RAID_GRP_INFO; 5638c2ecf20Sopenharmony_ci dc->raid_grp_ix = 0; 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci esas2r_rq_destroy_request(rq, a); 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci /* continue discovery if it's interrupt driven */ 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci if (!(dc->flags & DCF_POLLED)) 5708c2ecf20Sopenharmony_ci esas2r_disc_continue(a, rq); 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&a->mem_lock, flags); 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci esas2r_trace_exit(); 5758c2ecf20Sopenharmony_ci} 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_cistatic bool esas2r_disc_raid_grp_info(struct esas2r_adapter *a, 5788c2ecf20Sopenharmony_ci struct esas2r_request *rq) 5798c2ecf20Sopenharmony_ci{ 5808c2ecf20Sopenharmony_ci struct esas2r_disc_context *dc = 5818c2ecf20Sopenharmony_ci (struct esas2r_disc_context *)rq->interrupt_cx; 5828c2ecf20Sopenharmony_ci bool rslt; 5838c2ecf20Sopenharmony_ci struct atto_vda_grp_info *grpinfo; 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci esas2r_trace_enter(); 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci esas2r_trace("raid_group_idx: %d", dc->raid_grp_ix); 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci if (dc->raid_grp_ix >= VDA_MAX_RAID_GROUPS) { 5908c2ecf20Sopenharmony_ci dc->state = DCS_DISC_DONE; 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci esas2r_trace_exit(); 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci return false; 5958c2ecf20Sopenharmony_ci } 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci esas2r_rq_init_request(rq, a); 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci grpinfo = &rq->vda_rsp_data->mgt_data.data.grp_info; 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci memset(grpinfo, 0, sizeof(struct atto_vda_grp_info)); 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci esas2r_build_mgt_req(a, 6048c2ecf20Sopenharmony_ci rq, 6058c2ecf20Sopenharmony_ci VDAMGT_GRP_INFO, 6068c2ecf20Sopenharmony_ci dc->scan_gen, 6078c2ecf20Sopenharmony_ci 0, 6088c2ecf20Sopenharmony_ci sizeof(struct atto_vda_grp_info), 6098c2ecf20Sopenharmony_ci NULL); 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci grpinfo->grp_index = dc->raid_grp_ix; 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci rq->comp_cb = esas2r_disc_raid_grp_info_cb; 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci rq->interrupt_cx = dc; 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci rslt = esas2r_disc_start_request(a, rq); 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci esas2r_trace_exit(); 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci return rslt; 6228c2ecf20Sopenharmony_ci} 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_cistatic void esas2r_disc_raid_grp_info_cb(struct esas2r_adapter *a, 6258c2ecf20Sopenharmony_ci struct esas2r_request *rq) 6268c2ecf20Sopenharmony_ci{ 6278c2ecf20Sopenharmony_ci struct esas2r_disc_context *dc = 6288c2ecf20Sopenharmony_ci (struct esas2r_disc_context *)rq->interrupt_cx; 6298c2ecf20Sopenharmony_ci unsigned long flags; 6308c2ecf20Sopenharmony_ci struct atto_vda_grp_info *grpinfo; 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci esas2r_trace_enter(); 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci spin_lock_irqsave(&a->mem_lock, flags); 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci if (rq->req_stat == RS_SCAN_GEN) { 6378c2ecf20Sopenharmony_ci dc->scan_gen = rq->func_rsp.mgt_rsp.scan_generation; 6388c2ecf20Sopenharmony_ci dc->raid_grp_ix = 0; 6398c2ecf20Sopenharmony_ci goto done; 6408c2ecf20Sopenharmony_ci } 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci if (rq->req_stat == RS_SUCCESS) { 6438c2ecf20Sopenharmony_ci grpinfo = &rq->vda_rsp_data->mgt_data.data.grp_info; 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci if (grpinfo->status != VDA_GRP_STAT_ONLINE 6468c2ecf20Sopenharmony_ci && grpinfo->status != VDA_GRP_STAT_DEGRADED) { 6478c2ecf20Sopenharmony_ci /* go to the next group. */ 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci dc->raid_grp_ix++; 6508c2ecf20Sopenharmony_ci } else { 6518c2ecf20Sopenharmony_ci memcpy(&dc->raid_grp_name[0], 6528c2ecf20Sopenharmony_ci &grpinfo->grp_name[0], 6538c2ecf20Sopenharmony_ci sizeof(grpinfo->grp_name)); 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci dc->interleave = le32_to_cpu(grpinfo->interleave); 6568c2ecf20Sopenharmony_ci dc->block_size = le32_to_cpu(grpinfo->block_size); 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci dc->state = DCS_PART_INFO; 6598c2ecf20Sopenharmony_ci dc->part_num = 0; 6608c2ecf20Sopenharmony_ci } 6618c2ecf20Sopenharmony_ci } else { 6628c2ecf20Sopenharmony_ci if (!(rq->req_stat == RS_GRP_INVALID)) { 6638c2ecf20Sopenharmony_ci esas2r_log(ESAS2R_LOG_WARN, 6648c2ecf20Sopenharmony_ci "A request for RAID group info failed - " 6658c2ecf20Sopenharmony_ci "returned with %x", 6668c2ecf20Sopenharmony_ci rq->req_stat); 6678c2ecf20Sopenharmony_ci } 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci dc->dev_ix = 0; 6708c2ecf20Sopenharmony_ci dc->state = DCS_PT_DEV_INFO; 6718c2ecf20Sopenharmony_ci } 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_cidone: 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci esas2r_rq_destroy_request(rq, a); 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci /* continue discovery if it's interrupt driven */ 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci if (!(dc->flags & DCF_POLLED)) 6808c2ecf20Sopenharmony_ci esas2r_disc_continue(a, rq); 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&a->mem_lock, flags); 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci esas2r_trace_exit(); 6858c2ecf20Sopenharmony_ci} 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_cistatic bool esas2r_disc_part_info(struct esas2r_adapter *a, 6888c2ecf20Sopenharmony_ci struct esas2r_request *rq) 6898c2ecf20Sopenharmony_ci{ 6908c2ecf20Sopenharmony_ci struct esas2r_disc_context *dc = 6918c2ecf20Sopenharmony_ci (struct esas2r_disc_context *)rq->interrupt_cx; 6928c2ecf20Sopenharmony_ci bool rslt; 6938c2ecf20Sopenharmony_ci struct atto_vdapart_info *partinfo; 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci esas2r_trace_enter(); 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci esas2r_trace("part_num: %d", dc->part_num); 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci if (dc->part_num >= VDA_MAX_PARTITIONS) { 7008c2ecf20Sopenharmony_ci dc->state = DCS_RAID_GRP_INFO; 7018c2ecf20Sopenharmony_ci dc->raid_grp_ix++; 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci esas2r_trace_exit(); 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci return false; 7068c2ecf20Sopenharmony_ci } 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci esas2r_rq_init_request(rq, a); 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci partinfo = &rq->vda_rsp_data->mgt_data.data.part_info; 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci memset(partinfo, 0, sizeof(struct atto_vdapart_info)); 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci esas2r_build_mgt_req(a, 7158c2ecf20Sopenharmony_ci rq, 7168c2ecf20Sopenharmony_ci VDAMGT_PART_INFO, 7178c2ecf20Sopenharmony_ci dc->scan_gen, 7188c2ecf20Sopenharmony_ci 0, 7198c2ecf20Sopenharmony_ci sizeof(struct atto_vdapart_info), 7208c2ecf20Sopenharmony_ci NULL); 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci partinfo->part_no = dc->part_num; 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci memcpy(&partinfo->grp_name[0], 7258c2ecf20Sopenharmony_ci &dc->raid_grp_name[0], 7268c2ecf20Sopenharmony_ci sizeof(partinfo->grp_name)); 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci rq->comp_cb = esas2r_disc_part_info_cb; 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci rq->interrupt_cx = dc; 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci rslt = esas2r_disc_start_request(a, rq); 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci esas2r_trace_exit(); 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci return rslt; 7378c2ecf20Sopenharmony_ci} 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_cistatic void esas2r_disc_part_info_cb(struct esas2r_adapter *a, 7408c2ecf20Sopenharmony_ci struct esas2r_request *rq) 7418c2ecf20Sopenharmony_ci{ 7428c2ecf20Sopenharmony_ci struct esas2r_disc_context *dc = 7438c2ecf20Sopenharmony_ci (struct esas2r_disc_context *)rq->interrupt_cx; 7448c2ecf20Sopenharmony_ci unsigned long flags; 7458c2ecf20Sopenharmony_ci struct atto_vdapart_info *partinfo; 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_ci esas2r_trace_enter(); 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci spin_lock_irqsave(&a->mem_lock, flags); 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci if (rq->req_stat == RS_SCAN_GEN) { 7528c2ecf20Sopenharmony_ci dc->scan_gen = rq->func_rsp.mgt_rsp.scan_generation; 7538c2ecf20Sopenharmony_ci dc->raid_grp_ix = 0; 7548c2ecf20Sopenharmony_ci dc->state = DCS_RAID_GRP_INFO; 7558c2ecf20Sopenharmony_ci } else if (rq->req_stat == RS_SUCCESS) { 7568c2ecf20Sopenharmony_ci partinfo = &rq->vda_rsp_data->mgt_data.data.part_info; 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_ci dc->part_num = partinfo->part_no; 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_ci dc->curr_virt_id = le16_to_cpu(partinfo->target_id); 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci esas2r_targ_db_add_raid(a, dc); 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci dc->part_num++; 7658c2ecf20Sopenharmony_ci } else { 7668c2ecf20Sopenharmony_ci if (!(rq->req_stat == RS_PART_LAST)) { 7678c2ecf20Sopenharmony_ci esas2r_log(ESAS2R_LOG_WARN, 7688c2ecf20Sopenharmony_ci "A request for RAID group partition info " 7698c2ecf20Sopenharmony_ci "failed - status:%d", rq->req_stat); 7708c2ecf20Sopenharmony_ci } 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_ci dc->state = DCS_RAID_GRP_INFO; 7738c2ecf20Sopenharmony_ci dc->raid_grp_ix++; 7748c2ecf20Sopenharmony_ci } 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci esas2r_rq_destroy_request(rq, a); 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci /* continue discovery if it's interrupt driven */ 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci if (!(dc->flags & DCF_POLLED)) 7818c2ecf20Sopenharmony_ci esas2r_disc_continue(a, rq); 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&a->mem_lock, flags); 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci esas2r_trace_exit(); 7868c2ecf20Sopenharmony_ci} 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_cistatic bool esas2r_disc_passthru_dev_info(struct esas2r_adapter *a, 7898c2ecf20Sopenharmony_ci struct esas2r_request *rq) 7908c2ecf20Sopenharmony_ci{ 7918c2ecf20Sopenharmony_ci struct esas2r_disc_context *dc = 7928c2ecf20Sopenharmony_ci (struct esas2r_disc_context *)rq->interrupt_cx; 7938c2ecf20Sopenharmony_ci bool rslt; 7948c2ecf20Sopenharmony_ci struct atto_vda_devinfo *devinfo; 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci esas2r_trace_enter(); 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_ci esas2r_trace("dev_ix: %d", dc->dev_ix); 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci esas2r_rq_init_request(rq, a); 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_ci devinfo = &rq->vda_rsp_data->mgt_data.data.dev_info; 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci memset(devinfo, 0, sizeof(struct atto_vda_devinfo)); 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ci esas2r_build_mgt_req(a, 8078c2ecf20Sopenharmony_ci rq, 8088c2ecf20Sopenharmony_ci VDAMGT_DEV_PT_INFO, 8098c2ecf20Sopenharmony_ci dc->scan_gen, 8108c2ecf20Sopenharmony_ci dc->dev_ix, 8118c2ecf20Sopenharmony_ci sizeof(struct atto_vda_devinfo), 8128c2ecf20Sopenharmony_ci NULL); 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci rq->comp_cb = esas2r_disc_passthru_dev_info_cb; 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci rq->interrupt_cx = dc; 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ci rslt = esas2r_disc_start_request(a, rq); 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci esas2r_trace_exit(); 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci return rslt; 8238c2ecf20Sopenharmony_ci} 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_cistatic void esas2r_disc_passthru_dev_info_cb(struct esas2r_adapter *a, 8268c2ecf20Sopenharmony_ci struct esas2r_request *rq) 8278c2ecf20Sopenharmony_ci{ 8288c2ecf20Sopenharmony_ci struct esas2r_disc_context *dc = 8298c2ecf20Sopenharmony_ci (struct esas2r_disc_context *)rq->interrupt_cx; 8308c2ecf20Sopenharmony_ci unsigned long flags; 8318c2ecf20Sopenharmony_ci struct atto_vda_devinfo *devinfo; 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci esas2r_trace_enter(); 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_ci spin_lock_irqsave(&a->mem_lock, flags); 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ci if (rq->req_stat == RS_SCAN_GEN) { 8388c2ecf20Sopenharmony_ci dc->scan_gen = rq->func_rsp.mgt_rsp.scan_generation; 8398c2ecf20Sopenharmony_ci dc->dev_ix = 0; 8408c2ecf20Sopenharmony_ci dc->state = DCS_PT_DEV_INFO; 8418c2ecf20Sopenharmony_ci } else if (rq->req_stat == RS_SUCCESS) { 8428c2ecf20Sopenharmony_ci devinfo = &rq->vda_rsp_data->mgt_data.data.dev_info; 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci dc->dev_ix = le16_to_cpu(rq->func_rsp.mgt_rsp.dev_index); 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_ci dc->curr_virt_id = le16_to_cpu(devinfo->target_id); 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci if (le16_to_cpu(devinfo->features) & VDADEVFEAT_PHYS_ID) { 8498c2ecf20Sopenharmony_ci dc->curr_phys_id = 8508c2ecf20Sopenharmony_ci le16_to_cpu(devinfo->phys_target_id); 8518c2ecf20Sopenharmony_ci dc->dev_addr_type = ATTO_GDA_AT_PORT; 8528c2ecf20Sopenharmony_ci dc->state = DCS_PT_DEV_ADDR; 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci esas2r_trace("curr_virt_id: %d", dc->curr_virt_id); 8558c2ecf20Sopenharmony_ci esas2r_trace("curr_phys_id: %d", dc->curr_phys_id); 8568c2ecf20Sopenharmony_ci } else { 8578c2ecf20Sopenharmony_ci dc->dev_ix++; 8588c2ecf20Sopenharmony_ci } 8598c2ecf20Sopenharmony_ci } else { 8608c2ecf20Sopenharmony_ci if (!(rq->req_stat == RS_DEV_INVALID)) { 8618c2ecf20Sopenharmony_ci esas2r_log(ESAS2R_LOG_WARN, 8628c2ecf20Sopenharmony_ci "A request for device information failed - " 8638c2ecf20Sopenharmony_ci "status:%d", rq->req_stat); 8648c2ecf20Sopenharmony_ci } 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci dc->state = DCS_DISC_DONE; 8678c2ecf20Sopenharmony_ci } 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci esas2r_rq_destroy_request(rq, a); 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci /* continue discovery if it's interrupt driven */ 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci if (!(dc->flags & DCF_POLLED)) 8748c2ecf20Sopenharmony_ci esas2r_disc_continue(a, rq); 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&a->mem_lock, flags); 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci esas2r_trace_exit(); 8798c2ecf20Sopenharmony_ci} 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_cistatic bool esas2r_disc_passthru_dev_addr(struct esas2r_adapter *a, 8828c2ecf20Sopenharmony_ci struct esas2r_request *rq) 8838c2ecf20Sopenharmony_ci{ 8848c2ecf20Sopenharmony_ci struct esas2r_disc_context *dc = 8858c2ecf20Sopenharmony_ci (struct esas2r_disc_context *)rq->interrupt_cx; 8868c2ecf20Sopenharmony_ci bool rslt; 8878c2ecf20Sopenharmony_ci struct atto_ioctl *hi; 8888c2ecf20Sopenharmony_ci struct esas2r_sg_context sgc; 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_ci esas2r_trace_enter(); 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ci esas2r_rq_init_request(rq, a); 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci /* format the request. */ 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ci sgc.cur_offset = NULL; 8978c2ecf20Sopenharmony_ci sgc.get_phys_addr = (PGETPHYSADDR)esas2r_disc_get_phys_addr; 8988c2ecf20Sopenharmony_ci sgc.length = offsetof(struct atto_ioctl, data) 8998c2ecf20Sopenharmony_ci + sizeof(struct atto_hba_get_device_address); 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_ci esas2r_sgc_init(&sgc, a, rq, rq->vrq->ioctl.sge); 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_ci esas2r_build_ioctl_req(a, rq, sgc.length, VDA_IOCTL_HBA); 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci if (!esas2r_build_sg_list(a, rq, &sgc)) { 9068c2ecf20Sopenharmony_ci esas2r_rq_destroy_request(rq, a); 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_ci esas2r_trace_exit(); 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci return false; 9118c2ecf20Sopenharmony_ci } 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci rq->comp_cb = esas2r_disc_passthru_dev_addr_cb; 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ci rq->interrupt_cx = dc; 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_ci /* format the IOCTL data. */ 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci hi = (struct atto_ioctl *)a->disc_buffer; 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_ci memset(a->disc_buffer, 0, ESAS2R_DISC_BUF_LEN); 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_ci hi->version = ATTO_VER_GET_DEV_ADDR0; 9248c2ecf20Sopenharmony_ci hi->function = ATTO_FUNC_GET_DEV_ADDR; 9258c2ecf20Sopenharmony_ci hi->flags = HBAF_TUNNEL; 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_ci hi->data.get_dev_addr.target_id = le32_to_cpu(dc->curr_phys_id); 9288c2ecf20Sopenharmony_ci hi->data.get_dev_addr.addr_type = dc->dev_addr_type; 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_ci /* start it up. */ 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ci rslt = esas2r_disc_start_request(a, rq); 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_ci esas2r_trace_exit(); 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_ci return rslt; 9378c2ecf20Sopenharmony_ci} 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_cistatic void esas2r_disc_passthru_dev_addr_cb(struct esas2r_adapter *a, 9408c2ecf20Sopenharmony_ci struct esas2r_request *rq) 9418c2ecf20Sopenharmony_ci{ 9428c2ecf20Sopenharmony_ci struct esas2r_disc_context *dc = 9438c2ecf20Sopenharmony_ci (struct esas2r_disc_context *)rq->interrupt_cx; 9448c2ecf20Sopenharmony_ci struct esas2r_target *t = NULL; 9458c2ecf20Sopenharmony_ci unsigned long flags; 9468c2ecf20Sopenharmony_ci struct atto_ioctl *hi; 9478c2ecf20Sopenharmony_ci u16 addrlen; 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_ci esas2r_trace_enter(); 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_ci spin_lock_irqsave(&a->mem_lock, flags); 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_ci hi = (struct atto_ioctl *)a->disc_buffer; 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_ci if (rq->req_stat == RS_SUCCESS 9568c2ecf20Sopenharmony_ci && hi->status == ATTO_STS_SUCCESS) { 9578c2ecf20Sopenharmony_ci addrlen = le16_to_cpu(hi->data.get_dev_addr.addr_len); 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_ci if (dc->dev_addr_type == ATTO_GDA_AT_PORT) { 9608c2ecf20Sopenharmony_ci if (addrlen == sizeof(u64)) 9618c2ecf20Sopenharmony_ci memcpy(&dc->sas_addr, 9628c2ecf20Sopenharmony_ci &hi->data.get_dev_addr.address[0], 9638c2ecf20Sopenharmony_ci addrlen); 9648c2ecf20Sopenharmony_ci else 9658c2ecf20Sopenharmony_ci memset(&dc->sas_addr, 0, sizeof(dc->sas_addr)); 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_ci /* Get the unique identifier. */ 9688c2ecf20Sopenharmony_ci dc->dev_addr_type = ATTO_GDA_AT_UNIQUE; 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_ci goto next_dev_addr; 9718c2ecf20Sopenharmony_ci } else { 9728c2ecf20Sopenharmony_ci /* Add the pass through target. */ 9738c2ecf20Sopenharmony_ci if (HIBYTE(addrlen) == 0) { 9748c2ecf20Sopenharmony_ci t = esas2r_targ_db_add_pthru(a, 9758c2ecf20Sopenharmony_ci dc, 9768c2ecf20Sopenharmony_ci &hi->data. 9778c2ecf20Sopenharmony_ci get_dev_addr. 9788c2ecf20Sopenharmony_ci address[0], 9798c2ecf20Sopenharmony_ci (u8)hi->data. 9808c2ecf20Sopenharmony_ci get_dev_addr. 9818c2ecf20Sopenharmony_ci addr_len); 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_ci if (t) 9848c2ecf20Sopenharmony_ci memcpy(&t->sas_addr, &dc->sas_addr, 9858c2ecf20Sopenharmony_ci sizeof(t->sas_addr)); 9868c2ecf20Sopenharmony_ci } else { 9878c2ecf20Sopenharmony_ci /* getting the back end data failed */ 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_ci esas2r_log(ESAS2R_LOG_WARN, 9908c2ecf20Sopenharmony_ci "an error occurred retrieving the " 9918c2ecf20Sopenharmony_ci "back end data (%s:%d)", 9928c2ecf20Sopenharmony_ci __func__, 9938c2ecf20Sopenharmony_ci __LINE__); 9948c2ecf20Sopenharmony_ci } 9958c2ecf20Sopenharmony_ci } 9968c2ecf20Sopenharmony_ci } else { 9978c2ecf20Sopenharmony_ci /* getting the back end data failed */ 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_ci esas2r_log(ESAS2R_LOG_WARN, 10008c2ecf20Sopenharmony_ci "an error occurred retrieving the back end data - " 10018c2ecf20Sopenharmony_ci "rq->req_stat:%d hi->status:%d", 10028c2ecf20Sopenharmony_ci rq->req_stat, hi->status); 10038c2ecf20Sopenharmony_ci } 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_ci /* proceed to the next device. */ 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_ci if (dc->flags & DCF_DEV_SCAN) { 10088c2ecf20Sopenharmony_ci dc->dev_ix++; 10098c2ecf20Sopenharmony_ci dc->state = DCS_PT_DEV_INFO; 10108c2ecf20Sopenharmony_ci } else if (dc->flags & DCF_DEV_CHANGE) { 10118c2ecf20Sopenharmony_ci dc->curr_targ++; 10128c2ecf20Sopenharmony_ci dc->state = DCS_DEV_ADD; 10138c2ecf20Sopenharmony_ci } else { 10148c2ecf20Sopenharmony_ci esas2r_bugon(); 10158c2ecf20Sopenharmony_ci } 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_cinext_dev_addr: 10188c2ecf20Sopenharmony_ci esas2r_rq_destroy_request(rq, a); 10198c2ecf20Sopenharmony_ci 10208c2ecf20Sopenharmony_ci /* continue discovery if it's interrupt driven */ 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_ci if (!(dc->flags & DCF_POLLED)) 10238c2ecf20Sopenharmony_ci esas2r_disc_continue(a, rq); 10248c2ecf20Sopenharmony_ci 10258c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&a->mem_lock, flags); 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci esas2r_trace_exit(); 10288c2ecf20Sopenharmony_ci} 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_cistatic u32 esas2r_disc_get_phys_addr(struct esas2r_sg_context *sgc, u64 *addr) 10318c2ecf20Sopenharmony_ci{ 10328c2ecf20Sopenharmony_ci struct esas2r_adapter *a = sgc->adapter; 10338c2ecf20Sopenharmony_ci 10348c2ecf20Sopenharmony_ci if (sgc->length > ESAS2R_DISC_BUF_LEN) 10358c2ecf20Sopenharmony_ci esas2r_bugon(); 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_ci *addr = a->uncached_phys 10388c2ecf20Sopenharmony_ci + (u64)((u8 *)a->disc_buffer - a->uncached); 10398c2ecf20Sopenharmony_ci 10408c2ecf20Sopenharmony_ci return sgc->length; 10418c2ecf20Sopenharmony_ci} 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_cistatic bool esas2r_disc_dev_remove(struct esas2r_adapter *a, 10448c2ecf20Sopenharmony_ci struct esas2r_request *rq) 10458c2ecf20Sopenharmony_ci{ 10468c2ecf20Sopenharmony_ci struct esas2r_disc_context *dc = 10478c2ecf20Sopenharmony_ci (struct esas2r_disc_context *)rq->interrupt_cx; 10488c2ecf20Sopenharmony_ci struct esas2r_target *t; 10498c2ecf20Sopenharmony_ci struct esas2r_target *t2; 10508c2ecf20Sopenharmony_ci 10518c2ecf20Sopenharmony_ci esas2r_trace_enter(); 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_ci /* process removals. */ 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_ci for (t = a->targetdb; t < a->targetdb_end; t++) { 10568c2ecf20Sopenharmony_ci if (t->new_target_state != TS_NOT_PRESENT) 10578c2ecf20Sopenharmony_ci continue; 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_ci t->new_target_state = TS_INVALID; 10608c2ecf20Sopenharmony_ci 10618c2ecf20Sopenharmony_ci /* remove the right target! */ 10628c2ecf20Sopenharmony_ci 10638c2ecf20Sopenharmony_ci t2 = 10648c2ecf20Sopenharmony_ci esas2r_targ_db_find_by_virt_id(a, 10658c2ecf20Sopenharmony_ci esas2r_targ_get_id(t, 10668c2ecf20Sopenharmony_ci a)); 10678c2ecf20Sopenharmony_ci 10688c2ecf20Sopenharmony_ci if (t2) 10698c2ecf20Sopenharmony_ci esas2r_targ_db_remove(a, t2); 10708c2ecf20Sopenharmony_ci } 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_ci /* removals complete. process arrivals. */ 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_ci dc->state = DCS_DEV_ADD; 10758c2ecf20Sopenharmony_ci dc->curr_targ = a->targetdb; 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_ci esas2r_trace_exit(); 10788c2ecf20Sopenharmony_ci 10798c2ecf20Sopenharmony_ci return false; 10808c2ecf20Sopenharmony_ci} 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_cistatic bool esas2r_disc_dev_add(struct esas2r_adapter *a, 10838c2ecf20Sopenharmony_ci struct esas2r_request *rq) 10848c2ecf20Sopenharmony_ci{ 10858c2ecf20Sopenharmony_ci struct esas2r_disc_context *dc = 10868c2ecf20Sopenharmony_ci (struct esas2r_disc_context *)rq->interrupt_cx; 10878c2ecf20Sopenharmony_ci struct esas2r_target *t = dc->curr_targ; 10888c2ecf20Sopenharmony_ci 10898c2ecf20Sopenharmony_ci if (t >= a->targetdb_end) { 10908c2ecf20Sopenharmony_ci /* done processing state changes. */ 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_ci dc->state = DCS_DISC_DONE; 10938c2ecf20Sopenharmony_ci } else if (t->new_target_state == TS_PRESENT) { 10948c2ecf20Sopenharmony_ci struct atto_vda_ae_lu *luevt = &t->lu_event; 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_ci esas2r_trace_enter(); 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_ci /* clear this now in case more events come in. */ 10998c2ecf20Sopenharmony_ci 11008c2ecf20Sopenharmony_ci t->new_target_state = TS_INVALID; 11018c2ecf20Sopenharmony_ci 11028c2ecf20Sopenharmony_ci /* setup the discovery context for adding this device. */ 11038c2ecf20Sopenharmony_ci 11048c2ecf20Sopenharmony_ci dc->curr_virt_id = esas2r_targ_get_id(t, a); 11058c2ecf20Sopenharmony_ci 11068c2ecf20Sopenharmony_ci if ((luevt->hdr.bylength >= offsetof(struct atto_vda_ae_lu, id) 11078c2ecf20Sopenharmony_ci + sizeof(struct atto_vda_ae_lu_tgt_lun_raid)) 11088c2ecf20Sopenharmony_ci && !(luevt->dwevent & VDAAE_LU_PASSTHROUGH)) { 11098c2ecf20Sopenharmony_ci dc->block_size = luevt->id.tgtlun_raid.dwblock_size; 11108c2ecf20Sopenharmony_ci dc->interleave = luevt->id.tgtlun_raid.dwinterleave; 11118c2ecf20Sopenharmony_ci } else { 11128c2ecf20Sopenharmony_ci dc->block_size = 0; 11138c2ecf20Sopenharmony_ci dc->interleave = 0; 11148c2ecf20Sopenharmony_ci } 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_ci /* determine the device type being added. */ 11178c2ecf20Sopenharmony_ci 11188c2ecf20Sopenharmony_ci if (luevt->dwevent & VDAAE_LU_PASSTHROUGH) { 11198c2ecf20Sopenharmony_ci if (luevt->dwevent & VDAAE_LU_PHYS_ID) { 11208c2ecf20Sopenharmony_ci dc->state = DCS_PT_DEV_ADDR; 11218c2ecf20Sopenharmony_ci dc->dev_addr_type = ATTO_GDA_AT_PORT; 11228c2ecf20Sopenharmony_ci dc->curr_phys_id = luevt->wphys_target_id; 11238c2ecf20Sopenharmony_ci } else { 11248c2ecf20Sopenharmony_ci esas2r_log(ESAS2R_LOG_WARN, 11258c2ecf20Sopenharmony_ci "luevt->dwevent does not have the " 11268c2ecf20Sopenharmony_ci "VDAAE_LU_PHYS_ID bit set (%s:%d)", 11278c2ecf20Sopenharmony_ci __func__, __LINE__); 11288c2ecf20Sopenharmony_ci } 11298c2ecf20Sopenharmony_ci } else { 11308c2ecf20Sopenharmony_ci dc->raid_grp_name[0] = 0; 11318c2ecf20Sopenharmony_ci 11328c2ecf20Sopenharmony_ci esas2r_targ_db_add_raid(a, dc); 11338c2ecf20Sopenharmony_ci } 11348c2ecf20Sopenharmony_ci 11358c2ecf20Sopenharmony_ci esas2r_trace("curr_virt_id: %d", dc->curr_virt_id); 11368c2ecf20Sopenharmony_ci esas2r_trace("curr_phys_id: %d", dc->curr_phys_id); 11378c2ecf20Sopenharmony_ci esas2r_trace("dwevent: %d", luevt->dwevent); 11388c2ecf20Sopenharmony_ci 11398c2ecf20Sopenharmony_ci esas2r_trace_exit(); 11408c2ecf20Sopenharmony_ci } 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_ci if (dc->state == DCS_DEV_ADD) { 11438c2ecf20Sopenharmony_ci /* go to the next device. */ 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_ci dc->curr_targ++; 11468c2ecf20Sopenharmony_ci } 11478c2ecf20Sopenharmony_ci 11488c2ecf20Sopenharmony_ci return false; 11498c2ecf20Sopenharmony_ci} 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_ci/* 11528c2ecf20Sopenharmony_ci * When discovery is done, find all requests on defer queue and 11538c2ecf20Sopenharmony_ci * test if they need to be modified. If a target is no longer present 11548c2ecf20Sopenharmony_ci * then complete the request with RS_SEL. Otherwise, update the 11558c2ecf20Sopenharmony_ci * target_id since after a hibernate it can be a different value. 11568c2ecf20Sopenharmony_ci * VDA does not make passthrough target IDs persistent. 11578c2ecf20Sopenharmony_ci */ 11588c2ecf20Sopenharmony_cistatic void esas2r_disc_fix_curr_requests(struct esas2r_adapter *a) 11598c2ecf20Sopenharmony_ci{ 11608c2ecf20Sopenharmony_ci unsigned long flags; 11618c2ecf20Sopenharmony_ci struct esas2r_target *t; 11628c2ecf20Sopenharmony_ci struct esas2r_request *rq; 11638c2ecf20Sopenharmony_ci struct list_head *element; 11648c2ecf20Sopenharmony_ci 11658c2ecf20Sopenharmony_ci /* update virt_targ_id in any outstanding esas2r_requests */ 11668c2ecf20Sopenharmony_ci 11678c2ecf20Sopenharmony_ci spin_lock_irqsave(&a->queue_lock, flags); 11688c2ecf20Sopenharmony_ci 11698c2ecf20Sopenharmony_ci list_for_each(element, &a->defer_list) { 11708c2ecf20Sopenharmony_ci rq = list_entry(element, struct esas2r_request, req_list); 11718c2ecf20Sopenharmony_ci if (rq->vrq->scsi.function == VDA_FUNC_SCSI) { 11728c2ecf20Sopenharmony_ci t = a->targetdb + rq->target_id; 11738c2ecf20Sopenharmony_ci 11748c2ecf20Sopenharmony_ci if (t->target_state == TS_PRESENT) 11758c2ecf20Sopenharmony_ci rq->vrq->scsi.target_id = le16_to_cpu( 11768c2ecf20Sopenharmony_ci t->virt_targ_id); 11778c2ecf20Sopenharmony_ci else 11788c2ecf20Sopenharmony_ci rq->req_stat = RS_SEL; 11798c2ecf20Sopenharmony_ci } 11808c2ecf20Sopenharmony_ci 11818c2ecf20Sopenharmony_ci } 11828c2ecf20Sopenharmony_ci 11838c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&a->queue_lock, flags); 11848c2ecf20Sopenharmony_ci} 1185