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