aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/libsas
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/libsas')
-rw-r--r--drivers/scsi/libsas/Kconfig9
-rw-r--r--drivers/scsi/libsas/Makefile4
-rw-r--r--drivers/scsi/libsas/sas_ata.c2
-rw-r--r--drivers/scsi/libsas/sas_discover.c2
-rw-r--r--drivers/scsi/libsas/sas_expander.c35
-rw-r--r--drivers/scsi/libsas/sas_host_smp.c274
-rw-r--r--drivers/scsi/libsas/sas_internal.h16
-rw-r--r--drivers/scsi/libsas/sas_scsi_host.c9
-rw-r--r--drivers/scsi/libsas/sas_task.c36
9 files changed, 371 insertions, 16 deletions
diff --git a/drivers/scsi/libsas/Kconfig b/drivers/scsi/libsas/Kconfig
index c01a40d321d4..18f33cd54411 100644
--- a/drivers/scsi/libsas/Kconfig
+++ b/drivers/scsi/libsas/Kconfig
@@ -38,6 +38,15 @@ config SCSI_SAS_ATA
38 Builds in ATA support into libsas. Will necessitate 38 Builds in ATA support into libsas. Will necessitate
39 the loading of libata along with libsas. 39 the loading of libata along with libsas.
40 40
41config SCSI_SAS_HOST_SMP
42 bool "Support for SMP interpretation for SAS hosts"
43 default y
44 depends on SCSI_SAS_LIBSAS
45 help
46 Allows sas hosts to receive SMP frames. Selecting this
47 option builds an SMP interpreter into libsas. Say
48 N here if you want to save the few kb this consumes.
49
41config SCSI_SAS_LIBSAS_DEBUG 50config SCSI_SAS_LIBSAS_DEBUG
42 bool "Compile the SAS Domain Transport Attributes in debug mode" 51 bool "Compile the SAS Domain Transport Attributes in debug mode"
43 default y 52 default y
diff --git a/drivers/scsi/libsas/Makefile b/drivers/scsi/libsas/Makefile
index fd387b91856e..1ad1323c60fa 100644
--- a/drivers/scsi/libsas/Makefile
+++ b/drivers/scsi/libsas/Makefile
@@ -33,5 +33,7 @@ libsas-y += sas_init.o \
33 sas_dump.o \ 33 sas_dump.o \
34 sas_discover.o \ 34 sas_discover.o \
35 sas_expander.o \ 35 sas_expander.o \
36 sas_scsi_host.o 36 sas_scsi_host.o \
37 sas_task.o
37libsas-$(CONFIG_SCSI_SAS_ATA) += sas_ata.o 38libsas-$(CONFIG_SCSI_SAS_ATA) += sas_ata.o
39libsas-$(CONFIG_SCSI_SAS_HOST_SMP) += sas_host_smp.o \ No newline at end of file
diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c
index 827cfb132f21..0996f866f14c 100644
--- a/drivers/scsi/libsas/sas_ata.c
+++ b/drivers/scsi/libsas/sas_ata.c
@@ -498,7 +498,7 @@ static int sas_execute_task(struct sas_task *task, void *buffer, int size,
498 goto ex_err; 498 goto ex_err;
499 } 499 }
500 wait_for_completion(&task->completion); 500 wait_for_completion(&task->completion);
501 res = -ETASK; 501 res = -ECOMM;
502 if (task->task_state_flags & SAS_TASK_STATE_ABORTED) { 502 if (task->task_state_flags & SAS_TASK_STATE_ABORTED) {
503 int res2; 503 int res2;
504 SAS_DPRINTK("task aborted, flags:0x%x\n", 504 SAS_DPRINTK("task aborted, flags:0x%x\n",
diff --git a/drivers/scsi/libsas/sas_discover.c b/drivers/scsi/libsas/sas_discover.c
index 5f3a0d7b18de..31b9af224243 100644
--- a/drivers/scsi/libsas/sas_discover.c
+++ b/drivers/scsi/libsas/sas_discover.c
@@ -98,7 +98,7 @@ static int sas_get_port_device(struct asd_sas_port *port)
98 dev->dev_type = SATA_PM; 98 dev->dev_type = SATA_PM;
99 else 99 else
100 dev->dev_type = SATA_DEV; 100 dev->dev_type = SATA_DEV;
101 dev->tproto = SATA_PROTO; 101 dev->tproto = SAS_PROTOCOL_SATA;
102 } else { 102 } else {
103 struct sas_identify_frame *id = 103 struct sas_identify_frame *id =
104 (struct sas_identify_frame *) dev->frame_rcvd; 104 (struct sas_identify_frame *) dev->frame_rcvd;
diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c
index 8727436b222d..aefd865a5788 100644
--- a/drivers/scsi/libsas/sas_expander.c
+++ b/drivers/scsi/libsas/sas_expander.c
@@ -96,7 +96,7 @@ static int smp_execute_task(struct domain_device *dev, void *req, int req_size,
96 } 96 }
97 97
98 wait_for_completion(&task->completion); 98 wait_for_completion(&task->completion);
99 res = -ETASK; 99 res = -ECOMM;
100 if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) { 100 if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) {
101 SAS_DPRINTK("smp task timed out or aborted\n"); 101 SAS_DPRINTK("smp task timed out or aborted\n");
102 i->dft->lldd_abort_task(task); 102 i->dft->lldd_abort_task(task);
@@ -109,6 +109,16 @@ static int smp_execute_task(struct domain_device *dev, void *req, int req_size,
109 task->task_status.stat == SAM_GOOD) { 109 task->task_status.stat == SAM_GOOD) {
110 res = 0; 110 res = 0;
111 break; 111 break;
112 } if (task->task_status.resp == SAS_TASK_COMPLETE &&
113 task->task_status.stat == SAS_DATA_UNDERRUN) {
114 /* no error, but return the number of bytes of
115 * underrun */
116 res = task->task_status.residual;
117 break;
118 } if (task->task_status.resp == SAS_TASK_COMPLETE &&
119 task->task_status.stat == SAS_DATA_OVERRUN) {
120 res = -EMSGSIZE;
121 break;
112 } else { 122 } else {
113 SAS_DPRINTK("%s: task to dev %016llx response: 0x%x " 123 SAS_DPRINTK("%s: task to dev %016llx response: 0x%x "
114 "status 0x%x\n", __FUNCTION__, 124 "status 0x%x\n", __FUNCTION__,
@@ -656,9 +666,9 @@ static struct domain_device *sas_ex_discover_end_dev(
656 sas_ex_get_linkrate(parent, child, phy); 666 sas_ex_get_linkrate(parent, child, phy);
657 667
658#ifdef CONFIG_SCSI_SAS_ATA 668#ifdef CONFIG_SCSI_SAS_ATA
659 if ((phy->attached_tproto & SAS_PROTO_STP) || phy->attached_sata_dev) { 669 if ((phy->attached_tproto & SAS_PROTOCOL_STP) || phy->attached_sata_dev) {
660 child->dev_type = SATA_DEV; 670 child->dev_type = SATA_DEV;
661 if (phy->attached_tproto & SAS_PROTO_STP) 671 if (phy->attached_tproto & SAS_PROTOCOL_STP)
662 child->tproto = phy->attached_tproto; 672 child->tproto = phy->attached_tproto;
663 if (phy->attached_sata_dev) 673 if (phy->attached_sata_dev)
664 child->tproto |= SATA_DEV; 674 child->tproto |= SATA_DEV;
@@ -695,7 +705,7 @@ static struct domain_device *sas_ex_discover_end_dev(
695 } 705 }
696 } else 706 } else
697#endif 707#endif
698 if (phy->attached_tproto & SAS_PROTO_SSP) { 708 if (phy->attached_tproto & SAS_PROTOCOL_SSP) {
699 child->dev_type = SAS_END_DEV; 709 child->dev_type = SAS_END_DEV;
700 rphy = sas_end_device_alloc(phy->port); 710 rphy = sas_end_device_alloc(phy->port);
701 /* FIXME: error handling */ 711 /* FIXME: error handling */
@@ -1896,11 +1906,9 @@ int sas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
1896 } 1906 }
1897 1907
1898 /* no rphy means no smp target support (ie aic94xx host) */ 1908 /* no rphy means no smp target support (ie aic94xx host) */
1899 if (!rphy) { 1909 if (!rphy)
1900 printk("%s: can we send a smp request to a host?\n", 1910 return sas_smp_host_handler(shost, req, rsp);
1901 __FUNCTION__); 1911
1902 return -EINVAL;
1903 }
1904 type = rphy->identify.device_type; 1912 type = rphy->identify.device_type;
1905 1913
1906 if (type != SAS_EDGE_EXPANDER_DEVICE && 1914 if (type != SAS_EDGE_EXPANDER_DEVICE &&
@@ -1926,6 +1934,15 @@ int sas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
1926 1934
1927 ret = smp_execute_task(dev, bio_data(req->bio), req->data_len, 1935 ret = smp_execute_task(dev, bio_data(req->bio), req->data_len,
1928 bio_data(rsp->bio), rsp->data_len); 1936 bio_data(rsp->bio), rsp->data_len);
1937 if (ret > 0) {
1938 /* positive number is the untransferred residual */
1939 rsp->data_len = ret;
1940 req->data_len = 0;
1941 ret = 0;
1942 } else if (ret == 0) {
1943 rsp->data_len = 0;
1944 req->data_len = 0;
1945 }
1929 1946
1930 return ret; 1947 return ret;
1931} 1948}
diff --git a/drivers/scsi/libsas/sas_host_smp.c b/drivers/scsi/libsas/sas_host_smp.c
new file mode 100644
index 000000000000..16f93123271e
--- /dev/null
+++ b/drivers/scsi/libsas/sas_host_smp.c
@@ -0,0 +1,274 @@
1/*
2 * Serial Attached SCSI (SAS) Expander discovery and configuration
3 *
4 * Copyright (C) 2007 James E.J. Bottomley
5 * <James.Bottomley@HansenPartnership.com>
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; version 2 only.
10 */
11#include <linux/scatterlist.h>
12#include <linux/blkdev.h>
13
14#include "sas_internal.h"
15
16#include <scsi/scsi_transport.h>
17#include <scsi/scsi_transport_sas.h>
18#include "../scsi_sas_internal.h"
19
20static void sas_host_smp_discover(struct sas_ha_struct *sas_ha, u8 *resp_data,
21 u8 phy_id)
22{
23 struct sas_phy *phy;
24 struct sas_rphy *rphy;
25
26 if (phy_id >= sas_ha->num_phys) {
27 resp_data[2] = SMP_RESP_NO_PHY;
28 return;
29 }
30 resp_data[2] = SMP_RESP_FUNC_ACC;
31
32 phy = sas_ha->sas_phy[phy_id]->phy;
33 resp_data[9] = phy_id;
34 resp_data[13] = phy->negotiated_linkrate;
35 memcpy(resp_data + 16, sas_ha->sas_addr, SAS_ADDR_SIZE);
36 memcpy(resp_data + 24, sas_ha->sas_phy[phy_id]->attached_sas_addr,
37 SAS_ADDR_SIZE);
38 resp_data[40] = (phy->minimum_linkrate << 4) |
39 phy->minimum_linkrate_hw;
40 resp_data[41] = (phy->maximum_linkrate << 4) |
41 phy->maximum_linkrate_hw;
42
43 if (!sas_ha->sas_phy[phy_id]->port ||
44 !sas_ha->sas_phy[phy_id]->port->port_dev)
45 return;
46
47 rphy = sas_ha->sas_phy[phy_id]->port->port_dev->rphy;
48 resp_data[12] = rphy->identify.device_type << 4;
49 resp_data[14] = rphy->identify.initiator_port_protocols;
50 resp_data[15] = rphy->identify.target_port_protocols;
51}
52
53static void sas_report_phy_sata(struct sas_ha_struct *sas_ha, u8 *resp_data,
54 u8 phy_id)
55{
56 struct sas_rphy *rphy;
57 struct dev_to_host_fis *fis;
58 int i;
59
60 if (phy_id >= sas_ha->num_phys) {
61 resp_data[2] = SMP_RESP_NO_PHY;
62 return;
63 }
64
65 resp_data[2] = SMP_RESP_PHY_NO_SATA;
66
67 if (!sas_ha->sas_phy[phy_id]->port)
68 return;
69
70 rphy = sas_ha->sas_phy[phy_id]->port->port_dev->rphy;
71 fis = (struct dev_to_host_fis *)
72 sas_ha->sas_phy[phy_id]->port->port_dev->frame_rcvd;
73 if (rphy->identify.target_port_protocols != SAS_PROTOCOL_SATA)
74 return;
75
76 resp_data[2] = SMP_RESP_FUNC_ACC;
77 resp_data[9] = phy_id;
78 memcpy(resp_data + 16, sas_ha->sas_phy[phy_id]->attached_sas_addr,
79 SAS_ADDR_SIZE);
80
81 /* check to see if we have a valid d2h fis */
82 if (fis->fis_type != 0x34)
83 return;
84
85 /* the d2h fis is required by the standard to be in LE format */
86 for (i = 0; i < 20; i += 4) {
87 u8 *dst = resp_data + 24 + i, *src =
88 &sas_ha->sas_phy[phy_id]->port->port_dev->frame_rcvd[i];
89 dst[0] = src[3];
90 dst[1] = src[2];
91 dst[2] = src[1];
92 dst[3] = src[0];
93 }
94}
95
96static void sas_phy_control(struct sas_ha_struct *sas_ha, u8 phy_id,
97 u8 phy_op, enum sas_linkrate min,
98 enum sas_linkrate max, u8 *resp_data)
99{
100 struct sas_internal *i =
101 to_sas_internal(sas_ha->core.shost->transportt);
102 struct sas_phy_linkrates rates;
103
104 if (phy_id >= sas_ha->num_phys) {
105 resp_data[2] = SMP_RESP_NO_PHY;
106 return;
107 }
108 switch (phy_op) {
109 case PHY_FUNC_NOP:
110 case PHY_FUNC_LINK_RESET:
111 case PHY_FUNC_HARD_RESET:
112 case PHY_FUNC_DISABLE:
113 case PHY_FUNC_CLEAR_ERROR_LOG:
114 case PHY_FUNC_CLEAR_AFFIL:
115 case PHY_FUNC_TX_SATA_PS_SIGNAL:
116 break;
117
118 default:
119 resp_data[2] = SMP_RESP_PHY_UNK_OP;
120 return;
121 }
122
123 rates.minimum_linkrate = min;
124 rates.maximum_linkrate = max;
125
126 if (i->dft->lldd_control_phy(sas_ha->sas_phy[phy_id], phy_op, &rates))
127 resp_data[2] = SMP_RESP_FUNC_FAILED;
128 else
129 resp_data[2] = SMP_RESP_FUNC_ACC;
130}
131
132int sas_smp_host_handler(struct Scsi_Host *shost, struct request *req,
133 struct request *rsp)
134{
135 u8 *req_data = NULL, *resp_data = NULL, *buf;
136 struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(shost);
137 int error = -EINVAL, resp_data_len = rsp->data_len;
138
139 /* eight is the minimum size for request and response frames */
140 if (req->data_len < 8 || rsp->data_len < 8)
141 goto out;
142
143 if (bio_offset(req->bio) + req->data_len > PAGE_SIZE ||
144 bio_offset(rsp->bio) + rsp->data_len > PAGE_SIZE) {
145 shost_printk(KERN_ERR, shost,
146 "SMP request/response frame crosses page boundary");
147 goto out;
148 }
149
150 req_data = kzalloc(req->data_len, GFP_KERNEL);
151
152 /* make sure frame can always be built ... we copy
153 * back only the requested length */
154 resp_data = kzalloc(max(rsp->data_len, 128U), GFP_KERNEL);
155
156 if (!req_data || !resp_data) {
157 error = -ENOMEM;
158 goto out;
159 }
160
161 local_irq_disable();
162 buf = kmap_atomic(bio_page(req->bio), KM_USER0) + bio_offset(req->bio);
163 memcpy(req_data, buf, req->data_len);
164 kunmap_atomic(buf - bio_offset(req->bio), KM_USER0);
165 local_irq_enable();
166
167 if (req_data[0] != SMP_REQUEST)
168 goto out;
169
170 /* always succeeds ... even if we can't process the request
171 * the result is in the response frame */
172 error = 0;
173
174 /* set up default don't know response */
175 resp_data[0] = SMP_RESPONSE;
176 resp_data[1] = req_data[1];
177 resp_data[2] = SMP_RESP_FUNC_UNK;
178
179 switch (req_data[1]) {
180 case SMP_REPORT_GENERAL:
181 req->data_len -= 8;
182 resp_data_len -= 32;
183 resp_data[2] = SMP_RESP_FUNC_ACC;
184 resp_data[9] = sas_ha->num_phys;
185 break;
186
187 case SMP_REPORT_MANUF_INFO:
188 req->data_len -= 8;
189 resp_data_len -= 64;
190 resp_data[2] = SMP_RESP_FUNC_ACC;
191 memcpy(resp_data + 12, shost->hostt->name,
192 SAS_EXPANDER_VENDOR_ID_LEN);
193 memcpy(resp_data + 20, "libsas virt phy",
194 SAS_EXPANDER_PRODUCT_ID_LEN);
195 break;
196
197 case SMP_READ_GPIO_REG:
198 /* FIXME: need GPIO support in the transport class */
199 break;
200
201 case SMP_DISCOVER:
202 req->data_len =- 16;
203 if (req->data_len < 0) {
204 req->data_len = 0;
205 error = -EINVAL;
206 goto out;
207 }
208 resp_data_len -= 56;
209 sas_host_smp_discover(sas_ha, resp_data, req_data[9]);
210 break;
211
212 case SMP_REPORT_PHY_ERR_LOG:
213 /* FIXME: could implement this with additional
214 * libsas callbacks providing the HW supports it */
215 break;
216
217 case SMP_REPORT_PHY_SATA:
218 req->data_len =- 16;
219 if (req->data_len < 0) {
220 req->data_len = 0;
221 error = -EINVAL;
222 goto out;
223 }
224 resp_data_len -= 60;
225 sas_report_phy_sata(sas_ha, resp_data, req_data[9]);
226 break;
227
228 case SMP_REPORT_ROUTE_INFO:
229 /* Can't implement; hosts have no routes */
230 break;
231
232 case SMP_WRITE_GPIO_REG:
233 /* FIXME: need GPIO support in the transport class */
234 break;
235
236 case SMP_CONF_ROUTE_INFO:
237 /* Can't implement; hosts have no routes */
238 break;
239
240 case SMP_PHY_CONTROL:
241 req->data_len =- 44;
242 if (req->data_len < 0) {
243 req->data_len = 0;
244 error = -EINVAL;
245 goto out;
246 }
247 resp_data_len -= 8;
248 sas_phy_control(sas_ha, req_data[9], req_data[10],
249 req_data[32] >> 4, req_data[33] >> 4,
250 resp_data);
251 break;
252
253 case SMP_PHY_TEST_FUNCTION:
254 /* FIXME: should this be implemented? */
255 break;
256
257 default:
258 /* probably a 2.0 function */
259 break;
260 }
261
262 local_irq_disable();
263 buf = kmap_atomic(bio_page(rsp->bio), KM_USER0) + bio_offset(rsp->bio);
264 memcpy(buf, resp_data, rsp->data_len);
265 flush_kernel_dcache_page(bio_page(rsp->bio));
266 kunmap_atomic(buf - bio_offset(rsp->bio), KM_USER0);
267 local_irq_enable();
268 rsp->data_len = resp_data_len;
269
270 out:
271 kfree(req_data);
272 kfree(resp_data);
273 return error;
274}
diff --git a/drivers/scsi/libsas/sas_internal.h b/drivers/scsi/libsas/sas_internal.h
index 2b8213b1832d..b4f9368f116a 100644
--- a/drivers/scsi/libsas/sas_internal.h
+++ b/drivers/scsi/libsas/sas_internal.h
@@ -45,7 +45,7 @@
45void sas_scsi_recover_host(struct Scsi_Host *shost); 45void sas_scsi_recover_host(struct Scsi_Host *shost);
46 46
47int sas_show_class(enum sas_class class, char *buf); 47int sas_show_class(enum sas_class class, char *buf);
48int sas_show_proto(enum sas_proto proto, char *buf); 48int sas_show_proto(enum sas_protocol proto, char *buf);
49int sas_show_linkrate(enum sas_linkrate linkrate, char *buf); 49int sas_show_linkrate(enum sas_linkrate linkrate, char *buf);
50int sas_show_oob_mode(enum sas_oob_mode oob_mode, char *buf); 50int sas_show_oob_mode(enum sas_oob_mode oob_mode, char *buf);
51 51
@@ -80,6 +80,20 @@ struct domain_device *sas_find_dev_by_rphy(struct sas_rphy *rphy);
80 80
81void sas_hae_reset(struct work_struct *work); 81void sas_hae_reset(struct work_struct *work);
82 82
83#ifdef CONFIG_SCSI_SAS_HOST_SMP
84extern int sas_smp_host_handler(struct Scsi_Host *shost, struct request *req,
85 struct request *rsp);
86#else
87static inline int sas_smp_host_handler(struct Scsi_Host *shost,
88 struct request *req,
89 struct request *rsp)
90{
91 shost_printk(KERN_ERR, shost,
92 "Cannot send SMP to a sas host (not enabled in CONFIG)\n");
93 return -EINVAL;
94}
95#endif
96
83static inline void sas_queue_event(int event, spinlock_t *lock, 97static inline void sas_queue_event(int event, spinlock_t *lock,
84 unsigned long *pending, 98 unsigned long *pending,
85 struct work_struct *work, 99 struct work_struct *work,
diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c
index a3fdc57e2673..f869fba86807 100644
--- a/drivers/scsi/libsas/sas_scsi_host.c
+++ b/drivers/scsi/libsas/sas_scsi_host.c
@@ -108,7 +108,7 @@ static void sas_scsi_task_done(struct sas_task *task)
108 break; 108 break;
109 case SAM_CHECK_COND: 109 case SAM_CHECK_COND:
110 memcpy(sc->sense_buffer, ts->buf, 110 memcpy(sc->sense_buffer, ts->buf,
111 max(SCSI_SENSE_BUFFERSIZE, ts->buf_valid_size)); 111 min(SCSI_SENSE_BUFFERSIZE, ts->buf_valid_size));
112 stat = SAM_CHECK_COND; 112 stat = SAM_CHECK_COND;
113 break; 113 break;
114 default: 114 default:
@@ -148,7 +148,6 @@ static struct sas_task *sas_create_task(struct scsi_cmnd *cmd,
148 if (!task) 148 if (!task)
149 return NULL; 149 return NULL;
150 150
151 *(u32 *)cmd->sense_buffer = 0;
152 task->uldd_task = cmd; 151 task->uldd_task = cmd;
153 ASSIGN_SAS_TASK(cmd, task); 152 ASSIGN_SAS_TASK(cmd, task);
154 153
@@ -200,6 +199,10 @@ int sas_queue_up(struct sas_task *task)
200 */ 199 */
201int sas_queuecommand(struct scsi_cmnd *cmd, 200int sas_queuecommand(struct scsi_cmnd *cmd,
202 void (*scsi_done)(struct scsi_cmnd *)) 201 void (*scsi_done)(struct scsi_cmnd *))
202 __releases(host->host_lock)
203 __acquires(dev->sata_dev.ap->lock)
204 __releases(dev->sata_dev.ap->lock)
205 __acquires(host->host_lock)
203{ 206{
204 int res = 0; 207 int res = 0;
205 struct domain_device *dev = cmd_to_domain_dev(cmd); 208 struct domain_device *dev = cmd_to_domain_dev(cmd);
@@ -410,7 +413,7 @@ static int sas_recover_I_T(struct domain_device *dev)
410} 413}
411 414
412/* Find the sas_phy that's attached to this device */ 415/* Find the sas_phy that's attached to this device */
413struct sas_phy *find_local_sas_phy(struct domain_device *dev) 416static struct sas_phy *find_local_sas_phy(struct domain_device *dev)
414{ 417{
415 struct domain_device *pdev = dev->parent; 418 struct domain_device *pdev = dev->parent;
416 struct ex_phy *exphy = NULL; 419 struct ex_phy *exphy = NULL;
diff --git a/drivers/scsi/libsas/sas_task.c b/drivers/scsi/libsas/sas_task.c
new file mode 100644
index 000000000000..594524d5bfa1
--- /dev/null
+++ b/drivers/scsi/libsas/sas_task.c
@@ -0,0 +1,36 @@
1#include <linux/kernel.h>
2#include <scsi/sas.h>
3#include <scsi/libsas.h>
4
5/* fill task_status_struct based on SSP response frame */
6void sas_ssp_task_response(struct device *dev, struct sas_task *task,
7 struct ssp_response_iu *iu)
8{
9 struct task_status_struct *tstat = &task->task_status;
10
11 tstat->resp = SAS_TASK_COMPLETE;
12
13 if (iu->datapres == 0)
14 tstat->stat = iu->status;
15 else if (iu->datapres == 1)
16 tstat->stat = iu->resp_data[3];
17 else if (iu->datapres == 2) {
18 tstat->stat = SAM_CHECK_COND;
19 tstat->buf_valid_size =
20 min_t(int, SAS_STATUS_BUF_SIZE,
21 be32_to_cpu(iu->sense_data_len));
22 memcpy(tstat->buf, iu->sense_data, tstat->buf_valid_size);
23
24 if (iu->status != SAM_CHECK_COND)
25 dev_printk(KERN_WARNING, dev,
26 "dev %llx sent sense data, but "
27 "stat(%x) is not CHECK CONDITION\n",
28 SAS_ADDR(task->dev->sas_addr),
29 iu->status);
30 }
31 else
32 /* when datapres contains corrupt/unknown value... */
33 tstat->stat = SAM_CHECK_COND;
34}
35EXPORT_SYMBOL_GPL(sas_ssp_task_response);
36