perf annotate: Handle samples not at objdump output addr boundaries
[safe/jmp/linux-2.6] / drivers / scsi / qla4xxx / ql4_isr.c
index ef975e0..c196d55 100644 (file)
@@ -6,26 +6,99 @@
  */
 
 #include "ql4_def.h"
+#include "ql4_glbl.h"
+#include "ql4_dbg.h"
+#include "ql4_inline.h"
 
 /**
- * qla2x00_process_completed_request() - Process a Fast Post response.
- * @ha: SCSI driver HA context
- * @index: SRB index
+ * qla4xxx_copy_sense - copy sense data        into cmd sense buffer
+ * @ha: Pointer to host adapter structure.
+ * @sts_entry: Pointer to status entry structure.
+ * @srb: Pointer to srb structure.
  **/
-static void qla4xxx_process_completed_request(struct scsi_qla_host *ha,
-                                             uint32_t index)
+static void qla4xxx_copy_sense(struct scsi_qla_host *ha,
+                               struct status_entry *sts_entry,
+                               struct srb *srb)
 {
-       struct srb *srb;
+       struct scsi_cmnd *cmd = srb->cmd;
+       uint16_t sense_len;
+
+       memset(cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
+       sense_len = le16_to_cpu(sts_entry->senseDataByteCnt);
+       if (sense_len == 0)
+               return;
+
+       /* Save total available sense length,
+        * not to exceed cmd's sense buffer size */
+       sense_len = min_t(uint16_t, sense_len, SCSI_SENSE_BUFFERSIZE);
+       srb->req_sense_ptr = cmd->sense_buffer;
+       srb->req_sense_len = sense_len;
+
+       /* Copy sense from sts_entry pkt */
+       sense_len = min_t(uint16_t, sense_len, IOCB_MAX_SENSEDATA_LEN);
+       memcpy(cmd->sense_buffer, sts_entry->senseData, sense_len);
+
+       DEBUG2(printk(KERN_INFO "scsi%ld:%d:%d:%d: %s: sense key = %x, "
+               "ASL= %02x, ASC/ASCQ = %02x/%02x\n", ha->host_no,
+               cmd->device->channel, cmd->device->id,
+               cmd->device->lun, __func__,
+               sts_entry->senseData[2] & 0x0f,
+               sts_entry->senseData[7],
+               sts_entry->senseData[12],
+               sts_entry->senseData[13]));
+
+       DEBUG5(qla4xxx_dump_buffer(cmd->sense_buffer, sense_len));
+       srb->flags |= SRB_GOT_SENSE;
+
+       /* Update srb, in case a sts_cont pkt follows */
+       srb->req_sense_ptr += sense_len;
+       srb->req_sense_len -= sense_len;
+       if (srb->req_sense_len != 0)
+               ha->status_srb = srb;
+       else
+               ha->status_srb = NULL;
+}
+
+/**
+ * qla4xxx_status_cont_entry - Process a Status Continuations entry.
+ * @ha: SCSI driver HA context
+ * @sts_cont: Entry pointer
+ *
+ * Extended sense data.
+ */
+static void
+qla4xxx_status_cont_entry(struct scsi_qla_host *ha,
+                         struct status_cont_entry *sts_cont)
+{
+       struct srb *srb = ha->status_srb;
+       struct scsi_cmnd *cmd;
+       uint8_t sense_len;
+
+       if (srb == NULL)
+               return;
+
+       cmd = srb->cmd;
+       if (cmd == NULL) {
+               DEBUG2(printk(KERN_INFO "scsi%ld: %s: Cmd already returned "
+                       "back to OS srb=%p srb->state:%d\n", ha->host_no,
+                       __func__, srb, srb->state));
+               ha->status_srb = NULL;
+               return;
+       }
+
+       /* Copy sense data. */
+       sense_len = min_t(uint16_t, srb->req_sense_len,
+                         IOCB_MAX_EXT_SENSEDATA_LEN);
+       memcpy(srb->req_sense_ptr, sts_cont->ext_sense_data, sense_len);
+       DEBUG5(qla4xxx_dump_buffer(srb->req_sense_ptr, sense_len));
 
-       srb = qla4xxx_del_from_active_array(ha, index);
-       if (srb) {
-               /* Save ISP completion status */
-               srb->cmd->result = DID_OK << 16;
+       srb->req_sense_ptr += sense_len;
+       srb->req_sense_len -= sense_len;
+
+       /* Place command on done queue. */
+       if (srb->req_sense_len == 0) {
                qla4xxx_srb_compl(ha, srb);
-       } else {
-               DEBUG2(printk("scsi%ld: Invalid ISP SCSI completion handle = "
-                             "%d\n", ha->host_no, index));
-               set_bit(DPC_RESET_HA, &ha->dpc_flags);
+               ha->status_srb = NULL;
        }
 }
 
@@ -42,15 +115,6 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha,
        struct srb *srb;
        struct ddb_entry *ddb_entry;
        uint32_t residual;
-       uint16_t sensebytecnt;
-
-       if (sts_entry->completionStatus == SCS_COMPLETE &&
-           sts_entry->scsiStatus == 0) {
-               qla4xxx_process_completed_request(ha,
-                                                 le32_to_cpu(sts_entry->
-                                                             handle));
-               return;
-       }
 
        srb = qla4xxx_del_from_active_array(ha, le32_to_cpu(sts_entry->handle));
        if (!srb) {
@@ -59,6 +123,9 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha,
                              "handle 0x%x, sp=%p. This cmd may have already "
                              "been completed.\n", ha->host_no, __func__,
                              le32_to_cpu(sts_entry->handle), srb));
+               dev_warn(&ha->pdev->dev, "%s invalid status entry:"
+                       " handle=0x%0x\n", __func__, sts_entry->handle);
+               set_bit(DPC_RESET_HA, &ha->dpc_flags);
                return;
        }
 
