[SCSI] mvsas: misc improvements
[linux-2.6.git] / drivers / scsi / mvsas / mv_sas.c
index 38b4791..31ca8fe 100644 (file)
@@ -300,7 +300,10 @@ int mvs_slave_configure(struct scsi_device *sdev)
 
        if (ret)
                return ret;
-       if (dev_is_sata(dev)) {
+       if (!dev_is_sata(dev)) {
+               sas_change_queue_depth(sdev,
+                       MVS_QUEUE_SIZE,
+                       SCSI_QDEPTH_DEFAULT);
        }
        return 0;
 }
@@ -311,6 +314,7 @@ void mvs_scan_start(struct Scsi_Host *shost)
        unsigned short core_nr;
        struct mvs_info *mvi;
        struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
+       struct mvs_prv_info *mvs_prv = sha->lldd_ha;
 
        core_nr = ((struct mvs_prv_info *)sha->lldd_ha)->n_host;
 
@@ -319,15 +323,17 @@ void mvs_scan_start(struct Scsi_Host *shost)
                for (i = 0; i < mvi->chip->n_phy; ++i)
                        mvs_bytes_dmaed(mvi, i);
        }
+       mvs_prv->scan_finished = 1;
 }
 
 int mvs_scan_finished(struct Scsi_Host *shost, unsigned long time)
 {
-       /* give the phy enabling interrupt event time to come in (1s
-        * is empirically about all it takes) */
-       if (time < HZ)
+       struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
+       struct mvs_prv_info *mvs_prv = sha->lldd_ha;
+
+       if (mvs_prv->scan_finished == 0)
                return 0;
-       /* Wait for discovery to finish */
+
        scsi_flush_work(shost);
        return 1;
 }
@@ -625,6 +631,9 @@ static int mvs_task_prep_ssp(struct mvs_info *mvi,
        }
        if (is_tmf)
                flags |= (MCH_SSP_FR_TASK << MCH_SSP_FR_TYPE_SHIFT);
+       else
+               flags |= (MCH_SSP_FR_CMD << MCH_SSP_FR_TYPE_SHIFT);
+
        hdr->flags = cpu_to_le32(flags | (tei->n_elem << MCH_PRD_LEN_SHIFT));
        hdr->tags = cpu_to_le32(tag);
        hdr->data_len = cpu_to_le32(task->total_xfer_len);
@@ -1049,9 +1058,9 @@ static void mvs_slot_task_free(struct mvs_info *mvi, struct sas_task *task,
        mvs_slot_free(mvi, slot_idx);
 }
 
-static void mvs_update_wideport(struct mvs_info *mvi, int i)
+static void mvs_update_wideport(struct mvs_info *mvi, int phy_no)
 {
-       struct mvs_phy *phy = &mvi->phy[i];
+       struct mvs_phy *phy = &mvi->phy[phy_no];
        struct mvs_port *port = phy->port;
        int j, no;
 
@@ -1106,16 +1115,16 @@ static void *mvs_get_d2h_reg(struct mvs_info *mvi, int i, void *buf)
                return NULL;
 
        MVS_CHIP_DISP->write_port_cfg_addr(mvi, i, PHYR_SATA_SIG3);
-       s[3] = MVS_CHIP_DISP->read_port_cfg_data(mvi, i);
+       s[3] = cpu_to_le32(MVS_CHIP_DISP->read_port_cfg_data(mvi, i));
 
        MVS_CHIP_DISP->write_port_cfg_addr(mvi, i, PHYR_SATA_SIG2);
-       s[2] = MVS_CHIP_DISP->read_port_cfg_data(mvi, i);
+       s[2] = cpu_to_le32(MVS_CHIP_DISP->read_port_cfg_data(mvi, i));
 
        MVS_CHIP_DISP->write_port_cfg_addr(mvi, i, PHYR_SATA_SIG1);
-       s[1] = MVS_CHIP_DISP->read_port_cfg_data(mvi, i);
+       s[1] = cpu_to_le32(MVS_CHIP_DISP->read_port_cfg_data(mvi, i));
 
        MVS_CHIP_DISP->write_port_cfg_addr(mvi, i, PHYR_SATA_SIG0);
-       s[0] = MVS_CHIP_DISP->read_port_cfg_data(mvi, i);
+       s[0] = cpu_to_le32(MVS_CHIP_DISP->read_port_cfg_data(mvi, i));
 
        /* Workaround: take some ATAPI devices for ATA */
        if (((s[1] & 0x00FFFFFF) == 0x00EB1401) && (*(u8 *)&s[3] == 0x01))
@@ -1201,9 +1210,9 @@ void mvs_update_phyinfo(struct mvs_info *mvi, int i, int get_st)
                if (MVS_CHIP_DISP->phy_work_around)
                        MVS_CHIP_DISP->phy_work_around(mvi, i);
        }
