brintos

brintos / linux-shallow public Read only

0
0
Text · 28.6 KiB · ba42536 Raw
1186 lines · c
1/*2 *  linux/drivers/scsi/esas2r/esas2r_disc.c3 *      esas2r device discovery routines4 *5 *  Copyright (c) 2001-2013 ATTO Technology, Inc.6 *  (mailto:linuxdrivers@attotech.com)7 */8/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/9/*10 *  This program is free software; you can redistribute it and/or modify11 *  it under the terms of the GNU General Public License as published by12 *  the Free Software Foundation; version 2 of the License.13 *14 *  This program is distributed in the hope that it will be useful,15 *  but WITHOUT ANY WARRANTY; without even the implied warranty of16 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the17 *  GNU General Public License for more details.18 *19 *  NO WARRANTY20 *  THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR21 *  CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT22 *  LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,23 *  MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is24 *  solely responsible for determining the appropriateness of using and25 *  distributing the Program and assumes all risks associated with its26 *  exercise of rights under this Agreement, including but not limited to27 *  the risks and costs of program errors, damage to or loss of data,28 *  programs or equipment, and unavailability or interruption of operations.29 *30 *  DISCLAIMER OF LIABILITY31 *  NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY32 *  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL33 *  DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND34 *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR35 *  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE36 *  USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED37 *  HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES38 *39 *  You should have received a copy of the GNU General Public License40 *  along with this program; if not, write to the Free Software41 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA42 */43/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/44 45#include "esas2r.h"46 47/* Miscellaneous internal discovery routines */48static void esas2r_disc_abort(struct esas2r_adapter *a,49			      struct esas2r_request *rq);50static bool esas2r_disc_continue(struct esas2r_adapter *a,51				 struct esas2r_request *rq);52static void esas2r_disc_fix_curr_requests(struct esas2r_adapter *a);53static u32 esas2r_disc_get_phys_addr(struct esas2r_sg_context *sgc, u64 *addr);54static bool esas2r_disc_start_request(struct esas2r_adapter *a,55				      struct esas2r_request *rq);56 57/* Internal discovery routines that process the states */58static bool esas2r_disc_block_dev_scan(struct esas2r_adapter *a,59				       struct esas2r_request *rq);60static void esas2r_disc_block_dev_scan_cb(struct esas2r_adapter *a,61					  struct esas2r_request *rq);62static bool esas2r_disc_dev_add(struct esas2r_adapter *a,63				struct esas2r_request *rq);64static bool esas2r_disc_dev_remove(struct esas2r_adapter *a,65				   struct esas2r_request *rq);66static bool esas2r_disc_part_info(struct esas2r_adapter *a,67				  struct esas2r_request *rq);68static void esas2r_disc_part_info_cb(struct esas2r_adapter *a,69				     struct esas2r_request *rq);70static bool esas2r_disc_passthru_dev_info(struct esas2r_adapter *a,71					  struct esas2r_request *rq);72static void esas2r_disc_passthru_dev_info_cb(struct esas2r_adapter *a,73					     struct esas2r_request *rq);74static bool esas2r_disc_passthru_dev_addr(struct esas2r_adapter *a,75					  struct esas2r_request *rq);76static void esas2r_disc_passthru_dev_addr_cb(struct esas2r_adapter *a,77					     struct esas2r_request *rq);78static bool esas2r_disc_raid_grp_info(struct esas2r_adapter *a,79				      struct esas2r_request *rq);80static void esas2r_disc_raid_grp_info_cb(struct esas2r_adapter *a,81					 struct esas2r_request *rq);82 83void esas2r_disc_initialize(struct esas2r_adapter *a)84{85	struct esas2r_sas_nvram *nvr = a->nvram;86 87	esas2r_trace_enter();88 89	clear_bit(AF_DISC_IN_PROG, &a->flags);90	clear_bit(AF2_DEV_SCAN, &a->flags2);91	clear_bit(AF2_DEV_CNT_OK, &a->flags2);92 93	a->disc_start_time = jiffies_to_msecs(jiffies);94	a->disc_wait_time = nvr->dev_wait_time * 1000;95	a->disc_wait_cnt = nvr->dev_wait_count;96 97	if (a->disc_wait_cnt > ESAS2R_MAX_TARGETS)98		a->disc_wait_cnt = ESAS2R_MAX_TARGETS;99 100	/*101	 * If we are doing chip reset or power management processing, always102	 * wait for devices.  use the NVRAM device count if it is greater than103	 * previously discovered devices.104	 */105 106	esas2r_hdebug("starting discovery...");107 108	a->general_req.interrupt_cx = NULL;109 110	if (test_bit(AF_CHPRST_DETECTED, &a->flags) ||111	    test_bit(AF_POWER_MGT, &a->flags)) {112		if (a->prev_dev_cnt == 0) {113			/* Don't bother waiting if there is nothing to wait114			 * for.115			 */116			a->disc_wait_time = 0;117		} else {118			/*119			 * Set the device wait count to what was previously120			 * found.  We don't care if the user only configured121			 * a time because we know the exact count to wait for.122			 * There is no need to honor the user's wishes to123			 * always wait the full time.124			 */125			a->disc_wait_cnt = a->prev_dev_cnt;126 127			/*128			 * bump the minimum wait time to 15 seconds since the129			 * default is 3 (system boot or the boot driver usually130			 * buys us more time).131			 */132			if (a->disc_wait_time < 15000)133				a->disc_wait_time = 15000;134		}135	}136 137	esas2r_trace("disc wait count: %d", a->disc_wait_cnt);138	esas2r_trace("disc wait time: %d", a->disc_wait_time);139 140	if (a->disc_wait_time == 0)141		esas2r_disc_check_complete(a);142 143	esas2r_trace_exit();144}145 146void esas2r_disc_start_waiting(struct esas2r_adapter *a)147{148	unsigned long flags;149 150	spin_lock_irqsave(&a->mem_lock, flags);151 152	if (a->disc_ctx.disc_evt)153		esas2r_disc_start_port(a);154 155	spin_unlock_irqrestore(&a->mem_lock, flags);156}157 158void esas2r_disc_check_for_work(struct esas2r_adapter *a)159{160	struct esas2r_request *rq = &a->general_req;161 162	/* service any pending interrupts first */163 164	esas2r_polled_interrupt(a);165 166	/*167	 * now, interrupt processing may have queued up a discovery event.  go168	 * see if we have one to start.  we couldn't start it in the ISR since169	 * polled discovery would cause a deadlock.170	 */171 172	esas2r_disc_start_waiting(a);173 174	if (rq->interrupt_cx == NULL)175		return;176 177	if (rq->req_stat == RS_STARTED178	    && rq->timeout <= RQ_MAX_TIMEOUT) {179		/* wait for the current discovery request to complete. */180		esas2r_wait_request(a, rq);181 182		if (rq->req_stat == RS_TIMEOUT) {183			esas2r_disc_abort(a, rq);184			esas2r_local_reset_adapter(a);185			return;186		}187	}188 189	if (rq->req_stat == RS_PENDING190	    || rq->req_stat == RS_STARTED)191		return;192 193	esas2r_disc_continue(a, rq);194}195 196void esas2r_disc_check_complete(struct esas2r_adapter *a)197{198	unsigned long flags;199 200	esas2r_trace_enter();201 202	/* check to see if we should be waiting for devices */203	if (a->disc_wait_time) {204		u32 currtime = jiffies_to_msecs(jiffies);205		u32 time = currtime - a->disc_start_time;206 207		/*208		 * Wait until the device wait time is exhausted or the device209		 * wait count is satisfied.210		 */211		if (time < a->disc_wait_time212		    && (esas2r_targ_db_get_tgt_cnt(a) < a->disc_wait_cnt213			|| a->disc_wait_cnt == 0)) {214			/* After three seconds of waiting, schedule a scan. */215			if (time >= 3000216			    && !test_and_set_bit(AF2_DEV_SCAN, &a->flags2)) {217				spin_lock_irqsave(&a->mem_lock, flags);218				esas2r_disc_queue_event(a, DCDE_DEV_SCAN);219				spin_unlock_irqrestore(&a->mem_lock, flags);220			}221 222			esas2r_trace_exit();223			return;224		}225 226		/*227		 * We are done waiting...we think.  Adjust the wait time to228		 * consume events after the count is met.229		 */230		if (!test_and_set_bit(AF2_DEV_CNT_OK, &a->flags2))231			a->disc_wait_time = time + 3000;232 233		/* If we haven't done a full scan yet, do it now. */234		if (!test_and_set_bit(AF2_DEV_SCAN, &a->flags2)) {235			spin_lock_irqsave(&a->mem_lock, flags);236			esas2r_disc_queue_event(a, DCDE_DEV_SCAN);237			spin_unlock_irqrestore(&a->mem_lock, flags);238			esas2r_trace_exit();239			return;240		}241 242		/*243		 * Now, if there is still time left to consume events, continue244		 * waiting.245		 */246		if (time < a->disc_wait_time) {247			esas2r_trace_exit();248			return;249		}250	} else {251		if (!test_and_set_bit(AF2_DEV_SCAN, &a->flags2)) {252			spin_lock_irqsave(&a->mem_lock, flags);253			esas2r_disc_queue_event(a, DCDE_DEV_SCAN);254			spin_unlock_irqrestore(&a->mem_lock, flags);255		}256	}257 258	/* We want to stop waiting for devices. */259	a->disc_wait_time = 0;260 261	if (test_bit(AF_DISC_POLLED, &a->flags) &&262	    test_bit(AF_DISC_IN_PROG, &a->flags)) {263		/*264		 * Polled discovery is still pending so continue the active265		 * discovery until it is done.  At that point, we will stop266		 * polled discovery and transition to interrupt driven267		 * discovery.268		 */269	} else {270		/*271		 * Done waiting for devices.  Note that we get here immediately272		 * after deferred waiting completes because that is interrupt273		 * driven; i.e. There is no transition.274		 */275		esas2r_disc_fix_curr_requests(a);276		clear_bit(AF_DISC_PENDING, &a->flags);277 278		/*279		 * We have deferred target state changes until now because we280		 * don't want to report any removals (due to the first arrival)281		 * until the device wait time expires.282		 */283		set_bit(AF_PORT_CHANGE, &a->flags);284	}285 286	esas2r_trace_exit();287}288 289void esas2r_disc_queue_event(struct esas2r_adapter *a, u8 disc_evt)290{291	struct esas2r_disc_context *dc = &a->disc_ctx;292 293	esas2r_trace_enter();294 295	esas2r_trace("disc_event: %d", disc_evt);296 297	/* Initialize the discovery context */298	dc->disc_evt |= disc_evt;299 300	/*301	 * Don't start discovery before or during polled discovery.  if we did,302	 * we would have a deadlock if we are in the ISR already.303	 */304	if (!test_bit(AF_CHPRST_PENDING, &a->flags) &&305	    !test_bit(AF_DISC_POLLED, &a->flags))306		esas2r_disc_start_port(a);307 308	esas2r_trace_exit();309}310 311bool esas2r_disc_start_port(struct esas2r_adapter *a)312{313	struct esas2r_request *rq = &a->general_req;314	struct esas2r_disc_context *dc = &a->disc_ctx;315	bool ret;316 317	esas2r_trace_enter();318 319	if (test_bit(AF_DISC_IN_PROG, &a->flags)) {320		esas2r_trace_exit();321 322		return false;323	}324 325	/* If there is a discovery waiting, process it. */326	if (dc->disc_evt) {327		if (test_bit(AF_DISC_POLLED, &a->flags)328		    && a->disc_wait_time == 0) {329			/*330			 * We are doing polled discovery, but we no longer want331			 * to wait for devices.  Stop polled discovery and332			 * transition to interrupt driven discovery.333			 */334 335			esas2r_trace_exit();336 337			return false;338		}339	} else {340		/* Discovery is complete. */341 342		esas2r_hdebug("disc done");343 344		set_bit(AF_PORT_CHANGE, &a->flags);345 346		esas2r_trace_exit();347 348		return false;349	}350 351	/* Handle the discovery context */352	esas2r_trace("disc_evt: %d", dc->disc_evt);353	set_bit(AF_DISC_IN_PROG, &a->flags);354	dc->flags = 0;355 356	if (test_bit(AF_DISC_POLLED, &a->flags))357		dc->flags |= DCF_POLLED;358 359	rq->interrupt_cx = dc;360	rq->req_stat = RS_SUCCESS;361 362	/* Decode the event code */363	if (dc->disc_evt & DCDE_DEV_SCAN) {364		dc->disc_evt &= ~DCDE_DEV_SCAN;365 366		dc->flags |= DCF_DEV_SCAN;367		dc->state = DCS_BLOCK_DEV_SCAN;368	} else if (dc->disc_evt & DCDE_DEV_CHANGE) {369		dc->disc_evt &= ~DCDE_DEV_CHANGE;370 371		dc->flags |= DCF_DEV_CHANGE;372		dc->state = DCS_DEV_RMV;373	}374 375	/* Continue interrupt driven discovery */376	if (!test_bit(AF_DISC_POLLED, &a->flags))377		ret = esas2r_disc_continue(a, rq);378	else379		ret = true;380 381	esas2r_trace_exit();382 383	return ret;384}385 386static bool esas2r_disc_continue(struct esas2r_adapter *a,387				 struct esas2r_request *rq)388{389	struct esas2r_disc_context *dc =390		(struct esas2r_disc_context *)rq->interrupt_cx;391	bool rslt;392 393	/* Device discovery/removal */394	while (dc->flags & (DCF_DEV_CHANGE | DCF_DEV_SCAN)) {395		rslt = false;396 397		switch (dc->state) {398		case DCS_DEV_RMV:399 400			rslt = esas2r_disc_dev_remove(a, rq);401			break;402 403		case DCS_DEV_ADD:404 405			rslt = esas2r_disc_dev_add(a, rq);406			break;407 408		case DCS_BLOCK_DEV_SCAN:409 410			rslt = esas2r_disc_block_dev_scan(a, rq);411			break;412 413		case DCS_RAID_GRP_INFO:414 415			rslt = esas2r_disc_raid_grp_info(a, rq);416			break;417 418		case DCS_PART_INFO:419 420			rslt = esas2r_disc_part_info(a, rq);421			break;422 423		case DCS_PT_DEV_INFO:424 425			rslt = esas2r_disc_passthru_dev_info(a, rq);426			break;427		case DCS_PT_DEV_ADDR:428 429			rslt = esas2r_disc_passthru_dev_addr(a, rq);430			break;431		case DCS_DISC_DONE:432 433			dc->flags &= ~(DCF_DEV_CHANGE | DCF_DEV_SCAN);434			break;435 436		default:437 438			esas2r_bugon();439			dc->state = DCS_DISC_DONE;440			break;441		}442 443		if (rslt)444			return true;445	}446 447	/* Discovery is done...for now. */448	rq->interrupt_cx = NULL;449 450	if (!test_bit(AF_DISC_PENDING, &a->flags))451		esas2r_disc_fix_curr_requests(a);452 453	clear_bit(AF_DISC_IN_PROG, &a->flags);454 455	/* Start the next discovery. */456	return esas2r_disc_start_port(a);457}458 459static bool esas2r_disc_start_request(struct esas2r_adapter *a,460				      struct esas2r_request *rq)461{462	unsigned long flags;463 464	/* Set the timeout to a minimum value. */465	if (rq->timeout < ESAS2R_DEFAULT_TMO)466		rq->timeout = ESAS2R_DEFAULT_TMO;467 468	/*469	 * Override the request type to distinguish discovery requests.  If we470	 * end up deferring the request, esas2r_disc_local_start_request()471	 * will be called to restart it.472	 */473	rq->req_type = RT_DISC_REQ;474 475	spin_lock_irqsave(&a->queue_lock, flags);476 477	if (!test_bit(AF_CHPRST_PENDING, &a->flags) &&478	    !test_bit(AF_FLASHING, &a->flags))479		esas2r_disc_local_start_request(a, rq);480	else481		list_add_tail(&rq->req_list, &a->defer_list);482 483	spin_unlock_irqrestore(&a->queue_lock, flags);484 485	return true;486}487 488void esas2r_disc_local_start_request(struct esas2r_adapter *a,489				     struct esas2r_request *rq)490{491	esas2r_trace_enter();492 493	list_add_tail(&rq->req_list, &a->active_list);494 495	esas2r_start_vda_request(a, rq);496 497	esas2r_trace_exit();498 499	return;500}501 502static void esas2r_disc_abort(struct esas2r_adapter *a,503			      struct esas2r_request *rq)504{505	struct esas2r_disc_context *dc =506		(struct esas2r_disc_context *)rq->interrupt_cx;507 508	esas2r_trace_enter();509 510	/* abort the current discovery */511 512	dc->state = DCS_DISC_DONE;513 514	esas2r_trace_exit();515}516 517static bool esas2r_disc_block_dev_scan(struct esas2r_adapter *a,518				       struct esas2r_request *rq)519{520	struct esas2r_disc_context *dc =521		(struct esas2r_disc_context *)rq->interrupt_cx;522	bool rslt;523 524	esas2r_trace_enter();525 526	esas2r_rq_init_request(rq, a);527 528	esas2r_build_mgt_req(a,529			     rq,530			     VDAMGT_DEV_SCAN,531			     0,532			     0,533			     0,534			     NULL);535 536	rq->comp_cb = esas2r_disc_block_dev_scan_cb;537 538	rq->timeout = 30000;539	rq->interrupt_cx = dc;540 541	rslt = esas2r_disc_start_request(a, rq);542 543	esas2r_trace_exit();544 545	return rslt;546}547 548static void esas2r_disc_block_dev_scan_cb(struct esas2r_adapter *a,549					  struct esas2r_request *rq)550{551	struct esas2r_disc_context *dc =552		(struct esas2r_disc_context *)rq->interrupt_cx;553	unsigned long flags;554 555	esas2r_trace_enter();556 557	spin_lock_irqsave(&a->mem_lock, flags);558 559	if (rq->req_stat == RS_SUCCESS)560		dc->scan_gen = rq->func_rsp.mgt_rsp.scan_generation;561 562	dc->state = DCS_RAID_GRP_INFO;563	dc->raid_grp_ix = 0;564 565	esas2r_rq_destroy_request(rq, a);566 567	/* continue discovery if it's interrupt driven */568 569	if (!(dc->flags & DCF_POLLED))570		esas2r_disc_continue(a, rq);571 572	spin_unlock_irqrestore(&a->mem_lock, flags);573 574	esas2r_trace_exit();575}576 577static bool esas2r_disc_raid_grp_info(struct esas2r_adapter *a,578				      struct esas2r_request *rq)579{580	struct esas2r_disc_context *dc =581		(struct esas2r_disc_context *)rq->interrupt_cx;582	bool rslt;583	struct atto_vda_grp_info *grpinfo;584 585	esas2r_trace_enter();586 587	esas2r_trace("raid_group_idx: %d", dc->raid_grp_ix);588 589	if (dc->raid_grp_ix >= VDA_MAX_RAID_GROUPS) {590		dc->state = DCS_DISC_DONE;591 592		esas2r_trace_exit();593 594		return false;595	}596 597	esas2r_rq_init_request(rq, a);598 599	grpinfo = &rq->vda_rsp_data->mgt_data.data.grp_info;600 601	memset(grpinfo, 0, sizeof(struct atto_vda_grp_info));602 603	esas2r_build_mgt_req(a,604			     rq,605			     VDAMGT_GRP_INFO,606			     dc->scan_gen,607			     0,608			     sizeof(struct atto_vda_grp_info),609			     NULL);610 611	grpinfo->grp_index = dc->raid_grp_ix;612 613	rq->comp_cb = esas2r_disc_raid_grp_info_cb;614 615	rq->interrupt_cx = dc;616 617	rslt = esas2r_disc_start_request(a, rq);618 619	esas2r_trace_exit();620 621	return rslt;622}623 624static void esas2r_disc_raid_grp_info_cb(struct esas2r_adapter *a,625					 struct esas2r_request *rq)626{627	struct esas2r_disc_context *dc =628		(struct esas2r_disc_context *)rq->interrupt_cx;629	unsigned long flags;630	struct atto_vda_grp_info *grpinfo;631 632	esas2r_trace_enter();633 634	spin_lock_irqsave(&a->mem_lock, flags);635 636	if (rq->req_stat == RS_SCAN_GEN) {637		dc->scan_gen = rq->func_rsp.mgt_rsp.scan_generation;638		dc->raid_grp_ix = 0;639		goto done;640	}641 642	if (rq->req_stat == RS_SUCCESS) {643		grpinfo = &rq->vda_rsp_data->mgt_data.data.grp_info;644 645		if (grpinfo->status != VDA_GRP_STAT_ONLINE646		    && grpinfo->status != VDA_GRP_STAT_DEGRADED) {647			/* go to the next group. */648 649			dc->raid_grp_ix++;650		} else {651			memcpy(&dc->raid_grp_name[0],652			       &grpinfo->grp_name[0],653			       sizeof(grpinfo->grp_name));654 655			dc->interleave = le32_to_cpu(grpinfo->interleave);656			dc->block_size = le32_to_cpu(grpinfo->block_size);657 658			dc->state = DCS_PART_INFO;659			dc->part_num = 0;660		}661	} else {662		if (!(rq->req_stat == RS_GRP_INVALID)) {663			esas2r_log(ESAS2R_LOG_WARN,664				   "A request for RAID group info failed - "665				   "returned with %x",666				   rq->req_stat);667		}668 669		dc->dev_ix = 0;670		dc->state = DCS_PT_DEV_INFO;671	}672 673done:674 675	esas2r_rq_destroy_request(rq, a);676 677	/* continue discovery if it's interrupt driven */678 679	if (!(dc->flags & DCF_POLLED))680		esas2r_disc_continue(a, rq);681 682	spin_unlock_irqrestore(&a->mem_lock, flags);683 684	esas2r_trace_exit();685}686 687static bool esas2r_disc_part_info(struct esas2r_adapter *a,688				  struct esas2r_request *rq)689{690	struct esas2r_disc_context *dc =691		(struct esas2r_disc_context *)rq->interrupt_cx;692	bool rslt;693	struct atto_vdapart_info *partinfo;694 695	esas2r_trace_enter();696 697	esas2r_trace("part_num: %d", dc->part_num);698 699	if (dc->part_num >= VDA_MAX_PARTITIONS) {700		dc->state = DCS_RAID_GRP_INFO;701		dc->raid_grp_ix++;702 703		esas2r_trace_exit();704 705		return false;706	}707 708	esas2r_rq_init_request(rq, a);709 710	partinfo = &rq->vda_rsp_data->mgt_data.data.part_info;711 712	memset(partinfo, 0, sizeof(struct atto_vdapart_info));713 714	esas2r_build_mgt_req(a,715			     rq,716			     VDAMGT_PART_INFO,717			     dc->scan_gen,718			     0,719			     sizeof(struct atto_vdapart_info),720			     NULL);721 722	partinfo->part_no = dc->part_num;723 724	memcpy(&partinfo->grp_name[0],725	       &dc->raid_grp_name[0],726	       sizeof(partinfo->grp_name));727 728	rq->comp_cb = esas2r_disc_part_info_cb;729 730	rq->interrupt_cx = dc;731 732	rslt = esas2r_disc_start_request(a, rq);733 734	esas2r_trace_exit();735 736	return rslt;737}738 739static void esas2r_disc_part_info_cb(struct esas2r_adapter *a,740				     struct esas2r_request *rq)741{742	struct esas2r_disc_context *dc =743		(struct esas2r_disc_context *)rq->interrupt_cx;744	unsigned long flags;745	struct atto_vdapart_info *partinfo;746 747	esas2r_trace_enter();748 749	spin_lock_irqsave(&a->mem_lock, flags);750 751	if (rq->req_stat == RS_SCAN_GEN) {752		dc->scan_gen = rq->func_rsp.mgt_rsp.scan_generation;753		dc->raid_grp_ix = 0;754		dc->state = DCS_RAID_GRP_INFO;755	} else if (rq->req_stat == RS_SUCCESS) {756		partinfo = &rq->vda_rsp_data->mgt_data.data.part_info;757 758		dc->part_num = partinfo->part_no;759 760		dc->curr_virt_id = le16_to_cpu(partinfo->target_id);761 762		esas2r_targ_db_add_raid(a, dc);763 764		dc->part_num++;765	} else {766		if (!(rq->req_stat == RS_PART_LAST)) {767			esas2r_log(ESAS2R_LOG_WARN,768				   "A request for RAID group partition info "769				   "failed - status:%d", rq->req_stat);770		}771 772		dc->state = DCS_RAID_GRP_INFO;773		dc->raid_grp_ix++;774	}775 776	esas2r_rq_destroy_request(rq, a);777 778	/* continue discovery if it's interrupt driven */779 780	if (!(dc->flags & DCF_POLLED))781		esas2r_disc_continue(a, rq);782 783	spin_unlock_irqrestore(&a->mem_lock, flags);784 785	esas2r_trace_exit();786}787 788static bool esas2r_disc_passthru_dev_info(struct esas2r_adapter *a,789					  struct esas2r_request *rq)790{791	struct esas2r_disc_context *dc =792		(struct esas2r_disc_context *)rq->interrupt_cx;793	bool rslt;794	struct atto_vda_devinfo *devinfo;795 796	esas2r_trace_enter();797 798	esas2r_trace("dev_ix: %d", dc->dev_ix);799 800	esas2r_rq_init_request(rq, a);801 802	devinfo = &rq->vda_rsp_data->mgt_data.data.dev_info;803 804	memset(devinfo, 0, sizeof(struct atto_vda_devinfo));805 806	esas2r_build_mgt_req(a,807			     rq,808			     VDAMGT_DEV_PT_INFO,809			     dc->scan_gen,810			     dc->dev_ix,811			     sizeof(struct atto_vda_devinfo),812			     NULL);813 814	rq->comp_cb = esas2r_disc_passthru_dev_info_cb;815 816	rq->interrupt_cx = dc;817 818	rslt = esas2r_disc_start_request(a, rq);819 820	esas2r_trace_exit();821 822	return rslt;823}824 825static void esas2r_disc_passthru_dev_info_cb(struct esas2r_adapter *a,826					     struct esas2r_request *rq)827{828	struct esas2r_disc_context *dc =829		(struct esas2r_disc_context *)rq->interrupt_cx;830	unsigned long flags;831	struct atto_vda_devinfo *devinfo;832 833	esas2r_trace_enter();834 835	spin_lock_irqsave(&a->mem_lock, flags);836 837	if (rq->req_stat == RS_SCAN_GEN) {838		dc->scan_gen = rq->func_rsp.mgt_rsp.scan_generation;839		dc->dev_ix = 0;840		dc->state = DCS_PT_DEV_INFO;841	} else if (rq->req_stat == RS_SUCCESS) {842		devinfo = &rq->vda_rsp_data->mgt_data.data.dev_info;843 844		dc->dev_ix = le16_to_cpu(rq->func_rsp.mgt_rsp.dev_index);845 846		dc->curr_virt_id = le16_to_cpu(devinfo->target_id);847 848		if (le16_to_cpu(devinfo->features) & VDADEVFEAT_PHYS_ID) {849			dc->curr_phys_id =850				le16_to_cpu(devinfo->phys_target_id);851			dc->dev_addr_type = ATTO_GDA_AT_PORT;852			dc->state = DCS_PT_DEV_ADDR;853 854			esas2r_trace("curr_virt_id: %d", dc->curr_virt_id);855			esas2r_trace("curr_phys_id: %d", dc->curr_phys_id);856		} else {857			dc->dev_ix++;858		}859	} else {860		if (!(rq->req_stat == RS_DEV_INVALID)) {861			esas2r_log(ESAS2R_LOG_WARN,862				   "A request for device information failed - "863				   "status:%d", rq->req_stat);864		}865 866		dc->state = DCS_DISC_DONE;867	}868 869	esas2r_rq_destroy_request(rq, a);870 871	/* continue discovery if it's interrupt driven */872 873	if (!(dc->flags & DCF_POLLED))874		esas2r_disc_continue(a, rq);875 876	spin_unlock_irqrestore(&a->mem_lock, flags);877 878	esas2r_trace_exit();879}880 881static bool esas2r_disc_passthru_dev_addr(struct esas2r_adapter *a,882					  struct esas2r_request *rq)883{884	struct esas2r_disc_context *dc =885		(struct esas2r_disc_context *)rq->interrupt_cx;886	bool rslt;887	struct atto_ioctl *hi;888	struct esas2r_sg_context sgc;889 890	esas2r_trace_enter();891 892	esas2r_rq_init_request(rq, a);893 894	/* format the request. */895 896	sgc.cur_offset = NULL;897	sgc.get_phys_addr = (PGETPHYSADDR)esas2r_disc_get_phys_addr;898	sgc.length = offsetof(struct atto_ioctl, data)899		     + sizeof(struct atto_hba_get_device_address);900 901	esas2r_sgc_init(&sgc, a, rq, rq->vrq->ioctl.sge);902 903	esas2r_build_ioctl_req(a, rq, sgc.length, VDA_IOCTL_HBA);904 905	if (!esas2r_build_sg_list(a, rq, &sgc)) {906		esas2r_rq_destroy_request(rq, a);907 908		esas2r_trace_exit();909 910		return false;911	}912 913	rq->comp_cb = esas2r_disc_passthru_dev_addr_cb;914 915	rq->interrupt_cx = dc;916 917	/* format the IOCTL data. */918 919	hi = (struct atto_ioctl *)a->disc_buffer;920 921	memset(a->disc_buffer, 0, ESAS2R_DISC_BUF_LEN);922 923	hi->version = ATTO_VER_GET_DEV_ADDR0;924	hi->function = ATTO_FUNC_GET_DEV_ADDR;925	hi->flags = HBAF_TUNNEL;926 927	hi->data.get_dev_addr.target_id = le32_to_cpu(dc->curr_phys_id);928	hi->data.get_dev_addr.addr_type = dc->dev_addr_type;929 930	/* start it up. */931 932	rslt = esas2r_disc_start_request(a, rq);933 934	esas2r_trace_exit();935 936	return rslt;937}938 939static void esas2r_disc_passthru_dev_addr_cb(struct esas2r_adapter *a,940					     struct esas2r_request *rq)941{942	struct esas2r_disc_context *dc =943		(struct esas2r_disc_context *)rq->interrupt_cx;944	struct esas2r_target *t = NULL;945	unsigned long flags;946	struct atto_ioctl *hi;947	u16 addrlen;948 949	esas2r_trace_enter();950 951	spin_lock_irqsave(&a->mem_lock, flags);952 953	hi = (struct atto_ioctl *)a->disc_buffer;954 955	if (rq->req_stat == RS_SUCCESS956	    && hi->status == ATTO_STS_SUCCESS) {957		addrlen = le16_to_cpu(hi->data.get_dev_addr.addr_len);958 959		if (dc->dev_addr_type == ATTO_GDA_AT_PORT) {960			if (addrlen == sizeof(u64))961				memcpy(&dc->sas_addr,962				       &hi->data.get_dev_addr.address[0],963				       addrlen);964			else965				memset(&dc->sas_addr, 0, sizeof(dc->sas_addr));966 967			/* Get the unique identifier. */968			dc->dev_addr_type = ATTO_GDA_AT_UNIQUE;969 970			goto next_dev_addr;971		} else {972			/* Add the pass through target. */973			if (HIBYTE(addrlen) == 0) {974				t = esas2r_targ_db_add_pthru(a,975							     dc,976							     &hi->data.977							     get_dev_addr.978							     address[0],979							     (u8)hi->data.980							     get_dev_addr.981							     addr_len);982 983				if (t)984					memcpy(&t->sas_addr, &dc->sas_addr,985					       sizeof(t->sas_addr));986			} else {987				/* getting the back end data failed */988 989				esas2r_log(ESAS2R_LOG_WARN,990					   "an error occurred retrieving the "991					   "back end data (%s:%d)",992					   __func__,993					   __LINE__);994			}995		}996	} else {997		/* getting the back end data failed */998 999		esas2r_log(ESAS2R_LOG_WARN,1000			   "an error occurred retrieving the back end data - "1001			   "rq->req_stat:%d hi->status:%d",1002			   rq->req_stat, hi->status);1003	}1004 1005	/* proceed to the next device. */1006 1007	if (dc->flags & DCF_DEV_SCAN) {1008		dc->dev_ix++;1009		dc->state = DCS_PT_DEV_INFO;1010	} else if (dc->flags & DCF_DEV_CHANGE) {1011		dc->curr_targ++;1012		dc->state = DCS_DEV_ADD;1013	} else {1014		esas2r_bugon();1015	}1016 1017next_dev_addr:1018	esas2r_rq_destroy_request(rq, a);1019 1020	/* continue discovery if it's interrupt driven */1021 1022	if (!(dc->flags & DCF_POLLED))1023		esas2r_disc_continue(a, rq);1024 1025	spin_unlock_irqrestore(&a->mem_lock, flags);1026 1027	esas2r_trace_exit();1028}1029 1030static u32 esas2r_disc_get_phys_addr(struct esas2r_sg_context *sgc, u64 *addr)1031{1032	struct esas2r_adapter *a = sgc->adapter;1033 1034	if (sgc->length > ESAS2R_DISC_BUF_LEN) {1035		esas2r_bugon();1036	}1037 1038	*addr = a->uncached_phys1039		+ (u64)((u8 *)a->disc_buffer - a->uncached);1040 1041	return sgc->length;1042}1043 1044static bool esas2r_disc_dev_remove(struct esas2r_adapter *a,1045				   struct esas2r_request *rq)1046{1047	struct esas2r_disc_context *dc =1048		(struct esas2r_disc_context *)rq->interrupt_cx;1049	struct esas2r_target *t;1050	struct esas2r_target *t2;1051 1052	esas2r_trace_enter();1053 1054	/* process removals. */1055 1056	for (t = a->targetdb; t < a->targetdb_end; t++) {1057		if (t->new_target_state != TS_NOT_PRESENT)1058			continue;1059 1060		t->new_target_state = TS_INVALID;1061 1062		/* remove the right target! */1063 1064		t2 =1065			esas2r_targ_db_find_by_virt_id(a,1066						       esas2r_targ_get_id(t,1067									  a));1068 1069		if (t2)1070			esas2r_targ_db_remove(a, t2);1071	}1072 1073	/* removals complete.  process arrivals. */1074 1075	dc->state = DCS_DEV_ADD;1076	dc->curr_targ = a->targetdb;1077 1078	esas2r_trace_exit();1079 1080	return false;1081}1082 1083static bool esas2r_disc_dev_add(struct esas2r_adapter *a,1084				struct esas2r_request *rq)1085{1086	struct esas2r_disc_context *dc =1087		(struct esas2r_disc_context *)rq->interrupt_cx;1088	struct esas2r_target *t = dc->curr_targ;1089 1090	if (t >= a->targetdb_end) {1091		/* done processing state changes. */1092 1093		dc->state = DCS_DISC_DONE;1094	} else if (t->new_target_state == TS_PRESENT) {1095		struct atto_vda_ae_lu *luevt = &t->lu_event;1096 1097		esas2r_trace_enter();1098 1099		/* clear this now in case more events come in. */1100 1101		t->new_target_state = TS_INVALID;1102 1103		/* setup the discovery context for adding this device. */1104 1105		dc->curr_virt_id = esas2r_targ_get_id(t, a);1106 1107		if ((luevt->hdr.bylength >= offsetof(struct atto_vda_ae_lu, id)1108		     + sizeof(struct atto_vda_ae_lu_tgt_lun_raid))1109		    && !(luevt->dwevent & VDAAE_LU_PASSTHROUGH)) {1110			dc->block_size = luevt->id.tgtlun_raid.dwblock_size;1111			dc->interleave = luevt->id.tgtlun_raid.dwinterleave;1112		} else {1113			dc->block_size = 0;1114			dc->interleave = 0;1115		}1116 1117		/* determine the device type being added. */1118 1119		if (luevt->dwevent & VDAAE_LU_PASSTHROUGH) {1120			if (luevt->dwevent & VDAAE_LU_PHYS_ID) {1121				dc->state = DCS_PT_DEV_ADDR;1122				dc->dev_addr_type = ATTO_GDA_AT_PORT;1123				dc->curr_phys_id = luevt->wphys_target_id;1124			} else {1125				esas2r_log(ESAS2R_LOG_WARN,1126					   "luevt->dwevent does not have the "1127					   "VDAAE_LU_PHYS_ID bit set (%s:%d)",1128					   __func__, __LINE__);1129			}1130		} else {1131			dc->raid_grp_name[0] = 0;1132 1133			esas2r_targ_db_add_raid(a, dc);1134		}1135 1136		esas2r_trace("curr_virt_id: %d", dc->curr_virt_id);1137		esas2r_trace("curr_phys_id: %d", dc->curr_phys_id);1138		esas2r_trace("dwevent: %d", luevt->dwevent);1139 1140		esas2r_trace_exit();1141	}1142 1143	if (dc->state == DCS_DEV_ADD) {1144		/* go to the next device. */1145 1146		dc->curr_targ++;1147	}1148 1149	return false;1150}1151 1152/*1153 * When discovery is done, find all requests on defer queue and1154 * test if they need to be modified. If a target is no longer present1155 * then complete the request with RS_SEL. Otherwise, update the1156 * target_id since after a hibernate it can be a different value.1157 * VDA does not make passthrough target IDs persistent.1158 */1159static void esas2r_disc_fix_curr_requests(struct esas2r_adapter *a)1160{1161	unsigned long flags;1162	struct esas2r_target *t;1163	struct esas2r_request *rq;1164	struct list_head *element;1165 1166	/* update virt_targ_id in any outstanding esas2r_requests  */1167 1168	spin_lock_irqsave(&a->queue_lock, flags);1169 1170	list_for_each(element, &a->defer_list) {1171		rq = list_entry(element, struct esas2r_request, req_list);1172		if (rq->vrq->scsi.function == VDA_FUNC_SCSI) {1173			t = a->targetdb + rq->target_id;1174 1175			if (t->target_state == TS_PRESENT)1176				rq->vrq->scsi.target_id = le16_to_cpu(1177					t->virt_targ_id);1178			else1179				rq->req_stat = RS_SEL;1180		}1181 1182	}1183 1184	spin_unlock_irqrestore(&a->queue_lock, flags);1185}1186