vserver 1.9.3
[linux-2.6.git] / drivers / scsi / qla2xxx / qla_iocb.c
index 78a1c57..ebbae60 100644 (file)
  *
  ******************************************************************************/
 
-#include "qla_os.h"
 #include "qla_def.h"
 
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+
+#include <scsi/scsi_tcq.h>
+
 static inline uint16_t qla2x00_get_cmd_direction(struct scsi_cmnd *cmd);
 static inline cont_entry_t *qla2x00_prep_cont_type0_iocb(scsi_qla_host_t *);
 static inline cont_a64_entry_t *qla2x00_prep_cont_type1_iocb(scsi_qla_host_t *);
@@ -42,28 +46,6 @@ qla2x00_get_cmd_direction(struct scsi_cmnd *cmd)
                cflags = CF_WRITE;
        else if (cmd->sc_data_direction == DMA_FROM_DEVICE)
                cflags = CF_READ;
-       else {
-               switch (cmd->data_cmnd[0]) {
-               case WRITE_6:
-               case WRITE_10:
-               case WRITE_12:
-               case WRITE_BUFFER:
-               case WRITE_LONG:
-               case WRITE_SAME:
-               case WRITE_VERIFY:
-               case WRITE_VERIFY_12:
-               case FORMAT_UNIT:
-               case SEND_VOLUME_TAG:
-               case MODE_SELECT:
-               case SEND_DIAGNOSTIC:
-               case MODE_SELECT_10:
-                       cflags = CF_WRITE;
-                       break;
-               default:
-                       cflags = CF_READ;
-                       break;
-               }
-       }
        return (cflags);
 }
 
@@ -124,7 +106,7 @@ qla2x00_prep_cont_type0_iocb(scsi_qla_host_t *ha)
 
        /* Adjust ring index. */
        ha->req_ring_index++;
