brintos

brintos / linux-shallow public Read only

0
0
Text · 24.1 KiB · 5281d93 Raw
945 lines · c
1/*2 *  linux/drivers/scsi/esas2r/esas2r_int.c3 *      esas2r interrupt handling4 *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/* Local function prototypes */48static void esas2r_doorbell_interrupt(struct esas2r_adapter *a, u32 doorbell);49static void esas2r_get_outbound_responses(struct esas2r_adapter *a);50static void esas2r_process_bus_reset(struct esas2r_adapter *a);51 52/*53 * Poll the adapter for interrupts and service them.54 * This function handles both legacy interrupts and MSI.55 */56void esas2r_polled_interrupt(struct esas2r_adapter *a)57{58	u32 intstat;59	u32 doorbell;60 61	esas2r_disable_chip_interrupts(a);62 63	intstat = esas2r_read_register_dword(a, MU_INT_STATUS_OUT);64 65	if (intstat & MU_INTSTAT_POST_OUT) {66		/* clear the interrupt */67 68		esas2r_write_register_dword(a, MU_OUT_LIST_INT_STAT,69					    MU_OLIS_INT);70		esas2r_flush_register_dword(a, MU_OUT_LIST_INT_STAT);71 72		esas2r_get_outbound_responses(a);73	}74 75	if (intstat & MU_INTSTAT_DRBL) {76		doorbell = esas2r_read_register_dword(a, MU_DOORBELL_OUT);77		if (doorbell != 0)78			esas2r_doorbell_interrupt(a, doorbell);79	}80 81	esas2r_enable_chip_interrupts(a);82 83	if (atomic_read(&a->disable_cnt) == 0)84		esas2r_do_deferred_processes(a);85}86 87/*88 * Legacy and MSI interrupt handlers.  Note that the legacy interrupt handler89 * schedules a TASKLET to process events, whereas the MSI handler just90 * processes interrupt events directly.91 */92irqreturn_t esas2r_interrupt(int irq, void *dev_id)93{94	struct esas2r_adapter *a = (struct esas2r_adapter *)dev_id;95 96	if (!esas2r_adapter_interrupt_pending(a))97		return IRQ_NONE;98 99	set_bit(AF2_INT_PENDING, &a->flags2);100	esas2r_schedule_tasklet(a);101 102	return IRQ_HANDLED;103}104 105void esas2r_adapter_interrupt(struct esas2r_adapter *a)106{107	u32 doorbell;108 109	if (likely(a->int_stat & MU_INTSTAT_POST_OUT)) {110		/* clear the interrupt */111		esas2r_write_register_dword(a, MU_OUT_LIST_INT_STAT,112					    MU_OLIS_INT);113		esas2r_flush_register_dword(a, MU_OUT_LIST_INT_STAT);114		esas2r_get_outbound_responses(a);115	}116 117	if (unlikely(a->int_stat & MU_INTSTAT_DRBL)) {118		doorbell = esas2r_read_register_dword(a, MU_DOORBELL_OUT);119		if (doorbell != 0)120			esas2r_doorbell_interrupt(a, doorbell);121	}122 123	a->int_mask = ESAS2R_INT_STS_MASK;124 125	esas2r_enable_chip_interrupts(a);126 127	if (likely(atomic_read(&a->disable_cnt) == 0))128		esas2r_do_deferred_processes(a);129}130 131irqreturn_t esas2r_msi_interrupt(int irq, void *dev_id)132{133	struct esas2r_adapter *a = (struct esas2r_adapter *)dev_id;134	u32 intstat;135	u32 doorbell;136 137	intstat = esas2r_read_register_dword(a, MU_INT_STATUS_OUT);138 139	if (likely(intstat & MU_INTSTAT_POST_OUT)) {140		/* clear the interrupt */141 142		esas2r_write_register_dword(a, MU_OUT_LIST_INT_STAT,143					    MU_OLIS_INT);144		esas2r_flush_register_dword(a, MU_OUT_LIST_INT_STAT);145 146		esas2r_get_outbound_responses(a);147	}148 149	if (unlikely(intstat & MU_INTSTAT_DRBL)) {150		doorbell = esas2r_read_register_dword(a, MU_DOORBELL_OUT);151		if (doorbell != 0)152			esas2r_doorbell_interrupt(a, doorbell);153	}154 155	/*156	 * Work around a chip bug and force a new MSI to be sent if one is157	 * still pending.158	 */159	esas2r_disable_chip_interrupts(a);160	esas2r_enable_chip_interrupts(a);161 162	if (likely(atomic_read(&a->disable_cnt) == 0))163		esas2r_do_deferred_processes(a);164 165	esas2r_do_tasklet_tasks(a);166 167	return 1;168}169 170 171 172static void esas2r_handle_outbound_rsp_err(struct esas2r_adapter *a,173					   struct esas2r_request *rq,174					   struct atto_vda_ob_rsp *rsp)175{176 177	/*178	 * For I/O requests, only copy the response if an error179	 * occurred and setup a callback to do error processing.180	 */181	if (unlikely(rq->req_stat != RS_SUCCESS)) {182		memcpy(&rq->func_rsp, &rsp->func_rsp, sizeof(rsp->func_rsp));183 184		if (rq->req_stat == RS_ABORTED) {185			if (rq->timeout > RQ_MAX_TIMEOUT)186				rq->req_stat = RS_TIMEOUT;187		} else if (rq->req_stat == RS_SCSI_ERROR) {188			u8 scsistatus = rq->func_rsp.scsi_rsp.scsi_stat;189 190			esas2r_trace("scsistatus: %x", scsistatus);191 192			/* Any of these are a good result. */193			if (scsistatus == SAM_STAT_GOOD || scsistatus ==194			    SAM_STAT_CONDITION_MET || scsistatus ==195			    SAM_STAT_INTERMEDIATE || scsistatus ==196			    SAM_STAT_INTERMEDIATE_CONDITION_MET) {197				rq->req_stat = RS_SUCCESS;198				rq->func_rsp.scsi_rsp.scsi_stat =199					SAM_STAT_GOOD;200			}201		}202	}203}204 205static void esas2r_get_outbound_responses(struct esas2r_adapter *a)206{207	struct atto_vda_ob_rsp *rsp;208	u32 rspput_ptr;209	u32 rspget_ptr;210	struct esas2r_request *rq;211	u32 handle;212	unsigned long flags;213 214	LIST_HEAD(comp_list);215 216	esas2r_trace_enter();217 218	spin_lock_irqsave(&a->queue_lock, flags);219 220	/* Get the outbound limit and pointers */221	rspput_ptr = le32_to_cpu(*a->outbound_copy) & MU_OLC_WRT_PTR;222	rspget_ptr = a->last_read;223 224	esas2r_trace("rspput_ptr: %x, rspget_ptr: %x", rspput_ptr, rspget_ptr);225 226	/* If we don't have anything to process, get out */227	if (unlikely(rspget_ptr == rspput_ptr)) {228		spin_unlock_irqrestore(&a->queue_lock, flags);229		esas2r_trace_exit();230		return;231	}232 233	/* Make sure the firmware is healthy */234	if (unlikely(rspput_ptr >= a->list_size)) {235		spin_unlock_irqrestore(&a->queue_lock, flags);236		esas2r_bugon();237		esas2r_local_reset_adapter(a);238		esas2r_trace_exit();239		return;240	}241 242	do {243		rspget_ptr++;244 245		if (rspget_ptr >= a->list_size)246			rspget_ptr = 0;247 248		rsp = (struct atto_vda_ob_rsp *)a->outbound_list_md.virt_addr249		      + rspget_ptr;250 251		handle = rsp->handle;252 253		/* Verify the handle range */254		if (unlikely(LOWORD(handle) == 0255			     || LOWORD(handle) > num_requests +256			     num_ae_requests + 1)) {257			esas2r_bugon();258			continue;259		}260 261		/* Get the request for this handle */262		rq = a->req_table[LOWORD(handle)];263 264		if (unlikely(rq == NULL || rq->vrq->scsi.handle != handle)) {265			esas2r_bugon();266			continue;267		}268 269		list_del(&rq->req_list);270 271		/* Get the completion status */272		rq->req_stat = rsp->req_stat;273 274		esas2r_trace("handle: %x", handle);275		esas2r_trace("rq: %p", rq);276		esas2r_trace("req_status: %x", rq->req_stat);277 278		if (likely(rq->vrq->scsi.function == VDA_FUNC_SCSI)) {279			esas2r_handle_outbound_rsp_err(a, rq, rsp);280		} else {281			/*282			 * Copy the outbound completion struct for non-I/O283			 * requests.284			 */285			memcpy(&rq->func_rsp, &rsp->func_rsp,286			       sizeof(rsp->func_rsp));287		}288 289		/* Queue the request for completion. */290		list_add_tail(&rq->comp_list, &comp_list);291 292	} while (rspget_ptr != rspput_ptr);293 294	a->last_read = rspget_ptr;295	spin_unlock_irqrestore(&a->queue_lock, flags);296 297	esas2r_comp_list_drain(a, &comp_list);298	esas2r_trace_exit();299}300 301/*302 * Perform all deferred processes for the adapter.  Deferred303 * processes can only be done while the current interrupt304 * disable_cnt for the adapter is zero.305 */306void esas2r_do_deferred_processes(struct esas2r_adapter *a)307{308	int startreqs = 2;309	struct esas2r_request *rq;310	unsigned long flags;311 312	/*313	 * startreqs is used to control starting requests314	 * that are on the deferred queue315	 *  = 0 - do not start any requests316	 *  = 1 - can start discovery requests317	 *  = 2 - can start any request318	 */319 320	if (test_bit(AF_CHPRST_PENDING, &a->flags) ||321	    test_bit(AF_FLASHING, &a->flags))322		startreqs = 0;323	else if (test_bit(AF_DISC_PENDING, &a->flags))324		startreqs = 1;325 326	atomic_inc(&a->disable_cnt);327 328	/* Clear off the completed list to be processed later. */329 330	if (esas2r_is_tasklet_pending(a)) {331		esas2r_schedule_tasklet(a);332 333		startreqs = 0;334	}335 336	/*337	 * If we can start requests then traverse the defer queue338	 * looking for requests to start or complete339	 */340	if (startreqs && !list_empty(&a->defer_list)) {341		LIST_HEAD(comp_list);342		struct list_head *element, *next;343 344		spin_lock_irqsave(&a->queue_lock, flags);345 346		list_for_each_safe(element, next, &a->defer_list) {347			rq = list_entry(element, struct esas2r_request,348					req_list);349 350			if (rq->req_stat != RS_PENDING) {351				list_del(element);352				list_add_tail(&rq->comp_list, &comp_list);353			}354			/*355			 * Process discovery and OS requests separately.  We356			 * can't hold up discovery requests when discovery is357			 * pending.  In general, there may be different sets of358			 * conditions for starting different types of requests.359			 */360			else if (rq->req_type == RT_DISC_REQ) {361				list_del(element);362				esas2r_disc_local_start_request(a, rq);363			} else if (startreqs == 2) {364				list_del(element);365				esas2r_local_start_request(a, rq);366 367				/*368				 * Flashing could have been set by last local369				 * start370				 */371				if (test_bit(AF_FLASHING, &a->flags))372					break;373			}374		}375 376		spin_unlock_irqrestore(&a->queue_lock, flags);377		esas2r_comp_list_drain(a, &comp_list);378	}379 380	atomic_dec(&a->disable_cnt);381}382 383/*384 * Process an adapter reset (or one that is about to happen)385 * by making sure all outstanding requests are completed that386 * haven't been already.387 */388void esas2r_process_adapter_reset(struct esas2r_adapter *a)389{390	struct esas2r_request *rq = &a->general_req;391	unsigned long flags;392	struct esas2r_disc_context *dc;393 394	LIST_HEAD(comp_list);395	struct list_head *element;396 397	esas2r_trace_enter();398 399	spin_lock_irqsave(&a->queue_lock, flags);400 401	/* abort the active discovery, if any.   */402 403	if (rq->interrupt_cx) {404		dc = (struct esas2r_disc_context *)rq->interrupt_cx;405 406		dc->disc_evt = 0;407 408		clear_bit(AF_DISC_IN_PROG, &a->flags);409	}410 411	/*412	 * just clear the interrupt callback for now.  it will be dequeued if413	 * and when we find it on the active queue and we don't want the414	 * callback called.  also set the dummy completion callback in case we415	 * were doing an I/O request.416	 */417 418	rq->interrupt_cx = NULL;419	rq->interrupt_cb = NULL;420 421	rq->comp_cb = esas2r_dummy_complete;422 423	/* Reset the read and write pointers */424 425	*a->outbound_copy =426		a->last_write =427			a->last_read = a->list_size - 1;428 429	set_bit(AF_COMM_LIST_TOGGLE, &a->flags);430 431	/* Kill all the requests on the active list */432	list_for_each(element, &a->defer_list) {433		rq = list_entry(element, struct esas2r_request, req_list);434 435		if (rq->req_stat == RS_STARTED)436			if (esas2r_ioreq_aborted(a, rq, RS_ABORTED))437				list_add_tail(&rq->comp_list, &comp_list);438	}439 440	spin_unlock_irqrestore(&a->queue_lock, flags);441	esas2r_comp_list_drain(a, &comp_list);442	esas2r_process_bus_reset(a);443	esas2r_trace_exit();444}445 446static void esas2r_process_bus_reset(struct esas2r_adapter *a)447{448	struct esas2r_request *rq;449	struct list_head *element;450	unsigned long flags;451 452	LIST_HEAD(comp_list);453 454	esas2r_trace_enter();455 456	esas2r_hdebug("reset detected");457 458	spin_lock_irqsave(&a->queue_lock, flags);459 460	/* kill all the requests on the deferred queue */461	list_for_each(element, &a->defer_list) {462		rq = list_entry(element, struct esas2r_request, req_list);463		if (esas2r_ioreq_aborted(a, rq, RS_ABORTED))464			list_add_tail(&rq->comp_list, &comp_list);465	}466 467	spin_unlock_irqrestore(&a->queue_lock, flags);468 469	esas2r_comp_list_drain(a, &comp_list);470 471	if (atomic_read(&a->disable_cnt) == 0)472		esas2r_do_deferred_processes(a);473 474	clear_bit(AF_OS_RESET, &a->flags);475 476	esas2r_trace_exit();477}478 479static void esas2r_chip_rst_needed_during_tasklet(struct esas2r_adapter *a)480{481 482	clear_bit(AF_CHPRST_NEEDED, &a->flags);483	clear_bit(AF_BUSRST_NEEDED, &a->flags);484	clear_bit(AF_BUSRST_DETECTED, &a->flags);485	clear_bit(AF_BUSRST_PENDING, &a->flags);486	/*487	 * Make sure we don't get attempt more than 3 resets488	 * when the uptime between resets does not exceed one489	 * minute.  This will stop any situation where there is490	 * really something wrong with the hardware.  The way491	 * this works is that we start with uptime ticks at 0.492	 * Each time we do a reset, we add 20 seconds worth to493	 * the count.  Each time a timer tick occurs, as long494	 * as a chip reset is not pending, we decrement the495	 * tick count.  If the uptime ticks ever gets to 60496	 * seconds worth, we disable the adapter from that497	 * point forward.  Three strikes, you're out.498	 */499	if (!esas2r_is_adapter_present(a) || (a->chip_uptime >=500					      ESAS2R_CHP_UPTIME_MAX)) {501		esas2r_hdebug("*** adapter disabled ***");502 503		/*504		 * Ok, some kind of hard failure.  Make sure we505		 * exit this loop with chip interrupts506		 * permanently disabled so we don't lock up the507		 * entire system.  Also flag degraded mode to508		 * prevent the heartbeat from trying to recover.509		 */510 511		set_bit(AF_DEGRADED_MODE, &a->flags);512		set_bit(AF_DISABLED, &a->flags);513		clear_bit(AF_CHPRST_PENDING, &a->flags);514		clear_bit(AF_DISC_PENDING, &a->flags);515 516		esas2r_disable_chip_interrupts(a);517		a->int_mask = 0;518		esas2r_process_adapter_reset(a);519 520		esas2r_log(ESAS2R_LOG_CRIT,521			   "Adapter disabled because of hardware failure");522	} else {523		bool alrdyrst = test_and_set_bit(AF_CHPRST_STARTED, &a->flags);524 525		if (!alrdyrst)526			/*527			 * Only disable interrupts if this is528			 * the first reset attempt.529			 */530			esas2r_disable_chip_interrupts(a);531 532		if ((test_bit(AF_POWER_MGT, &a->flags)) &&533		    !test_bit(AF_FIRST_INIT, &a->flags) && !alrdyrst) {534			/*535			 * Don't reset the chip on the first536			 * deferred power up attempt.537			 */538		} else {539			esas2r_hdebug("*** resetting chip ***");540			esas2r_reset_chip(a);541		}542 543		/* Kick off the reinitialization */544		a->chip_uptime += ESAS2R_CHP_UPTIME_CNT;545		a->chip_init_time = jiffies_to_msecs(jiffies);546		if (!test_bit(AF_POWER_MGT, &a->flags)) {547			esas2r_process_adapter_reset(a);548 549			if (!alrdyrst) {550				/* Remove devices now that I/O is cleaned up. */551				a->prev_dev_cnt =552					esas2r_targ_db_get_tgt_cnt(a);553				esas2r_targ_db_remove_all(a, false);554			}555		}556 557		a->int_mask = 0;558	}559}560 561static void esas2r_handle_chip_rst_during_tasklet(struct esas2r_adapter *a)562{563	while (test_bit(AF_CHPRST_DETECTED, &a->flags)) {564		/*565		 * Balance the enable in esas2r_initadapter_hw.566		 * Esas2r_power_down already took care of it for power567		 * management.568		 */569		if (!test_bit(AF_DEGRADED_MODE, &a->flags) &&570		    !test_bit(AF_POWER_MGT, &a->flags))571			esas2r_disable_chip_interrupts(a);572 573		/* Reinitialize the chip. */574		esas2r_check_adapter(a);575		esas2r_init_adapter_hw(a, 0);576 577		if (test_bit(AF_CHPRST_NEEDED, &a->flags))578			break;579 580		if (test_bit(AF_POWER_MGT, &a->flags)) {581			/* Recovery from power management. */582			if (test_bit(AF_FIRST_INIT, &a->flags)) {583				/* Chip reset during normal power up */584				esas2r_log(ESAS2R_LOG_CRIT,585					   "The firmware was reset during a normal power-up sequence");586			} else {587				/* Deferred power up complete. */588				clear_bit(AF_POWER_MGT, &a->flags);589				esas2r_send_reset_ae(a, true);590			}591		} else {592			/* Recovery from online chip reset. */593			if (test_bit(AF_FIRST_INIT, &a->flags)) {594				/* Chip reset during driver load */595			} else {596				/* Chip reset after driver load */597				esas2r_send_reset_ae(a, false);598			}599 600			esas2r_log(ESAS2R_LOG_CRIT,601				   "Recovering from a chip reset while the chip was online");602		}603 604		clear_bit(AF_CHPRST_STARTED, &a->flags);605		esas2r_enable_chip_interrupts(a);606 607		/*608		 * Clear this flag last!  this indicates that the chip has been609		 * reset already during initialization.610		 */611		clear_bit(AF_CHPRST_DETECTED, &a->flags);612	}613}614 615 616/* Perform deferred tasks when chip interrupts are disabled */617void esas2r_do_tasklet_tasks(struct esas2r_adapter *a)618{619 620	if (test_bit(AF_CHPRST_NEEDED, &a->flags) ||621	    test_bit(AF_CHPRST_DETECTED, &a->flags)) {622		if (test_bit(AF_CHPRST_NEEDED, &a->flags))623			esas2r_chip_rst_needed_during_tasklet(a);624 625		esas2r_handle_chip_rst_during_tasklet(a);626	}627 628	if (test_bit(AF_BUSRST_NEEDED, &a->flags)) {629		esas2r_hdebug("hard resetting bus");630 631		clear_bit(AF_BUSRST_NEEDED, &a->flags);632 633		if (test_bit(AF_FLASHING, &a->flags))634			set_bit(AF_BUSRST_DETECTED, &a->flags);635		else636			esas2r_write_register_dword(a, MU_DOORBELL_IN,637						    DRBL_RESET_BUS);638	}639 640	if (test_bit(AF_BUSRST_DETECTED, &a->flags)) {641		esas2r_process_bus_reset(a);642 643		esas2r_log_dev(ESAS2R_LOG_WARN,644			       &(a->host->shost_gendev),645			       "scsi_report_bus_reset() called");646 647		scsi_report_bus_reset(a->host, 0);648 649		clear_bit(AF_BUSRST_DETECTED, &a->flags);650		clear_bit(AF_BUSRST_PENDING, &a->flags);651 652		esas2r_log(ESAS2R_LOG_WARN, "Bus reset complete");653	}654 655	if (test_bit(AF_PORT_CHANGE, &a->flags)) {656		clear_bit(AF_PORT_CHANGE, &a->flags);657 658		esas2r_targ_db_report_changes(a);659	}660 661	if (atomic_read(&a->disable_cnt) == 0)662		esas2r_do_deferred_processes(a);663}664 665static void esas2r_doorbell_interrupt(struct esas2r_adapter *a, u32 doorbell)666{667	if (!(doorbell & DRBL_FORCE_INT)) {668		esas2r_trace_enter();669		esas2r_trace("doorbell: %x", doorbell);670	}671 672	/* First clear the doorbell bits */673	esas2r_write_register_dword(a, MU_DOORBELL_OUT, doorbell);674 675	if (doorbell & DRBL_RESET_BUS)676		set_bit(AF_BUSRST_DETECTED, &a->flags);677 678	if (doorbell & DRBL_FORCE_INT)679		clear_bit(AF_HEARTBEAT, &a->flags);680 681	if (doorbell & DRBL_PANIC_REASON_MASK) {682		esas2r_hdebug("*** Firmware Panic ***");683		esas2r_log(ESAS2R_LOG_CRIT, "The firmware has panicked");684	}685 686	if (doorbell & DRBL_FW_RESET) {687		set_bit(AF2_COREDUMP_AVAIL, &a->flags2);688		esas2r_local_reset_adapter(a);689	}690 691	if (!(doorbell & DRBL_FORCE_INT)) {692		esas2r_trace_exit();693	}694}695 696void esas2r_force_interrupt(struct esas2r_adapter *a)697{698	esas2r_write_register_dword(a, MU_DOORBELL_IN, DRBL_FORCE_INT |699				    DRBL_DRV_VER);700}701 702 703static void esas2r_lun_event(struct esas2r_adapter *a, union atto_vda_ae *ae,704			     u16 target, u32 length)705{706	struct esas2r_target *t = a->targetdb + target;707	u32 cplen = length;708	unsigned long flags;709 710	if (cplen > sizeof(t->lu_event))711		cplen = sizeof(t->lu_event);712 713	esas2r_trace("ae->lu.dwevent: %x", ae->lu.dwevent);714	esas2r_trace("ae->lu.bystate: %x", ae->lu.bystate);715 716	spin_lock_irqsave(&a->mem_lock, flags);717 718	t->new_target_state = TS_INVALID;719 720	if (ae->lu.dwevent  & VDAAE_LU_LOST) {721		t->new_target_state = TS_NOT_PRESENT;722	} else {723		switch (ae->lu.bystate) {724		case VDAAE_LU_NOT_PRESENT:725		case VDAAE_LU_OFFLINE:726		case VDAAE_LU_DELETED:727		case VDAAE_LU_FACTORY_DISABLED:728			t->new_target_state = TS_NOT_PRESENT;729			break;730 731		case VDAAE_LU_ONLINE:732		case VDAAE_LU_DEGRADED:733			t->new_target_state = TS_PRESENT;734			break;735		}736	}737 738	if (t->new_target_state != TS_INVALID) {739		memcpy(&t->lu_event, &ae->lu, cplen);740 741		esas2r_disc_queue_event(a, DCDE_DEV_CHANGE);742	}743 744	spin_unlock_irqrestore(&a->mem_lock, flags);745}746 747 748 749void esas2r_ae_complete(struct esas2r_adapter *a, struct esas2r_request *rq)750{751	union atto_vda_ae *ae =752		(union atto_vda_ae *)rq->vda_rsp_data->ae_data.event_data;753	u32 length = le32_to_cpu(rq->func_rsp.ae_rsp.length);754	union atto_vda_ae *last =755		(union atto_vda_ae *)(rq->vda_rsp_data->ae_data.event_data756				      + length);757 758	esas2r_trace_enter();759	esas2r_trace("length: %d", length);760 761	if (length > sizeof(struct atto_vda_ae_data)762	    || (length & 3) != 0763	    || length == 0) {764		esas2r_log(ESAS2R_LOG_WARN,765			   "The AE request response length (%p) is too long: %d",766			   rq, length);767 768		esas2r_hdebug("aereq->length (0x%x) too long", length);769		esas2r_bugon();770 771		last = ae;772	}773 774	while (ae < last) {775		u16 target;776 777		esas2r_trace("ae: %p", ae);778		esas2r_trace("ae->hdr: %p", &(ae->hdr));779 780		length = ae->hdr.bylength;781 782		if (length > (u32)((u8 *)last - (u8 *)ae)783		    || (length & 3) != 0784		    || length == 0) {785			esas2r_log(ESAS2R_LOG_CRIT,786				   "the async event length is invalid (%p): %d",787				   ae, length);788 789			esas2r_hdebug("ae->hdr.length (0x%x) invalid", length);790			esas2r_bugon();791 792			break;793		}794 795		esas2r_nuxi_ae_data(ae);796 797		esas2r_queue_fw_event(a, fw_event_vda_ae, ae,798				      sizeof(union atto_vda_ae));799 800		switch (ae->hdr.bytype) {801		case VDAAE_HDR_TYPE_RAID:802 803			if (ae->raid.dwflags & (VDAAE_GROUP_STATE804						| VDAAE_RBLD_STATE805						| VDAAE_MEMBER_CHG806						| VDAAE_PART_CHG)) {807				esas2r_log(ESAS2R_LOG_INFO,808					   "RAID event received - name:%s rebuild_state:%d group_state:%d",809					   ae->raid.acname,810					   ae->raid.byrebuild_state,811					   ae->raid.bygroup_state);812			}813 814			break;815 816		case VDAAE_HDR_TYPE_LU:817			esas2r_log(ESAS2R_LOG_INFO,818				   "LUN event received: event:%d target_id:%d LUN:%d state:%d",819				   ae->lu.dwevent,820				   ae->lu.id.tgtlun.wtarget_id,821				   ae->lu.id.tgtlun.bylun,822				   ae->lu.bystate);823 824			target = ae->lu.id.tgtlun.wtarget_id;825 826			if (target < ESAS2R_MAX_TARGETS)827				esas2r_lun_event(a, ae, target, length);828 829			break;830 831		case VDAAE_HDR_TYPE_DISK:832			esas2r_log(ESAS2R_LOG_INFO, "Disk event received");833			break;834 835		default:836 837			/* Silently ignore the rest and let the apps deal with838			 * them.839			 */840 841			break;842		}843 844		ae = (union atto_vda_ae *)((u8 *)ae + length);845	}846 847	/* Now requeue it. */848	esas2r_start_ae_request(a, rq);849	esas2r_trace_exit();850}851 852/* Send an asynchronous event for a chip reset or power management. */853void esas2r_send_reset_ae(struct esas2r_adapter *a, bool pwr_mgt)854{855	struct atto_vda_ae_hdr ae;856 857	if (pwr_mgt)858		ae.bytype = VDAAE_HDR_TYPE_PWRMGT;859	else860		ae.bytype = VDAAE_HDR_TYPE_RESET;861 862	ae.byversion = VDAAE_HDR_VER_0;863	ae.byflags = 0;864	ae.bylength = (u8)sizeof(struct atto_vda_ae_hdr);865 866	if (pwr_mgt) {867		esas2r_hdebug("*** sending power management AE ***");868	} else {869		esas2r_hdebug("*** sending reset AE ***");870	}871 872	esas2r_queue_fw_event(a, fw_event_vda_ae, &ae,873			      sizeof(union atto_vda_ae));874}875 876void esas2r_dummy_complete(struct esas2r_adapter *a, struct esas2r_request *rq)877{}878 879static void esas2r_check_req_rsp_sense(struct esas2r_adapter *a,880				       struct esas2r_request *rq)881{882	u8 snslen, snslen2;883 884	snslen = snslen2 = rq->func_rsp.scsi_rsp.sense_len;885 886	if (snslen > rq->sense_len)887		snslen = rq->sense_len;888 889	if (snslen) {890		if (rq->sense_buf)891			memcpy(rq->sense_buf, rq->data_buf, snslen);892		else893			rq->sense_buf = (u8 *)rq->data_buf;894 895		/* See about possible sense data */896		if (snslen2 > 0x0c) {897			u8 *s = (u8 *)rq->data_buf;898 899			esas2r_trace_enter();900 901			/* Report LUNS data has changed */902			if (s[0x0c] == 0x3f && s[0x0d] == 0x0E) {903				esas2r_trace("rq->target_id: %d",904					     rq->target_id);905				esas2r_target_state_changed(a, rq->target_id,906							    TS_LUN_CHANGE);907			}908 909			esas2r_trace("add_sense_key=%x", s[0x0c]);910			esas2r_trace("add_sense_qual=%x", s[0x0d]);911			esas2r_trace_exit();912		}913	}914 915	rq->sense_len = snslen;916}917 918 919void esas2r_complete_request(struct esas2r_adapter *a,920			     struct esas2r_request *rq)921{922	if (rq->vrq->scsi.function == VDA_FUNC_FLASH923	    && rq->vrq->flash.sub_func == VDA_FLASH_COMMIT)924		clear_bit(AF_FLASHING, &a->flags);925 926	/* See if we setup a callback to do special processing */927 928	if (rq->interrupt_cb) {929		(*rq->interrupt_cb)(a, rq);930 931		if (rq->req_stat == RS_PENDING) {932			esas2r_start_request(a, rq);933			return;934		}935	}936 937	if (likely(rq->vrq->scsi.function == VDA_FUNC_SCSI)938	    && unlikely(rq->req_stat != RS_SUCCESS)) {939		esas2r_check_req_rsp_sense(a, rq);940		esas2r_log_request_failure(a, rq);941	}942 943	(*rq->comp_cb)(a, rq);944}945