-       mv_dprintk("port %d attach dev info is %x\n",
+       mv_dprintk("phy %d attach dev info is %x\n",
                i + mvi->id * mvi->chip->n_phy, phy->att_dev_info);
-       mv_dprintk("port %d attach sas addr is %llx\n",
+       mv_dprintk("phy %d attach sas addr is %llx\n",
                i + mvi->id * mvi->chip->n_phy, phy->att_dev_sas_addr);
 out_done:
        if (get_st)
@@ -1228,10 +1237,10 @@ static void mvs_port_notify_formed(struct asd_sas_phy *sas_phy, int lock)
        }
        hi = i/((struct mvs_prv_info *)sas_ha->lldd_ha)->n_phy;
        mvi = ((struct mvs_prv_info *)sas_ha->lldd_ha)->mvi[hi];
-       if (sas_port->id >= mvi->chip->n_phy)
-               port = &mvi->port[sas_port->id - mvi->chip->n_phy];
+       if (i >= mvi->chip->n_phy)
+               port = &mvi->port[i - mvi->chip->n_phy];
        else
-               port = &mvi->port[sas_port->id];
+               port = &mvi->port[i];
        if (lock)
                spin_lock_irqsave(&mvi->lock, flags);
        port->port_attached = 1;
@@ -1260,7 +1269,7 @@ static void mvs_port_notify_deformed(struct asd_sas_phy *sas_phy, int lock)
                        return;
        }
        list_for_each_entry(dev, &port->dev_list, dev_list_node)
-               mvs_do_release_task(phy->mvi, phy_no, NULL);
+               mvs_do_release_task(phy->mvi, phy_no, dev);
 
 }
 
@@ -1324,6 +1333,7 @@ int mvs_dev_found_notify(struct domain_device *dev, int lock)
        mvi_device->dev_status = MVS_DEV_NORMAL;
        mvi_device->dev_type = dev->dev_type;
        mvi_device->mvi_info = mvi;
+       mvi_device->sas_device = dev;
        if (parent_dev && DEV_IS_EXPANDER(parent_dev->dev_type)) {
                int phy_id;
                u8 phy_num = parent_dev->ex_dev.num_phys;
@@ -1375,6 +1385,7 @@ void mvs_dev_gone_notify(struct domain_device *dev)
                mv_dprintk("found dev has gone.\n");
        }
        dev->lldd_dev = NULL;
+       mvi_dev->sas_device = NULL;
 
        spin_unlock_irqrestore(&mvi->lock, flags);
 }
@@ -1455,7 +1466,7 @@ static int mvs_exec_internal_tmf_task(struct domain_device *dev,
                }
 
                wait_for_completion(&task->completion);