@@ -85,14 +152,30 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha,
        scsi_status = sts_entry->scsiStatus;
        switch (sts_entry->completionStatus) {
        case SCS_COMPLETE:
-               if (scsi_status == 0) {
-                       cmd->result = DID_OK << 16;
+
+               if (sts_entry->iscsiFlags & ISCSI_FLAG_RESIDUAL_OVER) {
+                       cmd->result = DID_ERROR << 16;
                        break;
                }
 
-               if (sts_entry->iscsiFlags &
-                   (ISCSI_FLAG_RESIDUAL_OVER|ISCSI_FLAG_RESIDUAL_UNDER))
-                       cmd->resid = residual;
+               if (sts_entry->iscsiFlags &ISCSI_FLAG_RESIDUAL_UNDER) {
+                       scsi_set_resid(cmd, residual);
+                       if (!scsi_status && ((scsi_bufflen(cmd) - residual) <
+                               cmd->underflow)) {
+
+                               cmd->result = DID_ERROR << 16;
+
+                               DEBUG2(printk("scsi%ld:%d:%d:%d: %s: "
+                                       "Mid-layer Data underrun0, "
+                                       "xferlen = 0x%x, "
+                                       "residual = 0x%x\n", ha->host_no,
+                                       cmd->device->channel,
+                                       cmd->device->id,
+                                       cmd->device->lun, __func__,
+                                       scsi_bufflen(cmd), residual));
+                               break;
+                       }
+               }
 
                cmd->result = DID_OK << 16 | scsi_status;
 
@@ -100,25 +183,7 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha,
                        break;
 
                /* Copy Sense Data into sense buffer. */
-               memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
-
-               sensebytecnt = le16_to_cpu(sts_entry->senseDataByteCnt);
-               if (sensebytecnt == 0)
-                       break;
-
-               memcpy(cmd->sense_buffer, sts_entry->senseData,
-                      min(sensebytecnt,
-                          (uint16_t) sizeof(cmd->sense_buffer)));
-
-               DEBUG2(printk("scsi%ld:%d:%d:%d: %s: sense key = %x, "
-                             "ASC/ASCQ = %02x/%02x\n", ha->host_no,
-                             cmd->device->channel, cmd->device->id,
-                             cmd->device->lun, __func__,
-                             sts_entry->senseData[2] & 0x0f,
-                             sts_entry->senseData[12],
-                             sts_entry->senseData[13]));
-
-               srb->flags |= SRB_GOT_SENSE;
+               qla4xxx_copy_sense(ha, sts_entry, srb);
                break;
 
        case SCS_INCOMPLETE:
@@ -148,7 +213,7 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha,
                              ha->host_no, cmd->device->channel,
                              cmd->device->id, cmd->device->lun));
 
