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