-       if (ha->req_ring_index == REQUEST_ENTRY_CNT) {
+       if (ha->req_ring_index == ha->request_q_length) {
                ha->req_ring_index = 0;
                ha->request_ring_ptr = ha->request_ring;
        } else {
@@ -153,7 +135,7 @@ qla2x00_prep_cont_type1_iocb(scsi_qla_host_t *ha)
 
        /* Adjust ring index. */
        ha->req_ring_index++;
-       if (ha->req_ring_index == REQUEST_ENTRY_CNT) {
+       if (ha->req_ring_index == ha->request_q_length) {
                ha->req_ring_index = 0;
                ha->request_ring_ptr = ha->request_ring;
        } else {
@@ -350,12 +332,14 @@ qla2x00_start_scsi(srb_t *sp)
        uint32_t        *clr_ptr;
        uint32_t        index;
        uint32_t        handle;
-       uint16_t        cnt;
        cmd_entry_t     *cmd_pkt;
        uint32_t        timeout;
        struct scatterlist *sg;
-
+       uint16_t        cnt;
+       uint16_t        req_cnt;
+       uint16_t        tot_dsds;
        device_reg_t    *reg;
+       char            tag[2];
 
        /* Setup device pointers. */
        ret = 0;
@@ -372,72 +356,60 @@ qla2x00_start_scsi(srb_t *sp)
                ha->marker_needed = 0;
        }
 
-       /* Calculate number of segments and entries required. */
-       if (sp->req_cnt == 0) {
-               sp->tot_dsds = 0;
-               if (cmd->use_sg) {
-                       sg = (struct scatterlist *) cmd->request_buffer;
-                       sp->tot_dsds = pci_map_sg(ha->pdev, sg, cmd->use_sg,
-                           cmd->sc_data_direction);
-               } else if (cmd->request_bufflen) {
-                   sp->tot_dsds++;
-               }
-               sp->req_cnt = (ha->calc_request_entries)(sp->tot_dsds);
-       }
-
        /* Acquire ring specific lock */
        spin_lock_irqsave(&ha->hardware_lock, flags);
 
-       if (ha->req_q_cnt < (sp->req_cnt + 2)) {
-               /* Calculate number of free request entries */
-               cnt = RD_REG_WORD(ISP_REQ_Q_OUT(ha, reg));
-               if (ha->req_ring_index < cnt)
-                       ha->req_q_cnt = cnt - ha->req_ring_index;
-               else
-                       ha->req_q_cnt = REQUEST_ENTRY_CNT -
-                           (ha->req_ring_index - cnt);
-       }
-
-       /* If no room for request in request ring */
-       if (ha->req_q_cnt < (sp->req_cnt + 2)) {
-               DEBUG5(printk("scsi(%ld): in-ptr=%x req_q_cnt=%x "
-                   "tot_dsds=%x.\n",
-                   ha->host_no, ha->req_ring_index, ha->req_q_cnt,
-                   sp->tot_dsds));
-
-               goto queuing_error;
-       }
-
        /* Check for room in outstanding command list. */
        handle = ha->current_outstanding_cmd;
        for (index = 1; index < MAX_OUTSTANDING_COMMANDS; index++) {
                handle++;
                if (handle == MAX_OUTSTANDING_COMMANDS)
                        handle = 1;
-               if (ha->outstanding_cmds[handle] == 0) {
-                       ha->current_outstanding_cmd = handle;
+               if (ha->outstanding_cmds[handle] == 0)
                        break;
-               }
        }
-       if (index == MAX_OUTSTANDING_COMMANDS) {
-               DEBUG5(printk("scsi(%ld): Unable to queue command -- NO ROOM "
-                   "IN OUTSTANDING ARRAY (req_q_cnt=%x).\n",
-                   ha->host_no, ha->req_q_cnt));
+       if (index == MAX_OUTSTANDING_COMMANDS)
+               goto queuing_error;
+
+       /* Calculate the number of request entries needed. */
+       req_cnt = (ha->calc_request_entries)(cmd->request->nr_hw_segments);
+       if (ha->req_q_cnt < (req_cnt + 2)) {
+               cnt = RD_REG_WORD_RELAXED(ISP_REQ_Q_OUT(ha, reg));
+               if (ha->req_ring_index < cnt)
+                       ha->req_q_cnt = cnt - ha->req_ring_index;
+               else
+                       ha->req_q_cnt = ha->request_q_length -
+                           (ha->req_ring_index - cnt);
+       }
+       if (ha->req_q_cnt < (req_cnt + 2))
                goto queuing_error;
+
+       /* Finally, we have enough space, now perform mappings. */
+       tot_dsds = 0;
+       if (cmd->use_sg) {
+               sg = (struct scatterlist *) cmd->request_buffer;
+               tot_dsds = pci_map_sg(ha->pdev, sg, cmd->use_sg,
+                   cmd->sc_data_direction);
+               if (tot_dsds == 0)
+                       goto queuing_error;
+       } else if (cmd->request_bufflen) {
+           tot_dsds++;
        }
+       req_cnt = (ha->calc_request_entries)(tot_dsds);
 
        /* Build command packet */
+       ha->current_outstanding_cmd = handle;
        ha->outstanding_cmds[handle] = sp;
        sp->ha = ha;
        sp->cmd->host_scribble = (unsigned char *)(unsigned long)handle;
-       ha->req_q_cnt -= sp->req_cnt;
+       ha->req_q_cnt -= req_cnt;
 
        cmd_pkt = (cmd_entry_t *)ha->request_ring_ptr;
        cmd_pkt->handle = handle;
        /* Zero out remaining portion of packet. */
        clr_ptr = (uint32_t *)cmd_pkt + 2;
        memset(clr_ptr, 0, REQUEST_ENTRY_SIZE - 8);
-       cmd_pkt->dseg_count = cpu_to_le16(sp->tot_dsds);
+       cmd_pkt->dseg_count = cpu_to_le16(tot_dsds);
 
        /* Set target ID */
        SET_TARGET_ID(ha, cmd_pkt->target, fclun->fcport->loop_id);
@@ -446,14 +418,17 @@ qla2x00_start_scsi(srb_t *sp)
        cmd_pkt->lun = cpu_to_le16(fclun->lun);
 
        /* Update tagged queuing modifier */
-       cmd_pkt->control_flags = __constant_cpu_to_le16(CF_SIMPLE_TAG);
-       if (cmd->device->tagged_supported) {
-               switch (cmd->tag) {
-               case HEAD_OF_QUEUE_TAG:
+       if (scsi_populate_tag_msg(cmd, tag)) {
+               switch (tag[0]) {
+               case MSG_SIMPLE_TAG:
+                       cmd_pkt->control_flags =
+                           __constant_cpu_to_le16(CF_SIMPLE_TAG);
+                       break;
+               case MSG_HEAD_TAG:
                        cmd_pkt->control_flags =
                            __constant_cpu_to_le16(CF_HEAD_TAG);
                        break;
-               case ORDERED_QUEUE_TAG:
+               case MSG_ORDERED_TAG:
                        cmd_pkt->control_flags =
                            __constant_cpu_to_le16(CF_ORDERED_TAG);
                        break;
@@ -477,14 +452,15 @@ qla2x00_start_scsi(srb_t *sp)
        cmd_pkt->byte_count = cpu_to_le32((uint32_t)cmd->request_bufflen);
 
        /* Build IOCB segments */
-       (ha->build_scsi_iocbs)(sp, cmd_pkt, sp->tot_dsds);
+       (ha->build_scsi_iocbs)(sp, cmd_pkt, tot_dsds);
 
        /* Set total data segment count. */
-       cmd_pkt->entry_count = (uint8_t)sp->req_cnt;
+       cmd_pkt->entry_count = (uint8_t)req_cnt;
+       wmb();
 
        /* Adjust ring index. */
        ha->req_ring_index++;
-       if (ha->req_ring_index == REQUEST_ENTRY_CNT) {
+       if (ha->req_ring_index == ha->request_q_length) {
                ha->req_ring_index = 0;
                ha->request_ring_ptr = ha->request_ring;
        } else
@@ -499,7 +475,7 @@ qla2x00_start_scsi(srb_t *sp)
 
        /* Set chip new ring index. */
        WRT_REG_WORD(ISP_REQ_Q_IN(ha, reg), ha->req_ring_index);
-       RD_REG_WORD(ISP_REQ_Q_IN(ha, reg));     /* PCI Posting. */
+       RD_REG_WORD_RELAXED(ISP_REQ_Q_IN(ha, reg));     /* PCI Posting. */
 
        spin_unlock_irqrestore(&ha->hardware_lock, flags);
        return (QLA_SUCCESS);
@@ -541,6 +517,7 @@ __qla2x00_marker(scsi_qla_host_t *ha, uint16_t loop_id, uint16_t lun,
                pkt->lun = cpu_to_le16(lun);
                SET_TARGET_ID(ha, pkt->target, loop_id);
        }
+       wmb();
 
        /* Issue command to ISP */
        qla2x00_isp_cmd(ha);
@@ -588,7 +565,7 @@ qla2x00_req_pkt(scsi_qla_host_t *ha)
                        if  (ha->req_ring_index < cnt)
                                ha->req_q_cnt = cnt - ha->req_ring_index;
                        else
-                               ha->req_q_cnt = REQUEST_ENTRY_CNT -
+                               ha->req_q_cnt = ha->request_q_length -
                                    (ha->req_ring_index - cnt);
                }
                /* If room for request in request ring. */
@@ -658,7 +635,7 @@ qla2x00_ms_req_pkt(scsi_qla_host_t *ha, srb_t  *sp)
                        if (ha->req_ring_index < cnt) {
                                ha->req_q_cnt = cnt - ha->req_ring_index;
                        } else {
-                               ha->req_q_cnt = REQUEST_ENTRY_CNT -
+                               ha->req_q_cnt = ha->request_q_length -
                                    (ha->req_ring_index - cnt);
                        }
                }
@@ -740,7 +717,7 @@ qla2x00_isp_cmd(scsi_qla_host_t *ha)
 
        /* Adjust ring index. */
        ha->req_ring_index++;
-       if (ha->req_ring_index == REQUEST_ENTRY_CNT) {
+       if (ha->req_ring_index == ha->request_q_length) {
                ha->req_ring_index = 0;
                ha->request_ring_ptr = ha->request_ring;
        } else
@@ -748,5 +725,5 @@ qla2x00_isp_cmd(scsi_qla_host_t *ha)
 
        /* Set chip new ring index. */
        WRT_REG_WORD(ISP_REQ_Q_IN(ha, reg), ha->req_ring_index);
-       RD_REG_WORD(ISP_REQ_Q_IN(ha, reg));     /* PCI Posting. */
+       RD_REG_WORD_RELAXED(ISP_REQ_Q_IN(ha, reg));     /* PCI Posting. */
 }