xref: /openbmc/linux/drivers/scsi/esas2r/esas2r_int.c (revision 6abf98de)
126780d9eSBradley Grove /*
226780d9eSBradley Grove  *  linux/drivers/scsi/esas2r/esas2r_int.c
326780d9eSBradley Grove  *      esas2r interrupt handling
426780d9eSBradley Grove  *
526780d9eSBradley Grove  *  Copyright (c) 2001-2013 ATTO Technology, Inc.
626780d9eSBradley Grove  *  (mailto:linuxdrivers@attotech.com)
726780d9eSBradley Grove  */
826780d9eSBradley Grove /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
926780d9eSBradley Grove /*
1026780d9eSBradley Grove  *  This program is free software; you can redistribute it and/or modify
1126780d9eSBradley Grove  *  it under the terms of the GNU General Public License as published by
1226780d9eSBradley Grove  *  the Free Software Foundation; version 2 of the License.
1326780d9eSBradley Grove  *
1426780d9eSBradley Grove  *  This program is distributed in the hope that it will be useful,
1526780d9eSBradley Grove  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
1626780d9eSBradley Grove  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1726780d9eSBradley Grove  *  GNU General Public License for more details.
1826780d9eSBradley Grove  *
1926780d9eSBradley Grove  *  NO WARRANTY
2026780d9eSBradley Grove  *  THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
2126780d9eSBradley Grove  *  CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
2226780d9eSBradley Grove  *  LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
2326780d9eSBradley Grove  *  MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
2426780d9eSBradley Grove  *  solely responsible for determining the appropriateness of using and
2526780d9eSBradley Grove  *  distributing the Program and assumes all risks associated with its
2626780d9eSBradley Grove  *  exercise of rights under this Agreement, including but not limited to
2726780d9eSBradley Grove  *  the risks and costs of program errors, damage to or loss of data,
2826780d9eSBradley Grove  *  programs or equipment, and unavailability or interruption of operations.
2926780d9eSBradley Grove  *
3026780d9eSBradley Grove  *  DISCLAIMER OF LIABILITY
3126780d9eSBradley Grove  *  NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
3226780d9eSBradley Grove  *  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3326780d9eSBradley Grove  *  DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
3426780d9eSBradley Grove  *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
3526780d9eSBradley Grove  *  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
3626780d9eSBradley Grove  *  USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
3726780d9eSBradley Grove  *  HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
3826780d9eSBradley Grove  *
3926780d9eSBradley Grove  *  You should have received a copy of the GNU General Public License
4026780d9eSBradley Grove  *  along with this program; if not, write to the Free Software
4126780d9eSBradley Grove  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
4226780d9eSBradley Grove  */
4326780d9eSBradley Grove /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4426780d9eSBradley Grove 
4526780d9eSBradley Grove #include "esas2r.h"
4626780d9eSBradley Grove 
4726780d9eSBradley Grove /* Local function prototypes */
4826780d9eSBradley Grove static void esas2r_doorbell_interrupt(struct esas2r_adapter *a, u32 doorbell);
4926780d9eSBradley Grove static void esas2r_get_outbound_responses(struct esas2r_adapter *a);
5026780d9eSBradley Grove static void esas2r_process_bus_reset(struct esas2r_adapter *a);
5126780d9eSBradley Grove 
5226780d9eSBradley Grove /*
5326780d9eSBradley Grove  * Poll the adapter for interrupts and service them.
5426780d9eSBradley Grove  * This function handles both legacy interrupts and MSI.
5526780d9eSBradley Grove  */
esas2r_polled_interrupt(struct esas2r_adapter * a)5626780d9eSBradley Grove void esas2r_polled_interrupt(struct esas2r_adapter *a)
5726780d9eSBradley Grove {
5826780d9eSBradley Grove 	u32 intstat;
5926780d9eSBradley Grove 	u32 doorbell;
6026780d9eSBradley Grove 
6126780d9eSBradley Grove 	esas2r_disable_chip_interrupts(a);
6226780d9eSBradley Grove 
6326780d9eSBradley Grove 	intstat = esas2r_read_register_dword(a, MU_INT_STATUS_OUT);
6426780d9eSBradley Grove 
6526780d9eSBradley Grove 	if (intstat & MU_INTSTAT_POST_OUT) {
6626780d9eSBradley Grove 		/* clear the interrupt */
6726780d9eSBradley Grove 
6826780d9eSBradley Grove 		esas2r_write_register_dword(a, MU_OUT_LIST_INT_STAT,
6926780d9eSBradley Grove 					    MU_OLIS_INT);
7026780d9eSBradley Grove 		esas2r_flush_register_dword(a, MU_OUT_LIST_INT_STAT);
7126780d9eSBradley Grove 
7226780d9eSBradley Grove 		esas2r_get_outbound_responses(a);
7326780d9eSBradley Grove 	}
7426780d9eSBradley Grove 
7526780d9eSBradley Grove 	if (intstat & MU_INTSTAT_DRBL) {
7626780d9eSBradley Grove 		doorbell = esas2r_read_register_dword(a, MU_DOORBELL_OUT);
7726780d9eSBradley Grove 		if (doorbell != 0)
7826780d9eSBradley Grove 			esas2r_doorbell_interrupt(a, doorbell);
7926780d9eSBradley Grove 	}
8026780d9eSBradley Grove 
8126780d9eSBradley Grove 	esas2r_enable_chip_interrupts(a);
8226780d9eSBradley Grove 
8326780d9eSBradley Grove 	if (atomic_read(&a->disable_cnt) == 0)
8426780d9eSBradley Grove 		esas2r_do_deferred_processes(a);
8526780d9eSBradley Grove }
8626780d9eSBradley Grove 
8726780d9eSBradley Grove /*
8826780d9eSBradley Grove  * Legacy and MSI interrupt handlers.  Note that the legacy interrupt handler
8926780d9eSBradley Grove  * schedules a TASKLET to process events, whereas the MSI handler just
9026780d9eSBradley Grove  * processes interrupt events directly.
9126780d9eSBradley Grove  */
esas2r_interrupt(int irq,void * dev_id)9226780d9eSBradley Grove irqreturn_t esas2r_interrupt(int irq, void *dev_id)
9326780d9eSBradley Grove {
9426780d9eSBradley Grove 	struct esas2r_adapter *a = (struct esas2r_adapter *)dev_id;
9526780d9eSBradley Grove 
9626780d9eSBradley Grove 	if (!esas2r_adapter_interrupt_pending(a))
9726780d9eSBradley Grove 		return IRQ_NONE;
9826780d9eSBradley Grove 
999588d24eSBradley Grove 	set_bit(AF2_INT_PENDING, &a->flags2);
10026780d9eSBradley Grove 	esas2r_schedule_tasklet(a);
10126780d9eSBradley Grove 
10226780d9eSBradley Grove 	return IRQ_HANDLED;
10326780d9eSBradley Grove }
10426780d9eSBradley Grove 
esas2r_adapter_interrupt(struct esas2r_adapter * a)10526780d9eSBradley Grove void esas2r_adapter_interrupt(struct esas2r_adapter *a)
10626780d9eSBradley Grove {
10726780d9eSBradley Grove 	u32 doorbell;
10826780d9eSBradley Grove 
10926780d9eSBradley Grove 	if (likely(a->int_stat & MU_INTSTAT_POST_OUT)) {
11026780d9eSBradley Grove 		/* clear the interrupt */
11126780d9eSBradley Grove 		esas2r_write_register_dword(a, MU_OUT_LIST_INT_STAT,
11226780d9eSBradley Grove 					    MU_OLIS_INT);
11326780d9eSBradley Grove 		esas2r_flush_register_dword(a, MU_OUT_LIST_INT_STAT);
11426780d9eSBradley Grove 		esas2r_get_outbound_responses(a);
11526780d9eSBradley Grove 	}
11626780d9eSBradley Grove 
11726780d9eSBradley Grove 	if (unlikely(a->int_stat & MU_INTSTAT_DRBL)) {
11826780d9eSBradley Grove 		doorbell = esas2r_read_register_dword(a, MU_DOORBELL_OUT);
11926780d9eSBradley Grove 		if (doorbell != 0)
12026780d9eSBradley Grove 			esas2r_doorbell_interrupt(a, doorbell);
12126780d9eSBradley Grove 	}
12226780d9eSBradley Grove 
12326780d9eSBradley Grove 	a->int_mask = ESAS2R_INT_STS_MASK;
12426780d9eSBradley Grove 
12526780d9eSBradley Grove 	esas2r_enable_chip_interrupts(a);
12626780d9eSBradley Grove 
12726780d9eSBradley Grove 	if (likely(atomic_read(&a->disable_cnt) == 0))
12826780d9eSBradley Grove 		esas2r_do_deferred_processes(a);
12926780d9eSBradley Grove }
13026780d9eSBradley Grove 
esas2r_msi_interrupt(int irq,void * dev_id)13126780d9eSBradley Grove irqreturn_t esas2r_msi_interrupt(int irq, void *dev_id)
13226780d9eSBradley Grove {
13326780d9eSBradley Grove 	struct esas2r_adapter *a = (struct esas2r_adapter *)dev_id;
13426780d9eSBradley Grove 	u32 intstat;
13526780d9eSBradley Grove 	u32 doorbell;
13626780d9eSBradley Grove 
13726780d9eSBradley Grove 	intstat = esas2r_read_register_dword(a, MU_INT_STATUS_OUT);
13826780d9eSBradley Grove 
13926780d9eSBradley Grove 	if (likely(intstat & MU_INTSTAT_POST_OUT)) {
14026780d9eSBradley Grove 		/* clear the interrupt */
14126780d9eSBradley Grove 
14226780d9eSBradley Grove 		esas2r_write_register_dword(a, MU_OUT_LIST_INT_STAT,
14326780d9eSBradley Grove 					    MU_OLIS_INT);
14426780d9eSBradley Grove 		esas2r_flush_register_dword(a, MU_OUT_LIST_INT_STAT);
14526780d9eSBradley Grove 
14626780d9eSBradley Grove 		esas2r_get_outbound_responses(a);
14726780d9eSBradley Grove 	}
14826780d9eSBradley Grove 
14926780d9eSBradley Grove 	if (unlikely(intstat & MU_INTSTAT_DRBL)) {
15026780d9eSBradley Grove 		doorbell = esas2r_read_register_dword(a, MU_DOORBELL_OUT);
15126780d9eSBradley Grove 		if (doorbell != 0)
15226780d9eSBradley Grove 			esas2r_doorbell_interrupt(a, doorbell);
15326780d9eSBradley Grove 	}
15426780d9eSBradley Grove 
15526780d9eSBradley Grove 	/*
15626780d9eSBradley Grove 	 * Work around a chip bug and force a new MSI to be sent if one is
15726780d9eSBradley Grove 	 * still pending.
15826780d9eSBradley Grove 	 */
15926780d9eSBradley Grove 	esas2r_disable_chip_interrupts(a);
16026780d9eSBradley Grove 	esas2r_enable_chip_interrupts(a);
16126780d9eSBradley Grove 
16226780d9eSBradley Grove 	if (likely(atomic_read(&a->disable_cnt) == 0))
16326780d9eSBradley Grove 		esas2r_do_deferred_processes(a);
16426780d9eSBradley Grove 
16526780d9eSBradley Grove 	esas2r_do_tasklet_tasks(a);
16626780d9eSBradley Grove 
16726780d9eSBradley Grove 	return 1;
16826780d9eSBradley Grove }
16926780d9eSBradley Grove 
17026780d9eSBradley Grove 
17126780d9eSBradley Grove 
esas2r_handle_outbound_rsp_err(struct esas2r_adapter * a,struct esas2r_request * rq,struct atto_vda_ob_rsp * rsp)17226780d9eSBradley Grove static void esas2r_handle_outbound_rsp_err(struct esas2r_adapter *a,
17326780d9eSBradley Grove 					   struct esas2r_request *rq,
17426780d9eSBradley Grove 					   struct atto_vda_ob_rsp *rsp)
17526780d9eSBradley Grove {
17626780d9eSBradley Grove 
17726780d9eSBradley Grove 	/*
17826780d9eSBradley Grove 	 * For I/O requests, only copy the response if an error
17926780d9eSBradley Grove 	 * occurred and setup a callback to do error processing.
18026780d9eSBradley Grove 	 */
18126780d9eSBradley Grove 	if (unlikely(rq->req_stat != RS_SUCCESS)) {
18226780d9eSBradley Grove 		memcpy(&rq->func_rsp, &rsp->func_rsp, sizeof(rsp->func_rsp));
18326780d9eSBradley Grove 
18426780d9eSBradley Grove 		if (rq->req_stat == RS_ABORTED) {
18526780d9eSBradley Grove 			if (rq->timeout > RQ_MAX_TIMEOUT)
18626780d9eSBradley Grove 				rq->req_stat = RS_TIMEOUT;
18726780d9eSBradley Grove 		} else if (rq->req_stat == RS_SCSI_ERROR) {
18826780d9eSBradley Grove 			u8 scsistatus = rq->func_rsp.scsi_rsp.scsi_stat;
18926780d9eSBradley Grove 
19026780d9eSBradley Grove 			esas2r_trace("scsistatus: %x", scsistatus);
19126780d9eSBradley Grove 
19226780d9eSBradley Grove 			/* Any of these are a good result. */
19326780d9eSBradley Grove 			if (scsistatus == SAM_STAT_GOOD || scsistatus ==
19426780d9eSBradley Grove 			    SAM_STAT_CONDITION_MET || scsistatus ==
19526780d9eSBradley Grove 			    SAM_STAT_INTERMEDIATE || scsistatus ==
19626780d9eSBradley Grove 			    SAM_STAT_INTERMEDIATE_CONDITION_MET) {
19726780d9eSBradley Grove 				rq->req_stat = RS_SUCCESS;
19826780d9eSBradley Grove 				rq->func_rsp.scsi_rsp.scsi_stat =
19926780d9eSBradley Grove 					SAM_STAT_GOOD;
20026780d9eSBradley Grove 			}
20126780d9eSBradley Grove 		}
20226780d9eSBradley Grove 	}
20326780d9eSBradley Grove }
20426780d9eSBradley Grove 
esas2r_get_outbound_responses(struct esas2r_adapter * a)20526780d9eSBradley Grove static void esas2r_get_outbound_responses(struct esas2r_adapter *a)
20626780d9eSBradley Grove {
20726780d9eSBradley Grove 	struct atto_vda_ob_rsp *rsp;
20826780d9eSBradley Grove 	u32 rspput_ptr;
20926780d9eSBradley Grove 	u32 rspget_ptr;
21026780d9eSBradley Grove 	struct esas2r_request *rq;
21126780d9eSBradley Grove 	u32 handle;
21226780d9eSBradley Grove 	unsigned long flags;
21326780d9eSBradley Grove 
21426780d9eSBradley Grove 	LIST_HEAD(comp_list);
21526780d9eSBradley Grove 
21626780d9eSBradley Grove 	esas2r_trace_enter();
21726780d9eSBradley Grove 
21826780d9eSBradley Grove 	spin_lock_irqsave(&a->queue_lock, flags);
21926780d9eSBradley Grove 
22026780d9eSBradley Grove 	/* Get the outbound limit and pointers */
22126780d9eSBradley Grove 	rspput_ptr = le32_to_cpu(*a->outbound_copy) & MU_OLC_WRT_PTR;
22226780d9eSBradley Grove 	rspget_ptr = a->last_read;
22326780d9eSBradley Grove 
22426780d9eSBradley Grove 	esas2r_trace("rspput_ptr: %x, rspget_ptr: %x", rspput_ptr, rspget_ptr);
22526780d9eSBradley Grove 
22626780d9eSBradley Grove 	/* If we don't have anything to process, get out */
22726780d9eSBradley Grove 	if (unlikely(rspget_ptr == rspput_ptr)) {
22826780d9eSBradley Grove 		spin_unlock_irqrestore(&a->queue_lock, flags);
22926780d9eSBradley Grove 		esas2r_trace_exit();
23026780d9eSBradley Grove 		return;
23126780d9eSBradley Grove 	}
23226780d9eSBradley Grove 
23326780d9eSBradley Grove 	/* Make sure the firmware is healthy */
23426780d9eSBradley Grove 	if (unlikely(rspput_ptr >= a->list_size)) {
23526780d9eSBradley Grove 		spin_unlock_irqrestore(&a->queue_lock, flags);
23626780d9eSBradley Grove 		esas2r_bugon();
23726780d9eSBradley Grove 		esas2r_local_reset_adapter(a);
23826780d9eSBradley Grove 		esas2r_trace_exit();
23926780d9eSBradley Grove 		return;
24026780d9eSBradley Grove 	}
24126780d9eSBradley Grove 
24226780d9eSBradley Grove 	do {
24326780d9eSBradley Grove 		rspget_ptr++;
24426780d9eSBradley Grove 
24526780d9eSBradley Grove 		if (rspget_ptr >= a->list_size)
24626780d9eSBradley Grove 			rspget_ptr = 0;
24726780d9eSBradley Grove 
24826780d9eSBradley Grove 		rsp = (struct atto_vda_ob_rsp *)a->outbound_list_md.virt_addr
24926780d9eSBradley Grove 		      + rspget_ptr;
25026780d9eSBradley Grove 
25126780d9eSBradley Grove 		handle = rsp->handle;
25226780d9eSBradley Grove 
25326780d9eSBradley Grove 		/* Verify the handle range */
25426780d9eSBradley Grove 		if (unlikely(LOWORD(handle) == 0
25526780d9eSBradley Grove 			     || LOWORD(handle) > num_requests +
25626780d9eSBradley Grove 			     num_ae_requests + 1)) {
25726780d9eSBradley Grove 			esas2r_bugon();
25826780d9eSBradley Grove 			continue;
25926780d9eSBradley Grove 		}
26026780d9eSBradley Grove 
26126780d9eSBradley Grove 		/* Get the request for this handle */
26226780d9eSBradley Grove 		rq = a->req_table[LOWORD(handle)];
26326780d9eSBradley Grove 
26426780d9eSBradley Grove 		if (unlikely(rq == NULL || rq->vrq->scsi.handle != handle)) {
26526780d9eSBradley Grove 			esas2r_bugon();
26626780d9eSBradley Grove 			continue;
26726780d9eSBradley Grove 		}
26826780d9eSBradley Grove 
26926780d9eSBradley Grove 		list_del(&rq->req_list);
27026780d9eSBradley Grove 
27126780d9eSBradley Grove 		/* Get the completion status */
27226780d9eSBradley Grove 		rq->req_stat = rsp->req_stat;
27326780d9eSBradley Grove 
27426780d9eSBradley Grove 		esas2r_trace("handle: %x", handle);
27526780d9eSBradley Grove 		esas2r_trace("rq: %p", rq);
27626780d9eSBradley Grove 		esas2r_trace("req_status: %x", rq->req_stat);
27726780d9eSBradley Grove 
27826780d9eSBradley Grove 		if (likely(rq->vrq->scsi.function == VDA_FUNC_SCSI)) {
27926780d9eSBradley Grove 			esas2r_handle_outbound_rsp_err(a, rq, rsp);
28026780d9eSBradley Grove 		} else {
28126780d9eSBradley Grove 			/*
28226780d9eSBradley Grove 			 * Copy the outbound completion struct for non-I/O
28326780d9eSBradley Grove 			 * requests.
28426780d9eSBradley Grove 			 */
28526780d9eSBradley Grove 			memcpy(&rq->func_rsp, &rsp->func_rsp,
28626780d9eSBradley Grove 			       sizeof(rsp->func_rsp));
28726780d9eSBradley Grove 		}
28826780d9eSBradley Grove 
28926780d9eSBradley Grove 		/* Queue the request for completion. */
29026780d9eSBradley Grove 		list_add_tail(&rq->comp_list, &comp_list);
29126780d9eSBradley Grove 
29226780d9eSBradley Grove 	} while (rspget_ptr != rspput_ptr);
29326780d9eSBradley Grove 
29426780d9eSBradley Grove 	a->last_read = rspget_ptr;
29526780d9eSBradley Grove 	spin_unlock_irqrestore(&a->queue_lock, flags);
29626780d9eSBradley Grove 
29726780d9eSBradley Grove 	esas2r_comp_list_drain(a, &comp_list);
29826780d9eSBradley Grove 	esas2r_trace_exit();
29926780d9eSBradley Grove }
30026780d9eSBradley Grove 
30126780d9eSBradley Grove /*
30226780d9eSBradley Grove  * Perform all deferred processes for the adapter.  Deferred
30326780d9eSBradley Grove  * processes can only be done while the current interrupt
30426780d9eSBradley Grove  * disable_cnt for the adapter is zero.
30526780d9eSBradley Grove  */
esas2r_do_deferred_processes(struct esas2r_adapter * a)30626780d9eSBradley Grove void esas2r_do_deferred_processes(struct esas2r_adapter *a)
30726780d9eSBradley Grove {
30826780d9eSBradley Grove 	int startreqs = 2;
30926780d9eSBradley Grove 	struct esas2r_request *rq;
31026780d9eSBradley Grove 	unsigned long flags;
31126780d9eSBradley Grove 
31226780d9eSBradley Grove 	/*
31326780d9eSBradley Grove 	 * startreqs is used to control starting requests
31426780d9eSBradley Grove 	 * that are on the deferred queue
31526780d9eSBradley Grove 	 *  = 0 - do not start any requests
31626780d9eSBradley Grove 	 *  = 1 - can start discovery requests
31726780d9eSBradley Grove 	 *  = 2 - can start any request
31826780d9eSBradley Grove 	 */
31926780d9eSBradley Grove 
3209588d24eSBradley Grove 	if (test_bit(AF_CHPRST_PENDING, &a->flags) ||
3219588d24eSBradley Grove 	    test_bit(AF_FLASHING, &a->flags))
32226780d9eSBradley Grove 		startreqs = 0;
3239588d24eSBradley Grove 	else if (test_bit(AF_DISC_PENDING, &a->flags))
32426780d9eSBradley Grove 		startreqs = 1;
32526780d9eSBradley Grove 
32626780d9eSBradley Grove 	atomic_inc(&a->disable_cnt);
32726780d9eSBradley Grove 
32826780d9eSBradley Grove 	/* Clear off the completed list to be processed later. */
32926780d9eSBradley Grove 
33026780d9eSBradley Grove 	if (esas2r_is_tasklet_pending(a)) {
33126780d9eSBradley Grove 		esas2r_schedule_tasklet(a);
33226780d9eSBradley Grove 
33326780d9eSBradley Grove 		startreqs = 0;
33426780d9eSBradley Grove 	}
33526780d9eSBradley Grove 
33626780d9eSBradley Grove 	/*
33726780d9eSBradley Grove 	 * If we can start requests then traverse the defer queue
33826780d9eSBradley Grove 	 * looking for requests to start or complete
33926780d9eSBradley Grove 	 */
34026780d9eSBradley Grove 	if (startreqs && !list_empty(&a->defer_list)) {
34126780d9eSBradley Grove 		LIST_HEAD(comp_list);
34226780d9eSBradley Grove 		struct list_head *element, *next;
34326780d9eSBradley Grove 
34426780d9eSBradley Grove 		spin_lock_irqsave(&a->queue_lock, flags);
34526780d9eSBradley Grove 
34626780d9eSBradley Grove 		list_for_each_safe(element, next, &a->defer_list) {
34726780d9eSBradley Grove 			rq = list_entry(element, struct esas2r_request,
34826780d9eSBradley Grove 					req_list);
34926780d9eSBradley Grove 
35026780d9eSBradley Grove 			if (rq->req_stat != RS_PENDING) {
35126780d9eSBradley Grove 				list_del(element);
35226780d9eSBradley Grove 				list_add_tail(&rq->comp_list, &comp_list);
35326780d9eSBradley Grove 			}
35426780d9eSBradley Grove 			/*
35526780d9eSBradley Grove 			 * Process discovery and OS requests separately.  We
35626780d9eSBradley Grove 			 * can't hold up discovery requests when discovery is
35726780d9eSBradley Grove 			 * pending.  In general, there may be different sets of
35826780d9eSBradley Grove 			 * conditions for starting different types of requests.
35926780d9eSBradley Grove 			 */
36026780d9eSBradley Grove 			else if (rq->req_type == RT_DISC_REQ) {
36126780d9eSBradley Grove 				list_del(element);
36226780d9eSBradley Grove 				esas2r_disc_local_start_request(a, rq);
36326780d9eSBradley Grove 			} else if (startreqs == 2) {
36426780d9eSBradley Grove 				list_del(element);
36526780d9eSBradley Grove 				esas2r_local_start_request(a, rq);
36626780d9eSBradley Grove 
36726780d9eSBradley Grove 				/*
36826780d9eSBradley Grove 				 * Flashing could have been set by last local
36926780d9eSBradley Grove 				 * start
37026780d9eSBradley Grove 				 */
3719588d24eSBradley Grove 				if (test_bit(AF_FLASHING, &a->flags))
37226780d9eSBradley Grove 					break;
37326780d9eSBradley Grove 			}
37426780d9eSBradley Grove 		}
37526780d9eSBradley Grove 
37626780d9eSBradley Grove 		spin_unlock_irqrestore(&a->queue_lock, flags);
37726780d9eSBradley Grove 		esas2r_comp_list_drain(a, &comp_list);
37826780d9eSBradley Grove 	}
37926780d9eSBradley Grove 
38026780d9eSBradley Grove 	atomic_dec(&a->disable_cnt);
38126780d9eSBradley Grove }
38226780d9eSBradley Grove 
38326780d9eSBradley Grove /*
38426780d9eSBradley Grove  * Process an adapter reset (or one that is about to happen)
38526780d9eSBradley Grove  * by making sure all outstanding requests are completed that
38626780d9eSBradley Grove  * haven't been already.
38726780d9eSBradley Grove  */
esas2r_process_adapter_reset(struct esas2r_adapter * a)38826780d9eSBradley Grove void esas2r_process_adapter_reset(struct esas2r_adapter *a)
38926780d9eSBradley Grove {
39026780d9eSBradley Grove 	struct esas2r_request *rq = &a->general_req;
39126780d9eSBradley Grove 	unsigned long flags;
39226780d9eSBradley Grove 	struct esas2r_disc_context *dc;
39326780d9eSBradley Grove 
39426780d9eSBradley Grove 	LIST_HEAD(comp_list);
39526780d9eSBradley Grove 	struct list_head *element;
39626780d9eSBradley Grove 
39726780d9eSBradley Grove 	esas2r_trace_enter();
39826780d9eSBradley Grove 
39926780d9eSBradley Grove 	spin_lock_irqsave(&a->queue_lock, flags);
40026780d9eSBradley Grove 
40126780d9eSBradley Grove 	/* abort the active discovery, if any.   */
40226780d9eSBradley Grove 
40326780d9eSBradley Grove 	if (rq->interrupt_cx) {
40426780d9eSBradley Grove 		dc = (struct esas2r_disc_context *)rq->interrupt_cx;
40526780d9eSBradley Grove 
40626780d9eSBradley Grove 		dc->disc_evt = 0;
40726780d9eSBradley Grove 
4089588d24eSBradley Grove 		clear_bit(AF_DISC_IN_PROG, &a->flags);
40926780d9eSBradley Grove 	}
41026780d9eSBradley Grove 
41126780d9eSBradley Grove 	/*
41226780d9eSBradley Grove 	 * just clear the interrupt callback for now.  it will be dequeued if
41326780d9eSBradley Grove 	 * and when we find it on the active queue and we don't want the
41426780d9eSBradley Grove 	 * callback called.  also set the dummy completion callback in case we
41526780d9eSBradley Grove 	 * were doing an I/O request.
41626780d9eSBradley Grove 	 */
41726780d9eSBradley Grove 
41826780d9eSBradley Grove 	rq->interrupt_cx = NULL;
41926780d9eSBradley Grove 	rq->interrupt_cb = NULL;
42026780d9eSBradley Grove 
42126780d9eSBradley Grove 	rq->comp_cb = esas2r_dummy_complete;
42226780d9eSBradley Grove 
42326780d9eSBradley Grove 	/* Reset the read and write pointers */
42426780d9eSBradley Grove 
42526780d9eSBradley Grove 	*a->outbound_copy =
42626780d9eSBradley Grove 		a->last_write =
42726780d9eSBradley Grove 			a->last_read = a->list_size - 1;
42826780d9eSBradley Grove 
4299588d24eSBradley Grove 	set_bit(AF_COMM_LIST_TOGGLE, &a->flags);
43026780d9eSBradley Grove 
43126780d9eSBradley Grove 	/* Kill all the requests on the active list */
43226780d9eSBradley Grove 	list_for_each(element, &a->defer_list) {
43326780d9eSBradley Grove 		rq = list_entry(element, struct esas2r_request, req_list);
43426780d9eSBradley Grove 
43526780d9eSBradley Grove 		if (rq->req_stat == RS_STARTED)
43626780d9eSBradley Grove 			if (esas2r_ioreq_aborted(a, rq, RS_ABORTED))
43726780d9eSBradley Grove 				list_add_tail(&rq->comp_list, &comp_list);
43826780d9eSBradley Grove 	}
43926780d9eSBradley Grove 
44026780d9eSBradley Grove 	spin_unlock_irqrestore(&a->queue_lock, flags);
44126780d9eSBradley Grove 	esas2r_comp_list_drain(a, &comp_list);
44226780d9eSBradley Grove 	esas2r_process_bus_reset(a);
44326780d9eSBradley Grove 	esas2r_trace_exit();
44426780d9eSBradley Grove }
44526780d9eSBradley Grove 
esas2r_process_bus_reset(struct esas2r_adapter * a)44626780d9eSBradley Grove static void esas2r_process_bus_reset(struct esas2r_adapter *a)
44726780d9eSBradley Grove {
44826780d9eSBradley Grove 	struct esas2r_request *rq;
44926780d9eSBradley Grove 	struct list_head *element;
45026780d9eSBradley Grove 	unsigned long flags;
45126780d9eSBradley Grove 
45226780d9eSBradley Grove 	LIST_HEAD(comp_list);
45326780d9eSBradley Grove 
45426780d9eSBradley Grove 	esas2r_trace_enter();
45526780d9eSBradley Grove 
45626780d9eSBradley Grove 	esas2r_hdebug("reset detected");
45726780d9eSBradley Grove 
45826780d9eSBradley Grove 	spin_lock_irqsave(&a->queue_lock, flags);
45926780d9eSBradley Grove 
46026780d9eSBradley Grove 	/* kill all the requests on the deferred queue */
46126780d9eSBradley Grove 	list_for_each(element, &a->defer_list) {
46226780d9eSBradley Grove 		rq = list_entry(element, struct esas2r_request, req_list);
46326780d9eSBradley Grove 		if (esas2r_ioreq_aborted(a, rq, RS_ABORTED))
46426780d9eSBradley Grove 			list_add_tail(&rq->comp_list, &comp_list);
46526780d9eSBradley Grove 	}
46626780d9eSBradley Grove 
46726780d9eSBradley Grove 	spin_unlock_irqrestore(&a->queue_lock, flags);
46826780d9eSBradley Grove 
46926780d9eSBradley Grove 	esas2r_comp_list_drain(a, &comp_list);
47026780d9eSBradley Grove 
47126780d9eSBradley Grove 	if (atomic_read(&a->disable_cnt) == 0)
47226780d9eSBradley Grove 		esas2r_do_deferred_processes(a);
47326780d9eSBradley Grove 
4749588d24eSBradley Grove 	clear_bit(AF_OS_RESET, &a->flags);
47526780d9eSBradley Grove 
47626780d9eSBradley Grove 	esas2r_trace_exit();
47726780d9eSBradley Grove }
47826780d9eSBradley Grove 
esas2r_chip_rst_needed_during_tasklet(struct esas2r_adapter * a)47926780d9eSBradley Grove static void esas2r_chip_rst_needed_during_tasklet(struct esas2r_adapter *a)
48026780d9eSBradley Grove {
48126780d9eSBradley Grove 
4829588d24eSBradley Grove 	clear_bit(AF_CHPRST_NEEDED, &a->flags);
4839588d24eSBradley Grove 	clear_bit(AF_BUSRST_NEEDED, &a->flags);
4849588d24eSBradley Grove 	clear_bit(AF_BUSRST_DETECTED, &a->flags);
4859588d24eSBradley Grove 	clear_bit(AF_BUSRST_PENDING, &a->flags);
48626780d9eSBradley Grove 	/*
48726780d9eSBradley Grove 	 * Make sure we don't get attempt more than 3 resets
48826780d9eSBradley Grove 	 * when the uptime between resets does not exceed one
48926780d9eSBradley Grove 	 * minute.  This will stop any situation where there is
49026780d9eSBradley Grove 	 * really something wrong with the hardware.  The way
49126780d9eSBradley Grove 	 * this works is that we start with uptime ticks at 0.
49226780d9eSBradley Grove 	 * Each time we do a reset, we add 20 seconds worth to
49326780d9eSBradley Grove 	 * the count.  Each time a timer tick occurs, as long
49426780d9eSBradley Grove 	 * as a chip reset is not pending, we decrement the
49526780d9eSBradley Grove 	 * tick count.  If the uptime ticks ever gets to 60
49626780d9eSBradley Grove 	 * seconds worth, we disable the adapter from that
49726780d9eSBradley Grove 	 * point forward.  Three strikes, you're out.
49826780d9eSBradley Grove 	 */
49926780d9eSBradley Grove 	if (!esas2r_is_adapter_present(a) || (a->chip_uptime >=
50026780d9eSBradley Grove 					      ESAS2R_CHP_UPTIME_MAX)) {
50126780d9eSBradley Grove 		esas2r_hdebug("*** adapter disabled ***");
50226780d9eSBradley Grove 
50326780d9eSBradley Grove 		/*
50426780d9eSBradley Grove 		 * Ok, some kind of hard failure.  Make sure we
50526780d9eSBradley Grove 		 * exit this loop with chip interrupts
50626780d9eSBradley Grove 		 * permanently disabled so we don't lock up the
50726780d9eSBradley Grove 		 * entire system.  Also flag degraded mode to
50826780d9eSBradley Grove 		 * prevent the heartbeat from trying to recover.
50926780d9eSBradley Grove 		 */
51026780d9eSBradley Grove 
5119588d24eSBradley Grove 		set_bit(AF_DEGRADED_MODE, &a->flags);
5129588d24eSBradley Grove 		set_bit(AF_DISABLED, &a->flags);
5139588d24eSBradley Grove 		clear_bit(AF_CHPRST_PENDING, &a->flags);
5149588d24eSBradley Grove 		clear_bit(AF_DISC_PENDING, &a->flags);
51526780d9eSBradley Grove 
51626780d9eSBradley Grove 		esas2r_disable_chip_interrupts(a);
51726780d9eSBradley Grove 		a->int_mask = 0;
51826780d9eSBradley Grove 		esas2r_process_adapter_reset(a);
51926780d9eSBradley Grove 
52026780d9eSBradley Grove 		esas2r_log(ESAS2R_LOG_CRIT,
52126780d9eSBradley Grove 			   "Adapter disabled because of hardware failure");
52226780d9eSBradley Grove 	} else {
5239588d24eSBradley Grove 		bool alrdyrst = test_and_set_bit(AF_CHPRST_STARTED, &a->flags);
52426780d9eSBradley Grove 
5259588d24eSBradley Grove 		if (!alrdyrst)
52626780d9eSBradley Grove 			/*
52726780d9eSBradley Grove 			 * Only disable interrupts if this is
52826780d9eSBradley Grove 			 * the first reset attempt.
52926780d9eSBradley Grove 			 */
53026780d9eSBradley Grove 			esas2r_disable_chip_interrupts(a);
53126780d9eSBradley Grove 
5329588d24eSBradley Grove 		if ((test_bit(AF_POWER_MGT, &a->flags)) &&
5339588d24eSBradley Grove 		    !test_bit(AF_FIRST_INIT, &a->flags) && !alrdyrst) {
53426780d9eSBradley Grove 			/*
53526780d9eSBradley Grove 			 * Don't reset the chip on the first
53626780d9eSBradley Grove 			 * deferred power up attempt.
53726780d9eSBradley Grove 			 */
53826780d9eSBradley Grove 		} else {
53926780d9eSBradley Grove 			esas2r_hdebug("*** resetting chip ***");
54026780d9eSBradley Grove 			esas2r_reset_chip(a);
54126780d9eSBradley Grove 		}
54226780d9eSBradley Grove 
54326780d9eSBradley Grove 		/* Kick off the reinitialization */
54426780d9eSBradley Grove 		a->chip_uptime += ESAS2R_CHP_UPTIME_CNT;
54526780d9eSBradley Grove 		a->chip_init_time = jiffies_to_msecs(jiffies);
5469588d24eSBradley Grove 		if (!test_bit(AF_POWER_MGT, &a->flags)) {
54726780d9eSBradley Grove 			esas2r_process_adapter_reset(a);
54826780d9eSBradley Grove 
5499588d24eSBradley Grove 			if (!alrdyrst) {
55026780d9eSBradley Grove 				/* Remove devices now that I/O is cleaned up. */
55126780d9eSBradley Grove 				a->prev_dev_cnt =
55226780d9eSBradley Grove 					esas2r_targ_db_get_tgt_cnt(a);
55326780d9eSBradley Grove 				esas2r_targ_db_remove_all(a, false);
55426780d9eSBradley Grove 			}
55526780d9eSBradley Grove 		}
55626780d9eSBradley Grove 
55726780d9eSBradley Grove 		a->int_mask = 0;
55826780d9eSBradley Grove 	}
55926780d9eSBradley Grove }
56026780d9eSBradley Grove 
esas2r_handle_chip_rst_during_tasklet(struct esas2r_adapter * a)56126780d9eSBradley Grove static void esas2r_handle_chip_rst_during_tasklet(struct esas2r_adapter *a)
56226780d9eSBradley Grove {
5639588d24eSBradley Grove 	while (test_bit(AF_CHPRST_DETECTED, &a->flags)) {
56426780d9eSBradley Grove 		/*
56526780d9eSBradley Grove 		 * Balance the enable in esas2r_initadapter_hw.
56626780d9eSBradley Grove 		 * Esas2r_power_down already took care of it for power
56726780d9eSBradley Grove 		 * management.
56826780d9eSBradley Grove 		 */
5699588d24eSBradley Grove 		if (!test_bit(AF_DEGRADED_MODE, &a->flags) &&
5709588d24eSBradley Grove 		    !test_bit(AF_POWER_MGT, &a->flags))
57126780d9eSBradley Grove 			esas2r_disable_chip_interrupts(a);
57226780d9eSBradley Grove 
57326780d9eSBradley Grove 		/* Reinitialize the chip. */
57426780d9eSBradley Grove 		esas2r_check_adapter(a);
57526780d9eSBradley Grove 		esas2r_init_adapter_hw(a, 0);
57626780d9eSBradley Grove 
5779588d24eSBradley Grove 		if (test_bit(AF_CHPRST_NEEDED, &a->flags))
57826780d9eSBradley Grove 			break;
57926780d9eSBradley Grove 
5809588d24eSBradley Grove 		if (test_bit(AF_POWER_MGT, &a->flags)) {
58126780d9eSBradley Grove 			/* Recovery from power management. */
5829588d24eSBradley Grove 			if (test_bit(AF_FIRST_INIT, &a->flags)) {
58326780d9eSBradley Grove 				/* Chip reset during normal power up */
58426780d9eSBradley Grove 				esas2r_log(ESAS2R_LOG_CRIT,
58526780d9eSBradley Grove 					   "The firmware was reset during a normal power-up sequence");
58626780d9eSBradley Grove 			} else {
58726780d9eSBradley Grove 				/* Deferred power up complete. */
5889588d24eSBradley Grove 				clear_bit(AF_POWER_MGT, &a->flags);
58926780d9eSBradley Grove 				esas2r_send_reset_ae(a, true);
59026780d9eSBradley Grove 			}
59126780d9eSBradley Grove 		} else {
59226780d9eSBradley Grove 			/* Recovery from online chip reset. */
5939588d24eSBradley Grove 			if (test_bit(AF_FIRST_INIT, &a->flags)) {
59426780d9eSBradley Grove 				/* Chip reset during driver load */
59526780d9eSBradley Grove 			} else {
59626780d9eSBradley Grove 				/* Chip reset after driver load */
59726780d9eSBradley Grove 				esas2r_send_reset_ae(a, false);
59826780d9eSBradley Grove 			}
59926780d9eSBradley Grove 
60026780d9eSBradley Grove 			esas2r_log(ESAS2R_LOG_CRIT,
60126780d9eSBradley Grove 				   "Recovering from a chip reset while the chip was online");
60226780d9eSBradley Grove 		}
60326780d9eSBradley Grove 
6049588d24eSBradley Grove 		clear_bit(AF_CHPRST_STARTED, &a->flags);
60526780d9eSBradley Grove 		esas2r_enable_chip_interrupts(a);
60626780d9eSBradley Grove 
60726780d9eSBradley Grove 		/*
60826780d9eSBradley Grove 		 * Clear this flag last!  this indicates that the chip has been
60926780d9eSBradley Grove 		 * reset already during initialization.
61026780d9eSBradley Grove 		 */
6119588d24eSBradley Grove 		clear_bit(AF_CHPRST_DETECTED, &a->flags);
61226780d9eSBradley Grove 	}
61326780d9eSBradley Grove }
61426780d9eSBradley Grove 
61526780d9eSBradley Grove 
61626780d9eSBradley Grove /* Perform deferred tasks when chip interrupts are disabled */
esas2r_do_tasklet_tasks(struct esas2r_adapter * a)61726780d9eSBradley Grove void esas2r_do_tasklet_tasks(struct esas2r_adapter *a)
61826780d9eSBradley Grove {
6199588d24eSBradley Grove 
6209588d24eSBradley Grove 	if (test_bit(AF_CHPRST_NEEDED, &a->flags) ||
6219588d24eSBradley Grove 	    test_bit(AF_CHPRST_DETECTED, &a->flags)) {
6229588d24eSBradley Grove 		if (test_bit(AF_CHPRST_NEEDED, &a->flags))
62326780d9eSBradley Grove 			esas2r_chip_rst_needed_during_tasklet(a);
62426780d9eSBradley Grove 
62526780d9eSBradley Grove 		esas2r_handle_chip_rst_during_tasklet(a);
62626780d9eSBradley Grove 	}
62726780d9eSBradley Grove 
6289588d24eSBradley Grove 	if (test_bit(AF_BUSRST_NEEDED, &a->flags)) {
62926780d9eSBradley Grove 		esas2r_hdebug("hard resetting bus");
63026780d9eSBradley Grove 
6319588d24eSBradley Grove 		clear_bit(AF_BUSRST_NEEDED, &a->flags);
63226780d9eSBradley Grove 
6339588d24eSBradley Grove 		if (test_bit(AF_FLASHING, &a->flags))
6349588d24eSBradley Grove 			set_bit(AF_BUSRST_DETECTED, &a->flags);
63526780d9eSBradley Grove 		else
63626780d9eSBradley Grove 			esas2r_write_register_dword(a, MU_DOORBELL_IN,
63726780d9eSBradley Grove 						    DRBL_RESET_BUS);
63826780d9eSBradley Grove 	}
63926780d9eSBradley Grove 
6409588d24eSBradley Grove 	if (test_bit(AF_BUSRST_DETECTED, &a->flags)) {
64126780d9eSBradley Grove 		esas2r_process_bus_reset(a);
64226780d9eSBradley Grove 
64326780d9eSBradley Grove 		esas2r_log_dev(ESAS2R_LOG_WARN,
64426780d9eSBradley Grove 			       &(a->host->shost_gendev),
64526780d9eSBradley Grove 			       "scsi_report_bus_reset() called");
64626780d9eSBradley Grove 
64726780d9eSBradley Grove 		scsi_report_bus_reset(a->host, 0);
64826780d9eSBradley Grove 
6499588d24eSBradley Grove 		clear_bit(AF_BUSRST_DETECTED, &a->flags);
6509588d24eSBradley Grove 		clear_bit(AF_BUSRST_PENDING, &a->flags);
65126780d9eSBradley Grove 
65226780d9eSBradley Grove 		esas2r_log(ESAS2R_LOG_WARN, "Bus reset complete");
65326780d9eSBradley Grove 	}
65426780d9eSBradley Grove 
6559588d24eSBradley Grove 	if (test_bit(AF_PORT_CHANGE, &a->flags)) {
6569588d24eSBradley Grove 		clear_bit(AF_PORT_CHANGE, &a->flags);
65726780d9eSBradley Grove 
65826780d9eSBradley Grove 		esas2r_targ_db_report_changes(a);
65926780d9eSBradley Grove 	}
66026780d9eSBradley Grove 
66126780d9eSBradley Grove 	if (atomic_read(&a->disable_cnt) == 0)
66226780d9eSBradley Grove 		esas2r_do_deferred_processes(a);
66326780d9eSBradley Grove }
66426780d9eSBradley Grove 
esas2r_doorbell_interrupt(struct esas2r_adapter * a,u32 doorbell)66526780d9eSBradley Grove static void esas2r_doorbell_interrupt(struct esas2r_adapter *a, u32 doorbell)
66626780d9eSBradley Grove {
66726780d9eSBradley Grove 	if (!(doorbell & DRBL_FORCE_INT)) {
66826780d9eSBradley Grove 		esas2r_trace_enter();
66926780d9eSBradley Grove 		esas2r_trace("doorbell: %x", doorbell);
67026780d9eSBradley Grove 	}
67126780d9eSBradley Grove 
67226780d9eSBradley Grove 	/* First clear the doorbell bits */
67326780d9eSBradley Grove 	esas2r_write_register_dword(a, MU_DOORBELL_OUT, doorbell);
67426780d9eSBradley Grove 
67526780d9eSBradley Grove 	if (doorbell & DRBL_RESET_BUS)
6769588d24eSBradley Grove 		set_bit(AF_BUSRST_DETECTED, &a->flags);
67726780d9eSBradley Grove 
67826780d9eSBradley Grove 	if (doorbell & DRBL_FORCE_INT)
6799588d24eSBradley Grove 		clear_bit(AF_HEARTBEAT, &a->flags);
68026780d9eSBradley Grove 
68126780d9eSBradley Grove 	if (doorbell & DRBL_PANIC_REASON_MASK) {
68226780d9eSBradley Grove 		esas2r_hdebug("*** Firmware Panic ***");
68326780d9eSBradley Grove 		esas2r_log(ESAS2R_LOG_CRIT, "The firmware has panicked");
68426780d9eSBradley Grove 	}
68526780d9eSBradley Grove 
68626780d9eSBradley Grove 	if (doorbell & DRBL_FW_RESET) {
6879588d24eSBradley Grove 		set_bit(AF2_COREDUMP_AVAIL, &a->flags2);
68826780d9eSBradley Grove 		esas2r_local_reset_adapter(a);
68926780d9eSBradley Grove 	}
69026780d9eSBradley Grove 
691*6abf98deSLee Jones 	if (!(doorbell & DRBL_FORCE_INT)) {
69226780d9eSBradley Grove 		esas2r_trace_exit();
69326780d9eSBradley Grove 	}
694*6abf98deSLee Jones }
69526780d9eSBradley Grove 
esas2r_force_interrupt(struct esas2r_adapter * a)69626780d9eSBradley Grove void esas2r_force_interrupt(struct esas2r_adapter *a)
69726780d9eSBradley Grove {
69826780d9eSBradley Grove 	esas2r_write_register_dword(a, MU_DOORBELL_IN, DRBL_FORCE_INT |
69926780d9eSBradley Grove 				    DRBL_DRV_VER);
70026780d9eSBradley Grove }
70126780d9eSBradley Grove 
70226780d9eSBradley Grove 
esas2r_lun_event(struct esas2r_adapter * a,union atto_vda_ae * ae,u16 target,u32 length)70326780d9eSBradley Grove static void esas2r_lun_event(struct esas2r_adapter *a, union atto_vda_ae *ae,
70426780d9eSBradley Grove 			     u16 target, u32 length)
70526780d9eSBradley Grove {
70626780d9eSBradley Grove 	struct esas2r_target *t = a->targetdb + target;
70726780d9eSBradley Grove 	u32 cplen = length;
70826780d9eSBradley Grove 	unsigned long flags;
70926780d9eSBradley Grove 
71026780d9eSBradley Grove 	if (cplen > sizeof(t->lu_event))
71126780d9eSBradley Grove 		cplen = sizeof(t->lu_event);
71226780d9eSBradley Grove 
71326780d9eSBradley Grove 	esas2r_trace("ae->lu.dwevent: %x", ae->lu.dwevent);
71426780d9eSBradley Grove 	esas2r_trace("ae->lu.bystate: %x", ae->lu.bystate);
71526780d9eSBradley Grove 
71626780d9eSBradley Grove 	spin_lock_irqsave(&a->mem_lock, flags);
71726780d9eSBradley Grove 
71826780d9eSBradley Grove 	t->new_target_state = TS_INVALID;
71926780d9eSBradley Grove 
72026780d9eSBradley Grove 	if (ae->lu.dwevent  & VDAAE_LU_LOST) {
72126780d9eSBradley Grove 		t->new_target_state = TS_NOT_PRESENT;
72226780d9eSBradley Grove 	} else {
72326780d9eSBradley Grove 		switch (ae->lu.bystate) {
72426780d9eSBradley Grove 		case VDAAE_LU_NOT_PRESENT:
72526780d9eSBradley Grove 		case VDAAE_LU_OFFLINE:
72626780d9eSBradley Grove 		case VDAAE_LU_DELETED:
72726780d9eSBradley Grove 		case VDAAE_LU_FACTORY_DISABLED:
72826780d9eSBradley Grove 			t->new_target_state = TS_NOT_PRESENT;
72926780d9eSBradley Grove 			break;
73026780d9eSBradley Grove 
73126780d9eSBradley Grove 		case VDAAE_LU_ONLINE:
73226780d9eSBradley Grove 		case VDAAE_LU_DEGRADED:
73326780d9eSBradley Grove 			t->new_target_state = TS_PRESENT;
73426780d9eSBradley Grove 			break;
73526780d9eSBradley Grove 		}
73626780d9eSBradley Grove 	}
73726780d9eSBradley Grove 
73826780d9eSBradley Grove 	if (t->new_target_state != TS_INVALID) {
73926780d9eSBradley Grove 		memcpy(&t->lu_event, &ae->lu, cplen);
74026780d9eSBradley Grove 
74126780d9eSBradley Grove 		esas2r_disc_queue_event(a, DCDE_DEV_CHANGE);
74226780d9eSBradley Grove 	}
74326780d9eSBradley Grove 
74426780d9eSBradley Grove 	spin_unlock_irqrestore(&a->mem_lock, flags);
74526780d9eSBradley Grove }
74626780d9eSBradley Grove 
74726780d9eSBradley Grove 
74826780d9eSBradley Grove 
esas2r_ae_complete(struct esas2r_adapter * a,struct esas2r_request * rq)74926780d9eSBradley Grove void esas2r_ae_complete(struct esas2r_adapter *a, struct esas2r_request *rq)
75026780d9eSBradley Grove {
75126780d9eSBradley Grove 	union atto_vda_ae *ae =
75226780d9eSBradley Grove 		(union atto_vda_ae *)rq->vda_rsp_data->ae_data.event_data;
75326780d9eSBradley Grove 	u32 length = le32_to_cpu(rq->func_rsp.ae_rsp.length);
75426780d9eSBradley Grove 	union atto_vda_ae *last =
75526780d9eSBradley Grove 		(union atto_vda_ae *)(rq->vda_rsp_data->ae_data.event_data
75626780d9eSBradley Grove 				      + length);
75726780d9eSBradley Grove 
75826780d9eSBradley Grove 	esas2r_trace_enter();
75926780d9eSBradley Grove 	esas2r_trace("length: %d", length);
76026780d9eSBradley Grove 
76126780d9eSBradley Grove 	if (length > sizeof(struct atto_vda_ae_data)
76226780d9eSBradley Grove 	    || (length & 3) != 0
76326780d9eSBradley Grove 	    || length == 0) {
76426780d9eSBradley Grove 		esas2r_log(ESAS2R_LOG_WARN,
76526780d9eSBradley Grove 			   "The AE request response length (%p) is too long: %d",
76626780d9eSBradley Grove 			   rq, length);
76726780d9eSBradley Grove 
76826780d9eSBradley Grove 		esas2r_hdebug("aereq->length (0x%x) too long", length);
76926780d9eSBradley Grove 		esas2r_bugon();
77026780d9eSBradley Grove 
77126780d9eSBradley Grove 		last = ae;
77226780d9eSBradley Grove 	}
77326780d9eSBradley Grove 
77426780d9eSBradley Grove 	while (ae < last) {
77526780d9eSBradley Grove 		u16 target;
77626780d9eSBradley Grove 
77726780d9eSBradley Grove 		esas2r_trace("ae: %p", ae);
77826780d9eSBradley Grove 		esas2r_trace("ae->hdr: %p", &(ae->hdr));
77926780d9eSBradley Grove 
78026780d9eSBradley Grove 		length = ae->hdr.bylength;
78126780d9eSBradley Grove 
78226780d9eSBradley Grove 		if (length > (u32)((u8 *)last - (u8 *)ae)
78326780d9eSBradley Grove 		    || (length & 3) != 0
78426780d9eSBradley Grove 		    || length == 0) {
78526780d9eSBradley Grove 			esas2r_log(ESAS2R_LOG_CRIT,
78626780d9eSBradley Grove 				   "the async event length is invalid (%p): %d",
78726780d9eSBradley Grove 				   ae, length);
78826780d9eSBradley Grove 
78926780d9eSBradley Grove 			esas2r_hdebug("ae->hdr.length (0x%x) invalid", length);
79026780d9eSBradley Grove 			esas2r_bugon();
79126780d9eSBradley Grove 
79226780d9eSBradley Grove 			break;
79326780d9eSBradley Grove 		}
79426780d9eSBradley Grove 
79526780d9eSBradley Grove 		esas2r_nuxi_ae_data(ae);
79626780d9eSBradley Grove 
79726780d9eSBradley Grove 		esas2r_queue_fw_event(a, fw_event_vda_ae, ae,
79826780d9eSBradley Grove 				      sizeof(union atto_vda_ae));
79926780d9eSBradley Grove 
80026780d9eSBradley Grove 		switch (ae->hdr.bytype) {
80126780d9eSBradley Grove 		case VDAAE_HDR_TYPE_RAID:
80226780d9eSBradley Grove 
80326780d9eSBradley Grove 			if (ae->raid.dwflags & (VDAAE_GROUP_STATE
80426780d9eSBradley Grove 						| VDAAE_RBLD_STATE
80526780d9eSBradley Grove 						| VDAAE_MEMBER_CHG
80626780d9eSBradley Grove 						| VDAAE_PART_CHG)) {
80726780d9eSBradley Grove 				esas2r_log(ESAS2R_LOG_INFO,
80826780d9eSBradley Grove 					   "RAID event received - name:%s rebuild_state:%d group_state:%d",
80926780d9eSBradley Grove 					   ae->raid.acname,
81026780d9eSBradley Grove 					   ae->raid.byrebuild_state,
81126780d9eSBradley Grove 					   ae->raid.bygroup_state);
81226780d9eSBradley Grove 			}
81326780d9eSBradley Grove 
81426780d9eSBradley Grove 			break;
81526780d9eSBradley Grove 
81626780d9eSBradley Grove 		case VDAAE_HDR_TYPE_LU:
81726780d9eSBradley Grove 			esas2r_log(ESAS2R_LOG_INFO,
81826780d9eSBradley Grove 				   "LUN event received: event:%d target_id:%d LUN:%d state:%d",
81926780d9eSBradley Grove 				   ae->lu.dwevent,
82026780d9eSBradley Grove 				   ae->lu.id.tgtlun.wtarget_id,
82126780d9eSBradley Grove 				   ae->lu.id.tgtlun.bylun,
82226780d9eSBradley Grove 				   ae->lu.bystate);
82326780d9eSBradley Grove 
82426780d9eSBradley Grove 			target = ae->lu.id.tgtlun.wtarget_id;
82526780d9eSBradley Grove 
82626780d9eSBradley Grove 			if (target < ESAS2R_MAX_TARGETS)
82726780d9eSBradley Grove 				esas2r_lun_event(a, ae, target, length);
82826780d9eSBradley Grove 
82926780d9eSBradley Grove 			break;
83026780d9eSBradley Grove 
83126780d9eSBradley Grove 		case VDAAE_HDR_TYPE_DISK:
83226780d9eSBradley Grove 			esas2r_log(ESAS2R_LOG_INFO, "Disk event received");
83326780d9eSBradley Grove 			break;
83426780d9eSBradley Grove 
83526780d9eSBradley Grove 		default:
83626780d9eSBradley Grove 
83726780d9eSBradley Grove 			/* Silently ignore the rest and let the apps deal with
83826780d9eSBradley Grove 			 * them.
83926780d9eSBradley Grove 			 */
84026780d9eSBradley Grove 
84126780d9eSBradley Grove 			break;
84226780d9eSBradley Grove 		}
84326780d9eSBradley Grove 
84426780d9eSBradley Grove 		ae = (union atto_vda_ae *)((u8 *)ae + length);
84526780d9eSBradley Grove 	}
84626780d9eSBradley Grove 
84726780d9eSBradley Grove 	/* Now requeue it. */
84826780d9eSBradley Grove 	esas2r_start_ae_request(a, rq);
84926780d9eSBradley Grove 	esas2r_trace_exit();
85026780d9eSBradley Grove }
85126780d9eSBradley Grove 
85226780d9eSBradley Grove /* Send an asynchronous event for a chip reset or power management. */
esas2r_send_reset_ae(struct esas2r_adapter * a,bool pwr_mgt)85326780d9eSBradley Grove void esas2r_send_reset_ae(struct esas2r_adapter *a, bool pwr_mgt)
85426780d9eSBradley Grove {
85526780d9eSBradley Grove 	struct atto_vda_ae_hdr ae;
85626780d9eSBradley Grove 
85726780d9eSBradley Grove 	if (pwr_mgt)
85826780d9eSBradley Grove 		ae.bytype = VDAAE_HDR_TYPE_PWRMGT;
85926780d9eSBradley Grove 	else
86026780d9eSBradley Grove 		ae.bytype = VDAAE_HDR_TYPE_RESET;
86126780d9eSBradley Grove 
86226780d9eSBradley Grove 	ae.byversion = VDAAE_HDR_VER_0;
86326780d9eSBradley Grove 	ae.byflags = 0;
86426780d9eSBradley Grove 	ae.bylength = (u8)sizeof(struct atto_vda_ae_hdr);
86526780d9eSBradley Grove 
866*6abf98deSLee Jones 	if (pwr_mgt) {
86726780d9eSBradley Grove 		esas2r_hdebug("*** sending power management AE ***");
868*6abf98deSLee Jones 	} else {
86926780d9eSBradley Grove 		esas2r_hdebug("*** sending reset AE ***");
870*6abf98deSLee Jones 	}
87126780d9eSBradley Grove 
87226780d9eSBradley Grove 	esas2r_queue_fw_event(a, fw_event_vda_ae, &ae,
87326780d9eSBradley Grove 			      sizeof(union atto_vda_ae));
87426780d9eSBradley Grove }
87526780d9eSBradley Grove 
esas2r_dummy_complete(struct esas2r_adapter * a,struct esas2r_request * rq)87626780d9eSBradley Grove void esas2r_dummy_complete(struct esas2r_adapter *a, struct esas2r_request *rq)
87726780d9eSBradley Grove {}
87826780d9eSBradley Grove 
esas2r_check_req_rsp_sense(struct esas2r_adapter * a,struct esas2r_request * rq)87926780d9eSBradley Grove static void esas2r_check_req_rsp_sense(struct esas2r_adapter *a,
88026780d9eSBradley Grove 				       struct esas2r_request *rq)
88126780d9eSBradley Grove {
88226780d9eSBradley Grove 	u8 snslen, snslen2;
88326780d9eSBradley Grove 
88426780d9eSBradley Grove 	snslen = snslen2 = rq->func_rsp.scsi_rsp.sense_len;
88526780d9eSBradley Grove 
88626780d9eSBradley Grove 	if (snslen > rq->sense_len)
88726780d9eSBradley Grove 		snslen = rq->sense_len;
88826780d9eSBradley Grove 
88926780d9eSBradley Grove 	if (snslen) {
89026780d9eSBradley Grove 		if (rq->sense_buf)
89126780d9eSBradley Grove 			memcpy(rq->sense_buf, rq->data_buf, snslen);
89226780d9eSBradley Grove 		else
89326780d9eSBradley Grove 			rq->sense_buf = (u8 *)rq->data_buf;
89426780d9eSBradley Grove 
89526780d9eSBradley Grove 		/* See about possible sense data */
89626780d9eSBradley Grove 		if (snslen2 > 0x0c) {
89726780d9eSBradley Grove 			u8 *s = (u8 *)rq->data_buf;
89826780d9eSBradley Grove 
89926780d9eSBradley Grove 			esas2r_trace_enter();
90026780d9eSBradley Grove 
90126780d9eSBradley Grove 			/* Report LUNS data has changed */
90226780d9eSBradley Grove 			if (s[0x0c] == 0x3f && s[0x0d] == 0x0E) {
90326780d9eSBradley Grove 				esas2r_trace("rq->target_id: %d",
90426780d9eSBradley Grove 					     rq->target_id);
90526780d9eSBradley Grove 				esas2r_target_state_changed(a, rq->target_id,
90626780d9eSBradley Grove 							    TS_LUN_CHANGE);
90726780d9eSBradley Grove 			}
90826780d9eSBradley Grove 
90926780d9eSBradley Grove 			esas2r_trace("add_sense_key=%x", s[0x0c]);
91026780d9eSBradley Grove 			esas2r_trace("add_sense_qual=%x", s[0x0d]);
91126780d9eSBradley Grove 			esas2r_trace_exit();
91226780d9eSBradley Grove 		}
91326780d9eSBradley Grove 	}
91426780d9eSBradley Grove 
91526780d9eSBradley Grove 	rq->sense_len = snslen;
91626780d9eSBradley Grove }
91726780d9eSBradley Grove 
91826780d9eSBradley Grove 
esas2r_complete_request(struct esas2r_adapter * a,struct esas2r_request * rq)91926780d9eSBradley Grove void esas2r_complete_request(struct esas2r_adapter *a,
92026780d9eSBradley Grove 			     struct esas2r_request *rq)
92126780d9eSBradley Grove {
92226780d9eSBradley Grove 	if (rq->vrq->scsi.function == VDA_FUNC_FLASH
92326780d9eSBradley Grove 	    && rq->vrq->flash.sub_func == VDA_FLASH_COMMIT)
9249588d24eSBradley Grove 		clear_bit(AF_FLASHING, &a->flags);
92526780d9eSBradley Grove 
92626780d9eSBradley Grove 	/* See if we setup a callback to do special processing */
92726780d9eSBradley Grove 
92826780d9eSBradley Grove 	if (rq->interrupt_cb) {
92926780d9eSBradley Grove 		(*rq->interrupt_cb)(a, rq);
93026780d9eSBradley Grove 
93126780d9eSBradley Grove 		if (rq->req_stat == RS_PENDING) {
93226780d9eSBradley Grove 			esas2r_start_request(a, rq);
93326780d9eSBradley Grove 			return;
93426780d9eSBradley Grove 		}
93526780d9eSBradley Grove 	}
93626780d9eSBradley Grove 
93726780d9eSBradley Grove 	if (likely(rq->vrq->scsi.function == VDA_FUNC_SCSI)
93826780d9eSBradley Grove 	    && unlikely(rq->req_stat != RS_SUCCESS)) {
93926780d9eSBradley Grove 		esas2r_check_req_rsp_sense(a, rq);
94026780d9eSBradley Grove 		esas2r_log_request_failure(a, rq);
94126780d9eSBradley Grove 	}
94226780d9eSBradley Grove 
94326780d9eSBradley Grove 	(*rq->comp_cb)(a, rq);
94426780d9eSBradley Grove }
945