-               res = -TMF_RESP_FUNC_FAILED;
+               res = TMF_RESP_FUNC_FAILED;
                /* Even TMF timed out, return direct. */
                if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) {
                        if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) {
@@ -1505,11 +1516,10 @@ static int mvs_debug_issue_ssp_tmf(struct domain_device *dev,
                                u8 *lun, struct mvs_tmf_task *tmf)
 {
        struct sas_ssp_task ssp_task;
-       DECLARE_COMPLETION_ONSTACK(completion);
        if (!(dev->tproto & SAS_PROTOCOL_SSP))
                return TMF_RESP_FUNC_ESUPP;
 
-       strncpy((u8 *)&ssp_task.LUN, lun, 8);
+       memcpy(ssp_task.LUN, lun, 8);
 
        return mvs_exec_internal_tmf_task(dev, &ssp_task,
                                sizeof(ssp_task), tmf);
@@ -1533,7 +1543,7 @@ static int mvs_debug_I_T_nexus_reset(struct domain_device *dev)
 int mvs_lu_reset(struct domain_device *dev, u8 *lun)
 {
        unsigned long flags;
-       int i, phyno[WIDE_PORT_MAX_PHY], num , rc = TMF_RESP_FUNC_FAILED;
+       int rc = TMF_RESP_FUNC_FAILED;
        struct mvs_tmf_task tmf_task;
        struct mvs_device * mvi_dev = dev->lldd_dev;
        struct mvs_info *mvi = mvi_dev->mvi_info;
@@ -1542,10 +1552,8 @@ int mvs_lu_reset(struct domain_device *dev, u8 *lun)
        mvi_dev->dev_status = MVS_DEV_EH;
        rc = mvs_debug_issue_ssp_tmf(dev, lun, &tmf_task);
        if (rc == TMF_RESP_FUNC_COMPLETE) {
-               num = mvs_find_dev_phyno(dev, phyno);
                spin_lock_irqsave(&mvi->lock, flags);
-               for (i = 0; i < num; i++)
-                       mvs_release_task(mvi, dev);
+               mvs_release_task(mvi, dev);
                spin_unlock_irqrestore(&mvi->lock, flags);
        }
        /* If failed, fall-through I_T_Nexus reset */
@@ -1563,6 +1571,8 @@ int mvs_I_T_nexus_reset(struct domain_device *dev)
 
        if (mvi_dev->dev_status != MVS_DEV_EH)
                return TMF_RESP_FUNC_COMPLETE;
+       else
+               mvi_dev->dev_status = MVS_DEV_NORMAL;
        rc = mvs_debug_I_T_nexus_reset(dev);
        mv_printk("%s for device[%x]:rc= %d\n",
                __func__, mvi_dev->device_id, rc);
@@ -1606,9 +1616,6 @@ int mvs_query_task(struct sas_task *task)
                case TMF_RESP_FUNC_FAILED:
                case TMF_RESP_FUNC_COMPLETE:
                        break;
-               default:
-                       rc = TMF_RESP_FUNC_COMPLETE;
-                       break;
                }
        }
        mv_printk("%s:rc= %d\n", __func__, rc);
@@ -1628,8 +1635,8 @@ int mvs_abort_task(struct sas_task *task)
        u32 tag;
 
        if (!mvi_dev) {
-               mv_printk("%s:%d TMF_RESP_FUNC_FAILED\n", __func__, __LINE__);
-               rc = TMF_RESP_FUNC_FAILED;
+               mv_printk("Device has removed\n");
+               return TMF_RESP_FUNC_FAILED;
        }
 
        mvi = mvi_dev->mvi_info;
@@ -1677,22 +1684,15 @@ int mvs_abort_task(struct sas_task *task)
                /* to do free register_set */
                if (SATA_DEV == dev->dev_type) {
                        struct mvs_slot_info *slot = task->lldd_task;
-                       struct task_status_struct *tstat;
                        u32 slot_idx = (u32)(slot - mvi->slot_info);
-                       tstat = &task->task_status;
-                       mv_dprintk(KERN_DEBUG "mv_abort_task() mvi=%p task=%p "
+                       mv_dprintk("mvs_abort_task() mvi=%p task=%p "
                                   "slot=%p slot_idx=x%x\n",
                                   mvi, task, slot, slot_idx);
-                       tstat->stat = SAS_ABORTED_TASK;
-                       if (mvi_dev && mvi_dev->running_req)
-                               mvi_dev->running_req--;
-                       if (sas_protocol_ata(task->task_proto))
-                               mvs_free_reg_set(mvi, mvi_dev);
+                       mvs_tmf_timedout((unsigned long)task);
                        mvs_slot_task_free(mvi, task, slot, slot_idx);
-                       return -1;
+                       rc = TMF_RESP_FUNC_COMPLETE;
+                       goto out;
                }
-       } else {
-               /* SMP */
 
        }
 out:
@@ -1813,7 +1813,7 @@ static int mvs_slot_err(struct mvs_info *mvi, struct sas_task *task,
 {
        struct mvs_slot_info *slot = &mvi->slot_info[slot_idx];
        int stat;
-       u32 err_dw0 = le32_to_cpu(*(u32 *) (slot->response));
+       u32 err_dw0 = le32_to_cpu(*(u32 *)slot->response);
        u32 err_dw1 = le32_to_cpu(*((u32 *)slot->response + 1));
        u32 tfs = 0;
        enum mvs_port_type type = PORT_TYPE_SAS;
@@ -1847,10 +1847,8 @@ static int mvs_slot_err(struct mvs_info *mvi, struct sas_task *task,
        case SAS_PROTOCOL_STP:
        case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:
        {
-               if (err_dw0 == 0x80400002)
-                       mv_printk("find reserved error, why?\n");
-
                task->ata_task.use_ncq = 0;
+               stat = SAS_PROTO_RESPONSE;
                mvs_sata_done(mvi, task, slot_idx, err_dw0);
        }
                break;
@@ -1912,6 +1910,9 @@ int mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc, u32 flags)
 
        /* error info record present */
        if (unlikely((rx_desc & RXQ_ERR) && (*(u64 *) slot->response))) {
+               mv_dprintk("port %d slot %d rx_desc %X has error info"
+                       "%016llX.\n", slot->port->sas_port.id, slot_idx,
+                        rx_desc, (u64)(*(u64 *)slot->response));
                tstat->stat = mvs_slot_err(mvi, task, slot_idx);
                tstat->resp = SAS_TASK_COMPLETE;
                goto out;
@@ -1973,8 +1974,7 @@ out:
        spin_unlock(&mvi->lock);
        if (task->task_done)
                task->task_done(task);
-       else
-               mv_dprintk("why has not task_done.\n");
+
        spin_lock(&mvi->lock);
 
        return sts;
@@ -2115,9 +2115,10 @@ void mvs_int_port(struct mvs_info *mvi, int phy_no, u32 events)
        struct mvs_phy *phy = &mvi->phy[phy_no];
 
        phy->irq_status = MVS_CHIP_DISP->read_port_irq_stat(mvi, phy_no);
-       mv_dprintk("port %d ctrl sts=0x%X.\n", phy_no+mvi->id*mvi->chip->n_phy,
+       MVS_CHIP_DISP->write_port_irq_stat(mvi, phy_no, phy->irq_status);
+       mv_dprintk("phy %d ctrl sts=0x%08X.\n", phy_no+mvi->id*mvi->chip->n_phy,
                MVS_CHIP_DISP->read_phy_ctl(mvi, phy_no));
-       mv_dprintk("Port %d irq sts = 0x%X\n", phy_no+mvi->id*mvi->chip->n_phy,
+       mv_dprintk("phy %d irq sts = 0x%08X\n", phy_no+mvi->id*mvi->chip->n_phy,
                phy->irq_status);
 
        /*
@@ -2126,11 +2127,12 @@ void mvs_int_port(struct mvs_info *mvi, int phy_no, u32 events)
        */
 
        if (phy->irq_status & PHYEV_DCDR_ERR) {
-               mv_dprintk("port %d STP decoding error.\n",
+               mv_dprintk("phy %d STP decoding error.\n",
                phy_no + mvi->id*mvi->chip->n_phy);
        }
 
        if (phy->irq_status & PHYEV_POOF) {
+               mdelay(500);
                if (!(phy->phy_event & PHY_PLUG_OUT)) {
                        int dev_sata = phy->phy_type & PORT_TYPE_SATA;
                        int ready;
@@ -2141,10 +2143,6 @@ void mvs_int_port(struct mvs_info *mvi, int phy_no, u32 events)
                                (void *)(unsigned long)phy_no,
                                PHY_PLUG_EVENT);
                        ready = mvs_is_phy_ready(mvi, phy_no);
-                       if (!ready)
-                               mv_dprintk("phy%d Unplug Notice\n",
-                                       phy_no +
-                                       mvi->id * mvi->chip->n_phy);
                        if (ready || dev_sata) {
                                if (MVS_CHIP_DISP->stp_reset)
                                        MVS_CHIP_DISP->stp_reset(mvi,
@@ -2164,7 +2162,7 @@ void mvs_int_port(struct mvs_info *mvi, int phy_no, u32 events)
                if (phy->timer.function == NULL) {
                        phy->timer.data = (unsigned long)phy;
                        phy->timer.function = mvs_sig_time_out;
-                       phy->timer.expires = jiffies + 10*HZ;
+                       phy->timer.expires = jiffies + 5*HZ;
                        add_timer(&phy->timer);
                }
        }
@@ -2198,12 +2196,11 @@ void mvs_int_port(struct mvs_info *mvi, int phy_no, u32 events)
                                phy_no + mvi->id*mvi->chip->n_phy);
                }
        } else if (phy->irq_status & PHYEV_BROAD_CH) {
-               mv_dprintk("port %d broadcast change.\n",
+               mv_dprintk("phy %d broadcast change.\n",
                        phy_no + mvi->id*mvi->chip->n_phy);
                mvs_handle_event(mvi, (void *)(unsigned long)phy_no,
                                EXP_BRCT_CHG);
        }
-       MVS_CHIP_DISP->write_port_irq_stat(mvi, phy_no, phy->irq_status);
 }
 
 int mvs_int_rx(struct mvs_info *mvi, bool self_clear)