1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Aic94xx SAS/SATA Tasks |
4 | * |
5 | * Copyright (C) 2005 Adaptec, Inc. All rights reserved. |
6 | * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com> |
7 | */ |
8 | |
9 | #include <linux/spinlock.h> |
10 | #include "aic94xx.h" |
11 | #include "aic94xx_sas.h" |
12 | #include "aic94xx_hwi.h" |
13 | |
14 | static void asd_unbuild_ata_ascb(struct asd_ascb *a); |
15 | static void asd_unbuild_smp_ascb(struct asd_ascb *a); |
16 | static void asd_unbuild_ssp_ascb(struct asd_ascb *a); |
17 | |
18 | static void asd_can_dequeue(struct asd_ha_struct *asd_ha, int num) |
19 | { |
20 | unsigned long flags; |
21 | |
22 | spin_lock_irqsave(&asd_ha->seq.pend_q_lock, flags); |
23 | asd_ha->seq.can_queue += num; |
24 | spin_unlock_irqrestore(lock: &asd_ha->seq.pend_q_lock, flags); |
25 | } |
26 | |
27 | /* DMA_... to our direction translation. |
28 | */ |
29 | static const u8 data_dir_flags[] = { |
30 | [DMA_BIDIRECTIONAL] = DATA_DIR_BYRECIPIENT, /* UNSPECIFIED */ |
31 | [DMA_TO_DEVICE] = DATA_DIR_OUT, /* OUTBOUND */ |
32 | [DMA_FROM_DEVICE] = DATA_DIR_IN, /* INBOUND */ |
33 | [DMA_NONE] = DATA_DIR_NONE, /* NO TRANSFER */ |
34 | }; |
35 | |
36 | static int asd_map_scatterlist(struct sas_task *task, |
37 | struct sg_el *sg_arr, |
38 | gfp_t gfp_flags) |
39 | { |
40 | struct asd_ascb *ascb = task->lldd_task; |
41 | struct asd_ha_struct *asd_ha = ascb->ha; |
42 | struct scatterlist *sc; |
43 | int num_sg, res; |
44 | |
45 | if (task->data_dir == DMA_NONE) |
46 | return 0; |
47 | |
48 | if (task->num_scatter == 0) { |
49 | void *p = task->scatter; |
50 | dma_addr_t dma = dma_map_single(&asd_ha->pcidev->dev, p, |
51 | task->total_xfer_len, |
52 | task->data_dir); |
53 | if (dma_mapping_error(dev: &asd_ha->pcidev->dev, dma_addr: dma)) |
54 | return -ENOMEM; |
55 | |
56 | sg_arr[0].bus_addr = cpu_to_le64((u64)dma); |
57 | sg_arr[0].size = cpu_to_le32(task->total_xfer_len); |
58 | sg_arr[0].flags |= ASD_SG_EL_LIST_EOL; |
59 | return 0; |
60 | } |
61 | |
62 | /* STP tasks come from libata which has already mapped |
63 | * the SG list */ |
64 | if (sas_protocol_ata(proto: task->task_proto)) |
65 | num_sg = task->num_scatter; |
66 | else |
67 | num_sg = dma_map_sg(&asd_ha->pcidev->dev, task->scatter, |
68 | task->num_scatter, task->data_dir); |
69 | if (num_sg == 0) |
70 | return -ENOMEM; |
71 | |
72 | if (num_sg > 3) { |
73 | int i; |
74 | |
75 | ascb->sg_arr = asd_alloc_coherent(asd_ha, |
76 | size: num_sg*sizeof(struct sg_el), |
77 | flags: gfp_flags); |
78 | if (!ascb->sg_arr) { |
79 | res = -ENOMEM; |
80 | goto err_unmap; |
81 | } |
82 | for_each_sg(task->scatter, sc, num_sg, i) { |
83 | struct sg_el *sg = |
84 | &((struct sg_el *)ascb->sg_arr->vaddr)[i]; |
85 | sg->bus_addr = cpu_to_le64((u64)sg_dma_address(sc)); |
86 | sg->size = cpu_to_le32((u32)sg_dma_len(sc)); |
87 | if (i == num_sg-1) |
88 | sg->flags |= ASD_SG_EL_LIST_EOL; |
89 | } |
90 | |
91 | for_each_sg(task->scatter, sc, 2, i) { |
92 | sg_arr[i].bus_addr = |
93 | cpu_to_le64((u64)sg_dma_address(sc)); |
94 | sg_arr[i].size = cpu_to_le32((u32)sg_dma_len(sc)); |
95 | } |
96 | sg_arr[1].next_sg_offs = 2 * sizeof(*sg_arr); |
97 | sg_arr[1].flags |= ASD_SG_EL_LIST_EOS; |
98 | |
99 | memset(&sg_arr[2], 0, sizeof(*sg_arr)); |
100 | sg_arr[2].bus_addr=cpu_to_le64((u64)ascb->sg_arr->dma_handle); |
101 | } else { |
102 | int i; |
103 | for_each_sg(task->scatter, sc, num_sg, i) { |
104 | sg_arr[i].bus_addr = |
105 | cpu_to_le64((u64)sg_dma_address(sc)); |
106 | sg_arr[i].size = cpu_to_le32((u32)sg_dma_len(sc)); |
107 | } |
108 | sg_arr[i-1].flags |= ASD_SG_EL_LIST_EOL; |
109 | } |
110 | |
111 | return 0; |
112 | err_unmap: |
113 | if (sas_protocol_ata(proto: task->task_proto)) |
114 | dma_unmap_sg(&asd_ha->pcidev->dev, task->scatter, |
115 | task->num_scatter, task->data_dir); |
116 | return res; |
117 | } |
118 | |
119 | static void asd_unmap_scatterlist(struct asd_ascb *ascb) |
120 | { |
121 | struct asd_ha_struct *asd_ha = ascb->ha; |
122 | struct sas_task *task = ascb->uldd_task; |
123 | |
124 | if (task->data_dir == DMA_NONE) |
125 | return; |
126 | |
127 | if (task->num_scatter == 0) { |
128 | dma_addr_t dma = (dma_addr_t) |
129 | le64_to_cpu(ascb->scb->ssp_task.sg_element[0].bus_addr); |
130 | dma_unmap_single(&ascb->ha->pcidev->dev, dma, |
131 | task->total_xfer_len, task->data_dir); |
132 | return; |
133 | } |
134 | |
135 | asd_free_coherent(asd_ha, token: ascb->sg_arr); |
136 | if (task->task_proto != SAS_PROTOCOL_STP) |
137 | dma_unmap_sg(&asd_ha->pcidev->dev, task->scatter, |
138 | task->num_scatter, task->data_dir); |
139 | } |
140 | |
141 | /* ---------- Task complete tasklet ---------- */ |
142 | |
143 | static void asd_get_response_tasklet(struct asd_ascb *ascb, |
144 | struct done_list_struct *dl) |
145 | { |
146 | struct asd_ha_struct *asd_ha = ascb->ha; |
147 | struct sas_task *task = ascb->uldd_task; |
148 | struct task_status_struct *ts = &task->task_status; |
149 | unsigned long flags; |
150 | struct tc_resp_sb_struct { |
151 | __le16 index_escb; |
152 | u8 len_lsb; |
153 | u8 flags; |
154 | } __attribute__ ((packed)) *resp_sb = (void *) dl->status_block; |
155 | |
156 | /* int size = ((resp_sb->flags & 7) << 8) | resp_sb->len_lsb; */ |
157 | int edb_id = ((resp_sb->flags & 0x70) >> 4)-1; |
158 | struct asd_ascb *escb; |
159 | struct asd_dma_tok *edb; |
160 | void *r; |
161 | |
162 | spin_lock_irqsave(&asd_ha->seq.tc_index_lock, flags); |
163 | escb = asd_tc_index_find(seq: &asd_ha->seq, |
164 | index: (int)le16_to_cpu(resp_sb->index_escb)); |
165 | spin_unlock_irqrestore(lock: &asd_ha->seq.tc_index_lock, flags); |
166 | |
167 | if (!escb) { |
168 | ASD_DPRINTK("Uh-oh! No escb for this dl?!\n" ); |
169 | return; |
170 | } |
171 | |
172 | ts->buf_valid_size = 0; |
173 | edb = asd_ha->seq.edb_arr[edb_id + escb->edb_index]; |
174 | r = edb->vaddr; |
175 | if (task->task_proto == SAS_PROTOCOL_SSP) { |
176 | struct ssp_response_iu *iu = |
177 | r + 16 + sizeof(struct ssp_frame_hdr); |
178 | |
179 | ts->residual = le32_to_cpu(*(__le32 *)r); |
180 | |
181 | sas_ssp_task_response(dev: &asd_ha->pcidev->dev, task, iu); |
182 | } else { |
183 | struct ata_task_resp *resp = (void *) &ts->buf[0]; |
184 | |
185 | ts->residual = le32_to_cpu(*(__le32 *)r); |
186 | |
187 | if (SAS_STATUS_BUF_SIZE >= sizeof(*resp)) { |
188 | resp->frame_len = le16_to_cpu(*(__le16 *)(r+6)); |
189 | memcpy(&resp->ending_fis[0], r+16, ATA_RESP_FIS_SIZE); |
190 | ts->buf_valid_size = sizeof(*resp); |
191 | } |
192 | } |
193 | |
194 | asd_invalidate_edb(ascb: escb, edb_id); |
195 | } |
196 | |
197 | static void asd_task_tasklet_complete(struct asd_ascb *ascb, |
198 | struct done_list_struct *dl) |
199 | { |
200 | struct sas_task *task = ascb->uldd_task; |
201 | struct task_status_struct *ts = &task->task_status; |
202 | unsigned long flags; |
203 | u8 opcode = dl->opcode; |
204 | |
205 | asd_can_dequeue(asd_ha: ascb->ha, num: 1); |
206 | |
207 | Again: |
208 | switch (opcode) { |
209 | case TC_NO_ERROR: |
210 | ts->resp = SAS_TASK_COMPLETE; |
211 | ts->stat = SAS_SAM_STAT_GOOD; |
212 | break; |
213 | case TC_UNDERRUN: |
214 | ts->resp = SAS_TASK_COMPLETE; |
215 | ts->stat = SAS_DATA_UNDERRUN; |
216 | ts->residual = le32_to_cpu(*(__le32 *)dl->status_block); |
217 | break; |
218 | case TC_OVERRUN: |
219 | ts->resp = SAS_TASK_COMPLETE; |
220 | ts->stat = SAS_DATA_OVERRUN; |
221 | ts->residual = 0; |
222 | break; |
223 | case TC_SSP_RESP: |
224 | case TC_ATA_RESP: |
225 | ts->resp = SAS_TASK_COMPLETE; |
226 | ts->stat = SAS_PROTO_RESPONSE; |
227 | asd_get_response_tasklet(ascb, dl); |
228 | break; |
229 | case TF_OPEN_REJECT: |
230 | ts->resp = SAS_TASK_UNDELIVERED; |
231 | ts->stat = SAS_OPEN_REJECT; |
232 | if (dl->status_block[1] & 2) |
233 | ts->open_rej_reason = 1 + dl->status_block[2]; |
234 | else if (dl->status_block[1] & 1) |
235 | ts->open_rej_reason = (dl->status_block[2] >> 4)+10; |
236 | else |
237 | ts->open_rej_reason = SAS_OREJ_UNKNOWN; |
238 | break; |
239 | case TF_OPEN_TO: |
240 | ts->resp = SAS_TASK_UNDELIVERED; |
241 | ts->stat = SAS_OPEN_TO; |
242 | break; |
243 | case TF_PHY_DOWN: |
244 | case TU_PHY_DOWN: |
245 | ts->resp = SAS_TASK_UNDELIVERED; |
246 | ts->stat = SAS_PHY_DOWN; |
247 | break; |
248 | case TI_PHY_DOWN: |
249 | ts->resp = SAS_TASK_COMPLETE; |
250 | ts->stat = SAS_PHY_DOWN; |
251 | break; |
252 | case TI_BREAK: |
253 | case TI_PROTO_ERR: |
254 | case TI_NAK: |
255 | case TI_ACK_NAK_TO: |
256 | case TF_SMP_XMIT_RCV_ERR: |
257 | case TC_ATA_R_ERR_RECV: |
258 | ts->resp = SAS_TASK_COMPLETE; |
259 | ts->stat = SAS_INTERRUPTED; |
260 | break; |
261 | case TF_BREAK: |
262 | case TU_BREAK: |
263 | case TU_ACK_NAK_TO: |
264 | case TF_SMPRSP_TO: |
265 | ts->resp = SAS_TASK_UNDELIVERED; |
266 | ts->stat = SAS_DEV_NO_RESPONSE; |
267 | break; |
268 | case TF_NAK_RECV: |
269 | ts->resp = SAS_TASK_COMPLETE; |
270 | ts->stat = SAS_NAK_R_ERR; |
271 | break; |
272 | case TA_I_T_NEXUS_LOSS: |
273 | opcode = dl->status_block[0]; |
274 | goto Again; |
275 | case TF_INV_CONN_HANDLE: |
276 | ts->resp = SAS_TASK_UNDELIVERED; |
277 | ts->stat = SAS_DEVICE_UNKNOWN; |
278 | break; |
279 | case TF_REQUESTED_N_PENDING: |
280 | ts->resp = SAS_TASK_UNDELIVERED; |
281 | ts->stat = SAS_PENDING; |
282 | break; |
283 | case TC_TASK_CLEARED: |
284 | case TA_ON_REQ: |
285 | ts->resp = SAS_TASK_COMPLETE; |
286 | ts->stat = SAS_ABORTED_TASK; |
287 | break; |
288 | |
289 | case TF_NO_SMP_CONN: |
290 | case TF_TMF_NO_CTX: |
291 | case TF_TMF_NO_TAG: |
292 | case TF_TMF_TAG_FREE: |
293 | case TF_TMF_TASK_DONE: |
294 | case TF_TMF_NO_CONN_HANDLE: |
295 | case TF_IRTT_TO: |
296 | case TF_IU_SHORT: |
297 | case TF_DATA_OFFS_ERR: |
298 | ts->resp = SAS_TASK_UNDELIVERED; |
299 | ts->stat = SAS_DEV_NO_RESPONSE; |
300 | break; |
301 | |
302 | case TC_LINK_ADM_RESP: |
303 | case TC_CONTROL_PHY: |
304 | case TC_RESUME: |
305 | case TC_PARTIAL_SG_LIST: |
306 | default: |
307 | ASD_DPRINTK("%s: dl opcode: 0x%x?\n" , __func__, opcode); |
308 | break; |
309 | } |
310 | |
311 | switch (task->task_proto) { |
312 | case SAS_PROTOCOL_SATA: |
313 | case SAS_PROTOCOL_STP: |
314 | asd_unbuild_ata_ascb(a: ascb); |
315 | break; |
316 | case SAS_PROTOCOL_SMP: |
317 | asd_unbuild_smp_ascb(a: ascb); |
318 | break; |
319 | case SAS_PROTOCOL_SSP: |
320 | asd_unbuild_ssp_ascb(a: ascb); |
321 | break; |
322 | default: |
323 | break; |
324 | } |
325 | |
326 | spin_lock_irqsave(&task->task_state_lock, flags); |
327 | task->task_state_flags &= ~SAS_TASK_STATE_PENDING; |
328 | task->task_state_flags |= SAS_TASK_STATE_DONE; |
329 | if (unlikely((task->task_state_flags & SAS_TASK_STATE_ABORTED))) { |
330 | struct completion *completion = ascb->completion; |
331 | spin_unlock_irqrestore(lock: &task->task_state_lock, flags); |
332 | ASD_DPRINTK("task 0x%p done with opcode 0x%x resp 0x%x " |
333 | "stat 0x%x but aborted by upper layer!\n" , |
334 | task, opcode, ts->resp, ts->stat); |
335 | if (completion) |
336 | complete(completion); |
337 | } else { |
338 | spin_unlock_irqrestore(lock: &task->task_state_lock, flags); |
339 | task->lldd_task = NULL; |
340 | asd_ascb_free(ascb); |
341 | mb(); |
342 | task->task_done(task); |
343 | } |
344 | } |
345 | |
346 | /* ---------- ATA ---------- */ |
347 | |
348 | static int asd_build_ata_ascb(struct asd_ascb *ascb, struct sas_task *task, |
349 | gfp_t gfp_flags) |
350 | { |
351 | struct domain_device *dev = task->dev; |
352 | struct scb *scb; |
353 | u8 flags; |
354 | int res = 0; |
355 | |
356 | scb = ascb->scb; |
357 | |
358 | if (unlikely(task->ata_task.device_control_reg_update)) |
359 | scb->header.opcode = CONTROL_ATA_DEV; |
360 | else if (dev->sata_dev.class == ATA_DEV_ATAPI) |
361 | scb->header.opcode = INITIATE_ATAPI_TASK; |
362 | else |
363 | scb->header.opcode = INITIATE_ATA_TASK; |
364 | |
365 | scb->ata_task.proto_conn_rate = (1 << 5); /* STP */ |
366 | if (dev->port->oob_mode == SAS_OOB_MODE) |
367 | scb->ata_task.proto_conn_rate |= dev->linkrate; |
368 | |
369 | scb->ata_task.total_xfer_len = cpu_to_le32(task->total_xfer_len); |
370 | scb->ata_task.fis = task->ata_task.fis; |
371 | if (likely(!task->ata_task.device_control_reg_update)) |
372 | scb->ata_task.fis.flags |= 0x80; /* C=1: update ATA cmd reg */ |
373 | scb->ata_task.fis.flags &= 0xF0; /* PM_PORT field shall be 0 */ |
374 | if (dev->sata_dev.class == ATA_DEV_ATAPI) |
375 | memcpy(scb->ata_task.atapi_packet, task->ata_task.atapi_packet, |
376 | 16); |
377 | scb->ata_task.sister_scb = cpu_to_le16(0xFFFF); |
378 | scb->ata_task.conn_handle = cpu_to_le16( |
379 | (u16)(unsigned long)dev->lldd_dev); |
380 | |
381 | if (likely(!task->ata_task.device_control_reg_update)) { |
382 | flags = 0; |
383 | if (task->ata_task.dma_xfer) |
384 | flags |= DATA_XFER_MODE_DMA; |
385 | if (task->ata_task.use_ncq && |
386 | dev->sata_dev.class != ATA_DEV_ATAPI) |
387 | flags |= ATA_Q_TYPE_NCQ; |
388 | flags |= data_dir_flags[task->data_dir]; |
389 | scb->ata_task.ata_flags = flags; |
390 | |
391 | scb->ata_task.retry_count = 0; |
392 | |
393 | scb->ata_task.flags = 0; |
394 | } |
395 | ascb->tasklet_complete = asd_task_tasklet_complete; |
396 | |
397 | if (likely(!task->ata_task.device_control_reg_update)) |
398 | res = asd_map_scatterlist(task, sg_arr: scb->ata_task.sg_element, |
399 | gfp_flags); |
400 | |
401 | return res; |
402 | } |
403 | |
404 | static void asd_unbuild_ata_ascb(struct asd_ascb *a) |
405 | { |
406 | asd_unmap_scatterlist(ascb: a); |
407 | } |
408 | |
409 | /* ---------- SMP ---------- */ |
410 | |
411 | static int asd_build_smp_ascb(struct asd_ascb *ascb, struct sas_task *task, |
412 | gfp_t gfp_flags) |
413 | { |
414 | struct asd_ha_struct *asd_ha = ascb->ha; |
415 | struct domain_device *dev = task->dev; |
416 | struct scb *scb; |
417 | |
418 | dma_map_sg(&asd_ha->pcidev->dev, &task->smp_task.smp_req, 1, |
419 | DMA_TO_DEVICE); |
420 | dma_map_sg(&asd_ha->pcidev->dev, &task->smp_task.smp_resp, 1, |
421 | DMA_FROM_DEVICE); |
422 | |
423 | scb = ascb->scb; |
424 | |
425 | scb->header.opcode = INITIATE_SMP_TASK; |
426 | |
427 | scb->smp_task.proto_conn_rate = dev->linkrate; |
428 | |
429 | scb->smp_task.smp_req.bus_addr = |
430 | cpu_to_le64((u64)sg_dma_address(&task->smp_task.smp_req)); |
431 | scb->smp_task.smp_req.size = |
432 | cpu_to_le32((u32)sg_dma_len(&task->smp_task.smp_req)-4); |
433 | |
434 | scb->smp_task.smp_resp.bus_addr = |
435 | cpu_to_le64((u64)sg_dma_address(&task->smp_task.smp_resp)); |
436 | scb->smp_task.smp_resp.size = |
437 | cpu_to_le32((u32)sg_dma_len(&task->smp_task.smp_resp)-4); |
438 | |
439 | scb->smp_task.sister_scb = cpu_to_le16(0xFFFF); |
440 | scb->smp_task.conn_handle = cpu_to_le16((u16) |
441 | (unsigned long)dev->lldd_dev); |
442 | |
443 | ascb->tasklet_complete = asd_task_tasklet_complete; |
444 | |
445 | return 0; |
446 | } |
447 | |
448 | static void asd_unbuild_smp_ascb(struct asd_ascb *a) |
449 | { |
450 | struct sas_task *task = a->uldd_task; |
451 | |
452 | BUG_ON(!task); |
453 | dma_unmap_sg(&a->ha->pcidev->dev, &task->smp_task.smp_req, 1, |
454 | DMA_TO_DEVICE); |
455 | dma_unmap_sg(&a->ha->pcidev->dev, &task->smp_task.smp_resp, 1, |
456 | DMA_FROM_DEVICE); |
457 | } |
458 | |
459 | /* ---------- SSP ---------- */ |
460 | |
461 | static int asd_build_ssp_ascb(struct asd_ascb *ascb, struct sas_task *task, |
462 | gfp_t gfp_flags) |
463 | { |
464 | struct domain_device *dev = task->dev; |
465 | struct scb *scb; |
466 | int res = 0; |
467 | |
468 | scb = ascb->scb; |
469 | |
470 | scb->header.opcode = INITIATE_SSP_TASK; |
471 | |
472 | scb->ssp_task.proto_conn_rate = (1 << 4); /* SSP */ |
473 | scb->ssp_task.proto_conn_rate |= dev->linkrate; |
474 | scb->ssp_task.total_xfer_len = cpu_to_le32(task->total_xfer_len); |
475 | scb->ssp_task.ssp_frame.frame_type = SSP_DATA; |
476 | memcpy(scb->ssp_task.ssp_frame.hashed_dest_addr, dev->hashed_sas_addr, |
477 | HASHED_SAS_ADDR_SIZE); |
478 | memcpy(scb->ssp_task.ssp_frame.hashed_src_addr, |
479 | dev->port->ha->hashed_sas_addr, HASHED_SAS_ADDR_SIZE); |
480 | scb->ssp_task.ssp_frame.tptt = cpu_to_be16(0xFFFF); |
481 | |
482 | memcpy(scb->ssp_task.ssp_cmd.lun, task->ssp_task.LUN, 8); |
483 | scb->ssp_task.ssp_cmd.efb_prio_attr |= (task->ssp_task.task_attr & 7); |
484 | memcpy(scb->ssp_task.ssp_cmd.cdb, task->ssp_task.cmd->cmnd, |
485 | task->ssp_task.cmd->cmd_len); |
486 | |
487 | scb->ssp_task.sister_scb = cpu_to_le16(0xFFFF); |
488 | scb->ssp_task.conn_handle = cpu_to_le16( |
489 | (u16)(unsigned long)dev->lldd_dev); |
490 | scb->ssp_task.data_dir = data_dir_flags[task->data_dir]; |
491 | scb->ssp_task.retry_count = scb->ssp_task.retry_count; |
492 | |
493 | ascb->tasklet_complete = asd_task_tasklet_complete; |
494 | |
495 | res = asd_map_scatterlist(task, sg_arr: scb->ssp_task.sg_element, gfp_flags); |
496 | |
497 | return res; |
498 | } |
499 | |
500 | static void asd_unbuild_ssp_ascb(struct asd_ascb *a) |
501 | { |
502 | asd_unmap_scatterlist(ascb: a); |
503 | } |
504 | |
505 | /* ---------- Execute Task ---------- */ |
506 | |
507 | static int asd_can_queue(struct asd_ha_struct *asd_ha, int num) |
508 | { |
509 | int res = 0; |
510 | unsigned long flags; |
511 | |
512 | spin_lock_irqsave(&asd_ha->seq.pend_q_lock, flags); |
513 | if ((asd_ha->seq.can_queue - num) < 0) |
514 | res = -SAS_QUEUE_FULL; |
515 | else |
516 | asd_ha->seq.can_queue -= num; |
517 | spin_unlock_irqrestore(lock: &asd_ha->seq.pend_q_lock, flags); |
518 | |
519 | return res; |
520 | } |
521 | |
522 | int asd_execute_task(struct sas_task *task, gfp_t gfp_flags) |
523 | { |
524 | int res = 0; |
525 | LIST_HEAD(alist); |
526 | struct sas_task *t = task; |
527 | struct asd_ascb *ascb = NULL, *a; |
528 | struct asd_ha_struct *asd_ha = task->dev->port->ha->lldd_ha; |
529 | |
530 | res = asd_can_queue(asd_ha, num: 1); |
531 | if (res) |
532 | return res; |
533 | |
534 | res = 1; |
535 | ascb = asd_ascb_alloc_list(asd_ha, num: &res, gfp_mask: gfp_flags); |
536 | if (res) { |
537 | res = -ENOMEM; |
538 | goto out_err; |
539 | } |
540 | |
541 | __list_add(new: &alist, prev: ascb->list.prev, next: &ascb->list); |
542 | list_for_each_entry(a, &alist, list) { |
543 | a->uldd_task = t; |
544 | t->lldd_task = a; |
545 | break; |
546 | } |
547 | list_for_each_entry(a, &alist, list) { |
548 | t = a->uldd_task; |
549 | a->uldd_timer = 1; |
550 | if (t->task_proto & SAS_PROTOCOL_STP) |
551 | t->task_proto = SAS_PROTOCOL_STP; |
552 | switch (t->task_proto) { |
553 | case SAS_PROTOCOL_SATA: |
554 | case SAS_PROTOCOL_STP: |
555 | res = asd_build_ata_ascb(ascb: a, task: t, gfp_flags); |
556 | break; |
557 | case SAS_PROTOCOL_SMP: |
558 | res = asd_build_smp_ascb(ascb: a, task: t, gfp_flags); |
559 | break; |
560 | case SAS_PROTOCOL_SSP: |
561 | res = asd_build_ssp_ascb(ascb: a, task: t, gfp_flags); |
562 | break; |
563 | default: |
564 | asd_printk("unknown sas_task proto: 0x%x\n" , |
565 | t->task_proto); |
566 | res = -ENOMEM; |
567 | break; |
568 | } |
569 | if (res) |
570 | goto out_err_unmap; |
571 | } |
572 | list_del_init(entry: &alist); |
573 | |
574 | res = asd_post_ascb_list(asd_ha, ascb, num: 1); |
575 | if (unlikely(res)) { |
576 | a = NULL; |
577 | __list_add(new: &alist, prev: ascb->list.prev, next: &ascb->list); |
578 | goto out_err_unmap; |
579 | } |
580 | |
581 | return 0; |
582 | out_err_unmap: |
583 | { |
584 | struct asd_ascb *b = a; |
585 | list_for_each_entry(a, &alist, list) { |
586 | if (a == b) |
587 | break; |
588 | t = a->uldd_task; |
589 | switch (t->task_proto) { |
590 | case SAS_PROTOCOL_SATA: |
591 | case SAS_PROTOCOL_STP: |
592 | asd_unbuild_ata_ascb(a); |
593 | break; |
594 | case SAS_PROTOCOL_SMP: |
595 | asd_unbuild_smp_ascb(a); |
596 | break; |
597 | case SAS_PROTOCOL_SSP: |
598 | asd_unbuild_ssp_ascb(a); |
599 | break; |
600 | default: |
601 | break; |
602 | } |
603 | t->lldd_task = NULL; |
604 | } |
605 | } |
606 | list_del_init(entry: &alist); |
607 | out_err: |
608 | if (ascb) |
609 | asd_ascb_free_list(ascb_list: ascb); |
610 | asd_can_dequeue(asd_ha, num: 1); |
611 | return res; |
612 | } |
613 | |