-               cmd->result = DID_BUS_BUSY << 16;
+               cmd->result = DID_TRANSPORT_DISRUPTED << 16;
 
                /*
                 * Mark device missing so that we won't continue to send
@@ -161,31 +226,18 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha,
 
        case SCS_DATA_UNDERRUN:
        case SCS_DATA_OVERRUN:
-               if (sts_entry->iscsiFlags & ISCSI_FLAG_RESIDUAL_OVER) {
-                       DEBUG2(printk("scsi%ld:%d:%d:%d: %s: " "Data overrun, "
-                                     "residual = 0x%x\n", ha->host_no,
+               if ((sts_entry->iscsiFlags & ISCSI_FLAG_RESIDUAL_OVER) ||
+                    (sts_entry->completionStatus == SCS_DATA_OVERRUN)) {
+                       DEBUG2(printk("scsi%ld:%d:%d:%d: %s: " "Data overrun\n",
+                                     ha->host_no,
                                      cmd->device->channel, cmd->device->id,
-                                     cmd->device->lun, __func__, residual));
+                                     cmd->device->lun, __func__));
 
                        cmd->result = DID_ERROR << 16;
                        break;
                }
 
-               if ((sts_entry->iscsiFlags & ISCSI_FLAG_RESIDUAL_UNDER) == 0) {
-                       /*
-                        * Firmware detected a SCSI transport underrun
-                        * condition
-                        */
-                       cmd->resid = residual;
-                       DEBUG2(printk("scsi%ld:%d:%d:%d: %s: UNDERRUN status "
-                                     "detected, xferlen = 0x%x, residual = "
-                                     "0x%x\n",
-                                     ha->host_no, cmd->device->channel,
-                                     cmd->device->id,
-                                     cmd->device->lun, __func__,
-                                     cmd->request_bufflen,
-                                     residual));
-               }
+               scsi_set_resid(cmd, residual);
 
                /*
                 * If there is scsi_status, it takes precedense over
@@ -198,25 +250,7 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha,
                                break;
 
                        /* Copy Sense Data into sense buffer. */
