aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi')
-rw-r--r--drivers/scsi/aic94xx/aic94xx.h1
-rw-r--r--drivers/scsi/aic94xx/aic94xx_init.c2
-rw-r--r--drivers/scsi/aic94xx/aic94xx_tmf.c58
3 files changed, 56 insertions, 5 deletions
diff --git a/drivers/scsi/aic94xx/aic94xx.h b/drivers/scsi/aic94xx/aic94xx.h
index 32f513b1b78a..eb8efdcefe48 100644
--- a/drivers/scsi/aic94xx/aic94xx.h
+++ b/drivers/scsi/aic94xx/aic94xx.h
@@ -102,6 +102,7 @@ int asd_abort_task_set(struct domain_device *, u8 *lun);
102int asd_clear_aca(struct domain_device *, u8 *lun); 102int asd_clear_aca(struct domain_device *, u8 *lun);
103int asd_clear_task_set(struct domain_device *, u8 *lun); 103int asd_clear_task_set(struct domain_device *, u8 *lun);
104int asd_lu_reset(struct domain_device *, u8 *lun); 104int asd_lu_reset(struct domain_device *, u8 *lun);
105int asd_I_T_nexus_reset(struct domain_device *dev);
105int asd_query_task(struct sas_task *); 106int asd_query_task(struct sas_task *);
106 107
107/* ---------- Adapter and Port management ---------- */ 108/* ---------- Adapter and Port management ---------- */
diff --git a/drivers/scsi/aic94xx/aic94xx_init.c b/drivers/scsi/aic94xx/aic94xx_init.c
index 5d761eb67442..88d1e731b65e 100644
--- a/drivers/scsi/aic94xx/aic94xx_init.c
+++ b/drivers/scsi/aic94xx/aic94xx_init.c
@@ -1003,7 +1003,7 @@ static struct sas_domain_function_template aic94xx_transport_functions = {
1003 .lldd_abort_task_set = asd_abort_task_set, 1003 .lldd_abort_task_set = asd_abort_task_set,
1004 .lldd_clear_aca = asd_clear_aca, 1004 .lldd_clear_aca = asd_clear_aca,
1005 .lldd_clear_task_set = asd_clear_task_set, 1005 .lldd_clear_task_set = asd_clear_task_set,
1006 .lldd_I_T_nexus_reset = NULL, 1006 .lldd_I_T_nexus_reset = asd_I_T_nexus_reset,
1007 .lldd_lu_reset = asd_lu_reset, 1007 .lldd_lu_reset = asd_lu_reset,
1008 .lldd_query_task = asd_query_task, 1008 .lldd_query_task = asd_query_task,
1009 1009
diff --git a/drivers/scsi/aic94xx/aic94xx_tmf.c b/drivers/scsi/aic94xx/aic94xx_tmf.c
index 144f5ad20453..d684c7432e63 100644
--- a/drivers/scsi/aic94xx/aic94xx_tmf.c
+++ b/drivers/scsi/aic94xx/aic94xx_tmf.c
@@ -140,8 +140,14 @@ int asd_clear_nexus_port(struct asd_sas_port *port)
140 CLEAR_NEXUS_POST; 140 CLEAR_NEXUS_POST;
141} 141}
142 142
143#if 0 143enum clear_nexus_phase {
144static int asd_clear_nexus_I_T(struct domain_device *dev) 144 NEXUS_PHASE_PRE,
145 NEXUS_PHASE_POST,
146 NEXUS_PHASE_RESUME,
147};
148
149static int asd_clear_nexus_I_T(struct domain_device *dev,
150 enum clear_nexus_phase phase)
145{ 151{
146 struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha; 152 struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha;
147 struct asd_ascb *ascb; 153 struct asd_ascb *ascb;
@@ -150,12 +156,56 @@ static int asd_clear_nexus_I_T(struct domain_device *dev)
150 156
151 CLEAR_NEXUS_PRE; 157 CLEAR_NEXUS_PRE;
152 scb->clear_nexus.nexus = NEXUS_I_T; 158 scb->clear_nexus.nexus = NEXUS_I_T;
153 scb->clear_nexus.flags = SEND_Q | EXEC_Q | NOTINQ; 159 switch (phase) {
160 case NEXUS_PHASE_PRE:
161 scb->clear_nexus.flags = EXEC_Q | SUSPEND_TX;
162 break;
163 case NEXUS_PHASE_POST:
164 scb->clear_nexus.flags = SEND_Q | NOTINQ;
165 break;
166 case NEXUS_PHASE_RESUME:
167 scb->clear_nexus.flags = RESUME_TX;
168 }
154 scb->clear_nexus.conn_handle = cpu_to_le16((u16)(unsigned long) 169 scb->clear_nexus.conn_handle = cpu_to_le16((u16)(unsigned long)
155 dev->lldd_dev); 170 dev->lldd_dev);
156 CLEAR_NEXUS_POST; 171 CLEAR_NEXUS_POST;
157} 172}
158#endif 173
174int asd_I_T_nexus_reset(struct domain_device *dev)
175{
176 int res, tmp_res, i;
177 struct sas_phy *phy = sas_find_local_phy(dev);
178 /* Standard mandates link reset for ATA (type 0) and
179 * hard reset for SSP (type 1) */
180 int reset_type = (dev->dev_type == SATA_DEV ||
181 (dev->tproto & SAS_PROTOCOL_STP)) ? 0 : 1;
182
183 asd_clear_nexus_I_T(dev, NEXUS_PHASE_PRE);
184 /* send a hard reset */
185 ASD_DPRINTK("sending %s reset to %s\n",
186 reset_type ? "hard" : "soft", phy->dev.bus_id);
187 res = sas_phy_reset(phy, reset_type);
188 if (res == TMF_RESP_FUNC_COMPLETE) {
189 /* wait for the maximum settle time */
190 msleep(500);
191 /* clear all outstanding commands (keep nexus suspended) */
192 asd_clear_nexus_I_T(dev, NEXUS_PHASE_POST);
193 }
194 for (i = 0 ; i < 3; i++) {
195 tmp_res = asd_clear_nexus_I_T(dev, NEXUS_PHASE_RESUME);
196 if (tmp_res == TC_RESUME)
197 return res;
198 msleep(500);
199 }
200
201 /* This is a bit of a problem: the sequencer is still suspended
202 * and is refusing to resume. Hope it will resume on a bigger hammer
203 * or the disk is lost */
204 dev_printk(KERN_ERR, &phy->dev,
205 "Failed to resume nexus after reset 0x%x\n", tmp_res);
206
207 return TMF_RESP_FUNC_FAILED;
208}
159 209
160static int asd_clear_nexus_I_T_L(struct domain_device *dev, u8 *lun) 210static int asd_clear_nexus_I_T_L(struct domain_device *dev, u8 *lun)
161{ 211{