-                       memset(cmd->sense_buffer, 0,
-                              sizeof(cmd->sense_buffer));
-
-                       sensebytecnt =
-                               le16_to_cpu(sts_entry->senseDataByteCnt);
-                       if (sensebytecnt == 0)
-                               break;
-
-                       memcpy(cmd->sense_buffer, sts_entry->senseData,
-                              min(sensebytecnt,
-                                  (uint16_t) sizeof(cmd->sense_buffer)));
-
-                       DEBUG2(printk("scsi%ld:%d:%d:%d: %s: sense key = %x, "
-                                     "ASC/ASCQ = %02x/%02x\n", ha->host_no,
-                                     cmd->device->channel, cmd->device->id,
-                                     cmd->device->lun, __func__,
-                                     sts_entry->senseData[2] & 0x0f,
-                                     sts_entry->senseData[12],
-                                     sts_entry->senseData[13]));
+                       qla4xxx_copy_sense(ha, sts_entry, srb);
                } else {
                        /*
                         * If RISC reports underrun and target does not
@@ -227,7 +261,7 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha,
                        if ((sts_entry->iscsiFlags &
                             ISCSI_FLAG_RESIDUAL_UNDER) == 0) {
                                cmd->result = DID_BUS_BUSY << 16;
-                       } else if ((cmd->request_bufflen - residual) <
+                       } else if ((scsi_bufflen(cmd) - residual) <
                                   cmd->underflow) {
                                /*
                                 * Handle mid-layer underflow???
@@ -242,13 +276,13 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha,
                                 * will return DID_ERROR.
                                 */
                                DEBUG2(printk("scsi%ld:%d:%d:%d: %s: "
-                                             "Mid-layer Data underrun, "
-                                             "xferlen = 0x%x, "
-                                             "residual = 0x%x\n", ha->host_no,
-                                             cmd->device->channel,
-                                             cmd->device->id,
-                                             cmd->device->lun, __func__,
-                                             cmd->request_bufflen, residual));
+                                       "Mid-layer Data underrun1, "
+                                       "xferlen = 0x%x, "
+                                       "residual = 0x%x\n", ha->host_no,
+                                       cmd->device->channel,
+                                       cmd->device->id,
+                                       cmd->device->lun, __func__,
+                                       scsi_bufflen(cmd), residual));
 
                                cmd->result = DID_ERROR << 16;
                        } else {
@@ -267,7 +301,7 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha,
                if (atomic_read(&ddb_entry->state) == DDB_STATE_ONLINE)
                        qla4xxx_mark_device_missing(ha, ddb_entry);
 
-               cmd->result = DID_BUS_BUSY << 16;
+               cmd->result = DID_TRANSPORT_DISRUPTED << 16;
                break;
 
        case SCS_QUEUE_FULL:
@@ -292,9 +326,10 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha,
 
 status_entry_exit:
 
-       /* complete the request */
+       /* complete the request, if not waiting for status_continuation pkt */
        srb->cc_stat = sts_entry->completionStatus;
-       qla4xxx_srb_compl(ha, srb);
+       if (ha->status_srb == NULL)
+               qla4xxx_srb_compl(ha, srb);
 }
 
 /**
@@ -329,10 +364,7 @@ static void qla4xxx_process_response_queue(struct scsi_qla_host * ha)
                /* process entry */
                switch (sts_entry->hdr.entryType) {
                case ET_STATUS:
-                       /*
-                        * Common status - Single completion posted in single
-                        * IOSB.
-                        */
+                       /* Common status */
                        qla4xxx_status_entry(ha, sts_entry);
                        break;
 
@@ -340,9 +372,8 @@ static void qla4xxx_process_response_queue(struct scsi_qla_host * ha)
                        break;
 
                case ET_STATUS_CONTINUATION:
-                       /* Just throw away the status continuation entries */
-                       DEBUG2(printk("scsi%ld: %s: Status Continuation entry "
-                                     "- ignoring\n", ha->host_no, __func__));
+                       qla4xxx_status_cont_entry(ha,
+                               (struct status_cont_entry *) sts_entry);
                        break;
 
                case ET_COMMAND:
@@ -417,6 +448,7 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha,
                                       uint32_t mbox_status)
 {
        int i;
+       uint32_t mbox_stat2, mbox_stat3;
 
        if ((mbox_status == MBOX_STS_BUSY) ||
            (mbox_status == MBOX_STS_INTERMEDIATE_COMPLETION) ||
@@ -433,11 +465,16 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha,
                                        readl(&ha->reg->mailbox[i]);
 
                        set_bit(AF_MBOX_COMMAND_DONE, &ha->flags);
-                       wake_up(&ha->mailbox_wait_queue);
                }
        } else if (mbox_status >> 12 == MBOX_ASYNC_EVENT_STATUS) {
                /* Immediately process the AENs that don't require much work.
                 * Only queue the database_changed AENs */
+               if (ha->aen_log.count < MAX_AEN_ENTRIES) {
+                       for (i = 0; i < MBOX_AEN_REG_COUNT; i++)
+                               ha->aen_log.entry[ha->aen_log.count].mbox_sts[i] =
+                                       readl(&ha->reg->mailbox[i]);
+                       ha->aen_log.count++;
+               }
                switch (mbox_status) {
                case MBOX_ASTS_SYSTEM_ERROR:
                        /* Log Mailbox registers */
@@ -494,6 +531,16 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha,
                                      mbox_status));
                        break;
 
+               case MBOX_ASTS_IP_ADDR_STATE_CHANGED:
+                       mbox_stat2 = readl(&ha->reg->mailbox[2]);
+                       mbox_stat3 = readl(&ha->reg->mailbox[3]);
+
+                       if ((mbox_stat3 == 5) && (mbox_stat2 == 3))
+                               set_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags);
+                       else if ((mbox_stat3 == 2) && (mbox_stat2 == 5))
+                               set_bit(DPC_RESET_HA, &ha->dpc_flags);
+                       break;
+
                case MBOX_ASTS_MAC_ADDRESS_CHANGED:
                case MBOX_ASTS_DNS:
                        /* No action */
@@ -519,11 +566,6 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha,
                        /* Queue AEN information and process it in the DPC
                         * routine */
                        if (ha->aen_q_count > 0) {
-                               /* advance pointer */
-                               if (ha->aen_in == (MAX_AEN_ENTRIES - 1))
-                                       ha->aen_in = 0;
-                               else
-                                       ha->aen_in++;
 
                                /* decrement available counter */
                                ha->aen_q_count--;
@@ -543,6 +585,10 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha,
                                              ha->aen_q[ha->aen_in].mbox_sts[2],
                                              ha->aen_q[ha->aen_in].mbox_sts[3],
                                              ha->aen_q[ha->aen_in].  mbox_sts[4]));
+                               /* advance pointer */
+                               ha->aen_in++;
+                               if (ha->aen_in == MAX_AEN_ENTRIES)
+                                       ha->aen_in = 0;
 
                                /* The DPC routine will process the aen */
                                set_bit(DPC_AEN, &ha->dpc_flags);
@@ -686,7 +732,8 @@ irqreturn_t qla4xxx_intr_handler(int irq, void *dev_id)
                               &ha->reg->ctrl_status);
                        readl(&ha->reg->ctrl_status);
 
-                       set_bit(DPC_RESET_HA_INTR, &ha->dpc_flags);
+                       if (!ql4_mod_unload)
+                               set_bit(DPC_RESET_HA_INTR, &ha->dpc_flags);
 
                        break;
                } else if (intr_status & INTR_PENDING) {
@@ -724,25 +771,24 @@ void qla4xxx_process_aen(struct scsi_qla_host * ha, uint8_t process_aen)
 
        spin_lock_irqsave(&ha->hardware_lock, flags);
        while (ha->aen_out != ha->aen_in) {
-               /* Advance pointers for next entry */
-               if (ha->aen_out == (MAX_AEN_ENTRIES - 1))
-                       ha->aen_out = 0;
-               else
-                       ha->aen_out++;
-
-               ha->aen_q_count++;
                aen = &ha->aen_q[ha->aen_out];
-
                /* copy aen information to local structure */
                for (i = 0; i < MBOX_AEN_REG_COUNT; i++)
                        mbox_sts[i] = aen->mbox_sts[i];
 
+               ha->aen_q_count++;
+               ha->aen_out++;
+
+               if (ha->aen_out == MAX_AEN_ENTRIES)
+                       ha->aen_out = 0;
+
                spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
-               DEBUG(printk("scsi%ld: AEN[%d] %04x, index [%d] state=%04x "
-                            "mod=%x conerr=%08x \n", ha->host_no, ha->aen_out,
-                            mbox_sts[0], mbox_sts[2], mbox_sts[3],
-                            mbox_sts[1], mbox_sts[4]));
+               DEBUG2(printk("qla4xxx(%ld): AEN[%d]=0x%08x, mbx1=0x%08x mbx2=0x%08x"
+                       " mbx3=0x%08x mbx4=0x%08x\n", ha->host_no,
+                       (ha->aen_out ? (ha->aen_out-1): (MAX_AEN_ENTRIES-1)),
+                       mbox_sts[0], mbox_sts[1], mbox_sts[2],
+                       mbox_sts[3], mbox_sts[4]));
 
                switch (mbox_sts[0]) {
                case MBOX_ASTS_DATABASE_CHANGED:
@@ -792,6 +838,5 @@ void qla4xxx_process_aen(struct scsi_qla_host * ha, uint8_t process_aen)
                spin_lock_irqsave(&ha->hardware_lock, flags);
        }
        spin_unlock_irqrestore(&ha->hardware_lock, flags);
-
 }