blob: 6a97b07849b47b01a0132316c7071b041f787cb1 [file] [log] [blame]
James Bottomley2908d772006-08-29 09:22:51 -05001/*
2 * Serial Attached SCSI (SAS) class SCSI Host glue.
3 *
4 * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
5 * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
6 *
7 * This file is licensed under GPLv2.
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation; either version 2 of the
12 * License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
22 * USA
23 *
24 */
25
26#include "sas_internal.h"
27
28#include <scsi/scsi_host.h>
29#include <scsi/scsi_device.h>
30#include <scsi/scsi_tcq.h>
31#include <scsi/scsi.h>
Darrick J. Wongf4563932006-10-30 15:18:39 -080032#include <scsi/scsi_eh.h>
James Bottomley2908d772006-08-29 09:22:51 -050033#include <scsi/scsi_transport.h>
34#include <scsi/scsi_transport_sas.h>
35#include "../scsi_sas_internal.h"
36
37#include <linux/err.h>
38#include <linux/blkdev.h>
39#include <linux/scatterlist.h>
40
41/* ---------- SCSI Host glue ---------- */
42
43#define TO_SAS_TASK(_scsi_cmd) ((void *)(_scsi_cmd)->host_scribble)
44#define ASSIGN_SAS_TASK(_sc, _t) do { (_sc)->host_scribble = (void *) _t; } while (0)
45
46static void sas_scsi_task_done(struct sas_task *task)
47{
48 struct task_status_struct *ts = &task->task_status;
49 struct scsi_cmnd *sc = task->uldd_task;
Darrick J. Wongf4563932006-10-30 15:18:39 -080050 struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(sc->device->host);
James Bottomley2908d772006-08-29 09:22:51 -050051 unsigned ts_flags = task->task_state_flags;
52 int hs = 0, stat = 0;
53
54 if (unlikely(!sc)) {
55 SAS_DPRINTK("task_done called with non existing SCSI cmnd!\n");
56 list_del_init(&task->list);
57 sas_free_task(task);
58 return;
59 }
60
61 if (ts->resp == SAS_TASK_UNDELIVERED) {
62 /* transport error */
63 hs = DID_NO_CONNECT;
64 } else { /* ts->resp == SAS_TASK_COMPLETE */
65 /* task delivered, what happened afterwards? */
66 switch (ts->stat) {
67 case SAS_DEV_NO_RESPONSE:
68 case SAS_INTERRUPTED:
69 case SAS_PHY_DOWN:
70 case SAS_NAK_R_ERR:
71 case SAS_OPEN_TO:
72 hs = DID_NO_CONNECT;
73 break;
74 case SAS_DATA_UNDERRUN:
75 sc->resid = ts->residual;
76 if (sc->request_bufflen - sc->resid < sc->underflow)
77 hs = DID_ERROR;
78 break;
79 case SAS_DATA_OVERRUN:
80 hs = DID_ERROR;
81 break;
82 case SAS_QUEUE_FULL:
83 hs = DID_SOFT_ERROR; /* retry */
84 break;
85 case SAS_DEVICE_UNKNOWN:
86 hs = DID_BAD_TARGET;
87 break;
88 case SAS_SG_ERR:
89 hs = DID_PARITY;
90 break;
91 case SAS_OPEN_REJECT:
92 if (ts->open_rej_reason == SAS_OREJ_RSVD_RETRY)
93 hs = DID_SOFT_ERROR; /* retry */
94 else
95 hs = DID_ERROR;
96 break;
97 case SAS_PROTO_RESPONSE:
98 SAS_DPRINTK("LLDD:%s sent SAS_PROTO_RESP for an SSP "
99 "task; please report this\n",
100 task->dev->port->ha->sas_ha_name);
101 break;
102 case SAS_ABORTED_TASK:
103 hs = DID_ABORT;
104 break;
105 case SAM_CHECK_COND:
106 memcpy(sc->sense_buffer, ts->buf,
107 max(SCSI_SENSE_BUFFERSIZE, ts->buf_valid_size));
108 stat = SAM_CHECK_COND;
109 break;
110 default:
111 stat = ts->stat;
112 break;
113 }
114 }
115 ASSIGN_SAS_TASK(sc, NULL);
116 sc->result = (hs << 16) | stat;
117 list_del_init(&task->list);
118 sas_free_task(task);
119 /* This is very ugly but this is how SCSI Core works. */
120 if (ts_flags & SAS_TASK_STATE_ABORTED)
Darrick J. Wongf4563932006-10-30 15:18:39 -0800121 scsi_eh_finish_cmd(sc, &sas_ha->eh_done_q);
James Bottomley2908d772006-08-29 09:22:51 -0500122 else
123 sc->scsi_done(sc);
124}
125
126static enum task_attribute sas_scsi_get_task_attr(struct scsi_cmnd *cmd)
127{
128 enum task_attribute ta = TASK_ATTR_SIMPLE;
129 if (cmd->request && blk_rq_tagged(cmd->request)) {
130 if (cmd->device->ordered_tags &&
Jeff Garzik1bdfd552006-09-30 21:28:22 -0400131 (cmd->request->cmd_flags & REQ_HARDBARRIER))
James Bottomley2908d772006-08-29 09:22:51 -0500132 ta = TASK_ATTR_HOQ;
133 }
134 return ta;
135}
136
137static struct sas_task *sas_create_task(struct scsi_cmnd *cmd,
138 struct domain_device *dev,
Al Viro3cc27542006-09-25 02:55:40 +0100139 gfp_t gfp_flags)
James Bottomley2908d772006-08-29 09:22:51 -0500140{
141 struct sas_task *task = sas_alloc_task(gfp_flags);
142 struct scsi_lun lun;
143
144 if (!task)
145 return NULL;
146
147 *(u32 *)cmd->sense_buffer = 0;
148 task->uldd_task = cmd;
149 ASSIGN_SAS_TASK(cmd, task);
150
151 task->dev = dev;
152 task->task_proto = task->dev->tproto; /* BUG_ON(!SSP) */
153
154 task->ssp_task.retry_count = 1;
155 int_to_scsilun(cmd->device->lun, &lun);
156 memcpy(task->ssp_task.LUN, &lun.scsi_lun, 8);
157 task->ssp_task.task_attr = sas_scsi_get_task_attr(cmd);
158 memcpy(task->ssp_task.cdb, cmd->cmnd, 16);
159
160 task->scatter = cmd->request_buffer;
161 task->num_scatter = cmd->use_sg;
162 task->total_xfer_len = cmd->request_bufflen;
163 task->data_dir = cmd->sc_data_direction;
164
165 task->task_done = sas_scsi_task_done;
166
167 return task;
168}
169
170static int sas_queue_up(struct sas_task *task)
171{
172 struct sas_ha_struct *sas_ha = task->dev->port->ha;
173 struct scsi_core *core = &sas_ha->core;
174 unsigned long flags;
175 LIST_HEAD(list);
176
177 spin_lock_irqsave(&core->task_queue_lock, flags);
178 if (sas_ha->lldd_queue_size < core->task_queue_size + 1) {
179 spin_unlock_irqrestore(&core->task_queue_lock, flags);
180 return -SAS_QUEUE_FULL;
181 }
182 list_add_tail(&task->list, &core->task_queue);
183 core->task_queue_size += 1;
184 spin_unlock_irqrestore(&core->task_queue_lock, flags);
185 up(&core->queue_thread_sema);
186
187 return 0;
188}
189
190/**
191 * sas_queuecommand -- Enqueue a command for processing
192 * @parameters: See SCSI Core documentation
193 *
194 * Note: XXX: Remove the host unlock/lock pair when SCSI Core can
195 * call us without holding an IRQ spinlock...
196 */
197int sas_queuecommand(struct scsi_cmnd *cmd,
198 void (*scsi_done)(struct scsi_cmnd *))
199{
200 int res = 0;
201 struct domain_device *dev = cmd_to_domain_dev(cmd);
202 struct Scsi_Host *host = cmd->device->host;
203 struct sas_internal *i = to_sas_internal(host->transportt);
204
205 spin_unlock_irq(host->host_lock);
206
207 {
208 struct sas_ha_struct *sas_ha = dev->port->ha;
209 struct sas_task *task;
210
211 res = -ENOMEM;
212 task = sas_create_task(cmd, dev, GFP_ATOMIC);
213 if (!task)
214 goto out;
215
216 cmd->scsi_done = scsi_done;
217 /* Queue up, Direct Mode or Task Collector Mode. */
218 if (sas_ha->lldd_max_execute_num < 2)
219 res = i->dft->lldd_execute_task(task, 1, GFP_ATOMIC);
220 else
221 res = sas_queue_up(task);
222
223 /* Examine */
224 if (res) {
225 SAS_DPRINTK("lldd_execute_task returned: %d\n", res);
226 ASSIGN_SAS_TASK(cmd, NULL);
227 sas_free_task(task);
228 if (res == -SAS_QUEUE_FULL) {
229 cmd->result = DID_SOFT_ERROR << 16; /* retry */
230 res = 0;
231 scsi_done(cmd);
232 }
233 goto out;
234 }
235 }
236out:
237 spin_lock_irq(host->host_lock);
238 return res;
239}
240
241static void sas_scsi_clear_queue_lu(struct list_head *error_q, struct scsi_cmnd *my_cmd)
242{
243 struct scsi_cmnd *cmd, *n;
244
245 list_for_each_entry_safe(cmd, n, error_q, eh_entry) {
246 if (cmd == my_cmd)
247 list_del_init(&cmd->eh_entry);
248 }
249}
250
251static void sas_scsi_clear_queue_I_T(struct list_head *error_q,
252 struct domain_device *dev)
253{
254 struct scsi_cmnd *cmd, *n;
255
256 list_for_each_entry_safe(cmd, n, error_q, eh_entry) {
257 struct domain_device *x = cmd_to_domain_dev(cmd);
258
259 if (x == dev)
260 list_del_init(&cmd->eh_entry);
261 }
262}
263
264static void sas_scsi_clear_queue_port(struct list_head *error_q,
265 struct asd_sas_port *port)
266{
267 struct scsi_cmnd *cmd, *n;
268
269 list_for_each_entry_safe(cmd, n, error_q, eh_entry) {
270 struct domain_device *dev = cmd_to_domain_dev(cmd);
271 struct asd_sas_port *x = dev->port;
272
273 if (x == port)
274 list_del_init(&cmd->eh_entry);
275 }
276}
277
278enum task_disposition {
279 TASK_IS_DONE,
280 TASK_IS_ABORTED,
281 TASK_IS_AT_LU,
282 TASK_IS_NOT_AT_LU,
283};
284
285static enum task_disposition sas_scsi_find_task(struct sas_task *task)
286{
287 struct sas_ha_struct *ha = task->dev->port->ha;
288 unsigned long flags;
289 int i, res;
290 struct sas_internal *si =
291 to_sas_internal(task->dev->port->ha->core.shost->transportt);
292
293 if (ha->lldd_max_execute_num > 1) {
294 struct scsi_core *core = &ha->core;
295 struct sas_task *t, *n;
296
297 spin_lock_irqsave(&core->task_queue_lock, flags);
298 list_for_each_entry_safe(t, n, &core->task_queue, list) {
299 if (task == t) {
300 list_del_init(&t->list);
301 spin_unlock_irqrestore(&core->task_queue_lock,
302 flags);
303 SAS_DPRINTK("%s: task 0x%p aborted from "
304 "task_queue\n",
305 __FUNCTION__, task);
306 return TASK_IS_ABORTED;
307 }
308 }
309 spin_unlock_irqrestore(&core->task_queue_lock, flags);
310 }
311
Darrick J. Wongf4563932006-10-30 15:18:39 -0800312 spin_lock_irqsave(&task->task_state_lock, flags);
313 if (task->task_state_flags & SAS_TASK_INITIATOR_ABORTED) {
314 spin_unlock_irqrestore(&task->task_state_lock, flags);
315 SAS_DPRINTK("%s: task 0x%p already aborted\n",
316 __FUNCTION__, task);
317 return TASK_IS_ABORTED;
318 }
319 spin_unlock_irqrestore(&task->task_state_lock, flags);
320
James Bottomley2908d772006-08-29 09:22:51 -0500321 for (i = 0; i < 5; i++) {
322 SAS_DPRINTK("%s: aborting task 0x%p\n", __FUNCTION__, task);
323 res = si->dft->lldd_abort_task(task);
324
325 spin_lock_irqsave(&task->task_state_lock, flags);
326 if (task->task_state_flags & SAS_TASK_STATE_DONE) {
327 spin_unlock_irqrestore(&task->task_state_lock, flags);
328 SAS_DPRINTK("%s: task 0x%p is done\n", __FUNCTION__,
329 task);
330 return TASK_IS_DONE;
331 }
332 spin_unlock_irqrestore(&task->task_state_lock, flags);
333
334 if (res == TMF_RESP_FUNC_COMPLETE) {
335 SAS_DPRINTK("%s: task 0x%p is aborted\n",
336 __FUNCTION__, task);
337 return TASK_IS_ABORTED;
338 } else if (si->dft->lldd_query_task) {
339 SAS_DPRINTK("%s: querying task 0x%p\n",
340 __FUNCTION__, task);
341 res = si->dft->lldd_query_task(task);
342 if (res == TMF_RESP_FUNC_SUCC) {
343 SAS_DPRINTK("%s: task 0x%p at LU\n",
344 __FUNCTION__, task);
345 return TASK_IS_AT_LU;
346 } else if (res == TMF_RESP_FUNC_COMPLETE) {
347 SAS_DPRINTK("%s: task 0x%p not at LU\n",
348 __FUNCTION__, task);
349 return TASK_IS_NOT_AT_LU;
350 }
351 }
352 }
353 return res;
354}
355
356static int sas_recover_lu(struct domain_device *dev, struct scsi_cmnd *cmd)
357{
358 int res = TMF_RESP_FUNC_FAILED;
359 struct scsi_lun lun;
360 struct sas_internal *i =
361 to_sas_internal(dev->port->ha->core.shost->transportt);
362
363 int_to_scsilun(cmd->device->lun, &lun);
364
365 SAS_DPRINTK("eh: device %llx LUN %x has the task\n",
366 SAS_ADDR(dev->sas_addr),
367 cmd->device->lun);
368
369 if (i->dft->lldd_abort_task_set)
370 res = i->dft->lldd_abort_task_set(dev, lun.scsi_lun);
371
372 if (res == TMF_RESP_FUNC_FAILED) {
373 if (i->dft->lldd_clear_task_set)
374 res = i->dft->lldd_clear_task_set(dev, lun.scsi_lun);
375 }
376
377 if (res == TMF_RESP_FUNC_FAILED) {
378 if (i->dft->lldd_lu_reset)
379 res = i->dft->lldd_lu_reset(dev, lun.scsi_lun);
380 }
381
382 return res;
383}
384
385static int sas_recover_I_T(struct domain_device *dev)
386{
387 int res = TMF_RESP_FUNC_FAILED;
388 struct sas_internal *i =
389 to_sas_internal(dev->port->ha->core.shost->transportt);
390
391 SAS_DPRINTK("I_T nexus reset for dev %016llx\n",
392 SAS_ADDR(dev->sas_addr));
393
394 if (i->dft->lldd_I_T_nexus_reset)
395 res = i->dft->lldd_I_T_nexus_reset(dev);
396
397 return res;
398}
399
400void sas_scsi_recover_host(struct Scsi_Host *shost)
401{
402 struct sas_ha_struct *ha = SHOST_TO_SAS_HA(shost);
403 unsigned long flags;
404 LIST_HEAD(error_q);
405 struct scsi_cmnd *cmd, *n;
406 enum task_disposition res = TASK_IS_DONE;
407 int tmf_resp;
408 struct sas_internal *i = to_sas_internal(shost->transportt);
409
410 spin_lock_irqsave(shost->host_lock, flags);
411 list_splice_init(&shost->eh_cmd_q, &error_q);
412 spin_unlock_irqrestore(shost->host_lock, flags);
413
414 SAS_DPRINTK("Enter %s\n", __FUNCTION__);
415
416 /* All tasks on this list were marked SAS_TASK_STATE_ABORTED
417 * by sas_scsi_timed_out() callback.
418 */
419Again:
420 SAS_DPRINTK("going over list...\n");
421 list_for_each_entry_safe(cmd, n, &error_q, eh_entry) {
422 struct sas_task *task = TO_SAS_TASK(cmd);
James Bottomley2908d772006-08-29 09:22:51 -0500423 list_del_init(&cmd->eh_entry);
Darrick J. Wongf4563932006-10-30 15:18:39 -0800424
425 if (!task) {
426 SAS_DPRINTK("%s: taskless cmd?!\n", __FUNCTION__);
427 continue;
428 }
429 SAS_DPRINTK("trying to find task 0x%p\n", task);
James Bottomley2908d772006-08-29 09:22:51 -0500430 res = sas_scsi_find_task(task);
431
432 cmd->eh_eflags = 0;
James Bottomley2908d772006-08-29 09:22:51 -0500433
434 switch (res) {
435 case TASK_IS_DONE:
436 SAS_DPRINTK("%s: task 0x%p is done\n", __FUNCTION__,
437 task);
438 task->task_done(task);
439 continue;
440 case TASK_IS_ABORTED:
441 SAS_DPRINTK("%s: task 0x%p is aborted\n",
442 __FUNCTION__, task);
443 task->task_done(task);
444 continue;
445 case TASK_IS_AT_LU:
446 SAS_DPRINTK("task 0x%p is at LU: lu recover\n", task);
447 tmf_resp = sas_recover_lu(task->dev, cmd);
448 if (tmf_resp == TMF_RESP_FUNC_COMPLETE) {
449 SAS_DPRINTK("dev %016llx LU %x is "
450 "recovered\n",
451 SAS_ADDR(task->dev),
452 cmd->device->lun);
453 task->task_done(task);
454 sas_scsi_clear_queue_lu(&error_q, cmd);
455 goto Again;
456 }
457 /* fallthrough */
458 case TASK_IS_NOT_AT_LU:
459 SAS_DPRINTK("task 0x%p is not at LU: I_T recover\n",
460 task);
461 tmf_resp = sas_recover_I_T(task->dev);
462 if (tmf_resp == TMF_RESP_FUNC_COMPLETE) {
463 SAS_DPRINTK("I_T %016llx recovered\n",
464 SAS_ADDR(task->dev->sas_addr));
465 task->task_done(task);
466 sas_scsi_clear_queue_I_T(&error_q, task->dev);
467 goto Again;
468 }
469 /* Hammer time :-) */
470 if (i->dft->lldd_clear_nexus_port) {
471 struct asd_sas_port *port = task->dev->port;
472 SAS_DPRINTK("clearing nexus for port:%d\n",
473 port->id);
474 res = i->dft->lldd_clear_nexus_port(port);
475 if (res == TMF_RESP_FUNC_COMPLETE) {
476 SAS_DPRINTK("clear nexus port:%d "
477 "succeeded\n", port->id);
478 task->task_done(task);
479 sas_scsi_clear_queue_port(&error_q,
480 port);
481 goto Again;
482 }
483 }
484 if (i->dft->lldd_clear_nexus_ha) {
485 SAS_DPRINTK("clear nexus ha\n");
486 res = i->dft->lldd_clear_nexus_ha(ha);
487 if (res == TMF_RESP_FUNC_COMPLETE) {
488 SAS_DPRINTK("clear nexus ha "
489 "succeeded\n");
490 task->task_done(task);
491 goto out;
492 }
493 }
494 /* If we are here -- this means that no amount
495 * of effort could recover from errors. Quite
496 * possibly the HA just disappeared.
497 */
498 SAS_DPRINTK("error from device %llx, LUN %x "
499 "couldn't be recovered in any way\n",
500 SAS_ADDR(task->dev->sas_addr),
501 cmd->device->lun);
502
503 task->task_done(task);
504 goto clear_q;
505 }
506 }
507out:
Darrick J. Wongf4563932006-10-30 15:18:39 -0800508 scsi_eh_flush_done_q(&ha->eh_done_q);
James Bottomley2908d772006-08-29 09:22:51 -0500509 SAS_DPRINTK("--- Exit %s\n", __FUNCTION__);
510 return;
511clear_q:
512 SAS_DPRINTK("--- Exit %s -- clear_q\n", __FUNCTION__);
513 list_for_each_entry_safe(cmd, n, &error_q, eh_entry) {
514 struct sas_task *task = TO_SAS_TASK(cmd);
515 list_del_init(&cmd->eh_entry);
516 task->task_done(task);
517 }
518}
519
520enum scsi_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *cmd)
521{
522 struct sas_task *task = TO_SAS_TASK(cmd);
523 unsigned long flags;
524
525 if (!task) {
Darrick J. Wongf4563932006-10-30 15:18:39 -0800526 SAS_DPRINTK("command 0x%p, task 0x%p, gone: EH_HANDLED\n",
James Bottomley2908d772006-08-29 09:22:51 -0500527 cmd, task);
528 return EH_HANDLED;
529 }
530
531 spin_lock_irqsave(&task->task_state_lock, flags);
Darrick J. Wongf4563932006-10-30 15:18:39 -0800532 if (task->task_state_flags & SAS_TASK_INITIATOR_ABORTED) {
533 spin_unlock_irqrestore(&task->task_state_lock, flags);
534 SAS_DPRINTK("command 0x%p, task 0x%p, aborted by initiator: "
535 "EH_NOT_HANDLED\n", cmd, task);
536 return EH_NOT_HANDLED;
537 }
James Bottomley2908d772006-08-29 09:22:51 -0500538 if (task->task_state_flags & SAS_TASK_STATE_DONE) {
539 spin_unlock_irqrestore(&task->task_state_lock, flags);
540 SAS_DPRINTK("command 0x%p, task 0x%p, timed out: EH_HANDLED\n",
541 cmd, task);
542 return EH_HANDLED;
543 }
544 task->task_state_flags |= SAS_TASK_STATE_ABORTED;
545 spin_unlock_irqrestore(&task->task_state_lock, flags);
546
547 SAS_DPRINTK("command 0x%p, task 0x%p, timed out: EH_NOT_HANDLED\n",
548 cmd, task);
549
550 return EH_NOT_HANDLED;
551}
552
553struct domain_device *sas_find_dev_by_rphy(struct sas_rphy *rphy)
554{
555 struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent);
556 struct sas_ha_struct *ha = SHOST_TO_SAS_HA(shost);
557 struct domain_device *found_dev = NULL;
558 int i;
559
560 spin_lock(&ha->phy_port_lock);
561 for (i = 0; i < ha->num_phys; i++) {
562 struct asd_sas_port *port = ha->sas_port[i];
563 struct domain_device *dev;
564
565 spin_lock(&port->dev_list_lock);
566 list_for_each_entry(dev, &port->dev_list, dev_list_node) {
567 if (rphy == dev->rphy) {
568 found_dev = dev;
569 spin_unlock(&port->dev_list_lock);
570 goto found;
571 }
572 }
573 spin_unlock(&port->dev_list_lock);
574 }
575 found:
576 spin_unlock(&ha->phy_port_lock);
577
578 return found_dev;
579}
580
581static inline struct domain_device *sas_find_target(struct scsi_target *starget)
582{
583 struct sas_rphy *rphy = dev_to_rphy(starget->dev.parent);
584
585 return sas_find_dev_by_rphy(rphy);
586}
587
588int sas_target_alloc(struct scsi_target *starget)
589{
590 struct domain_device *found_dev = sas_find_target(starget);
591
592 if (!found_dev)
593 return -ENODEV;
594
595 starget->hostdata = found_dev;
596 return 0;
597}
598
599#define SAS_DEF_QD 32
600#define SAS_MAX_QD 64
601
602int sas_slave_configure(struct scsi_device *scsi_dev)
603{
604 struct domain_device *dev = sdev_to_domain_dev(scsi_dev);
605 struct sas_ha_struct *sas_ha;
606
607 BUG_ON(dev->rphy->identify.device_type != SAS_END_DEVICE);
608
609 sas_ha = dev->port->ha;
610
611 sas_read_port_mode_page(scsi_dev);
612
613 if (scsi_dev->tagged_supported) {
614 scsi_set_tag_type(scsi_dev, MSG_SIMPLE_TAG);
615 scsi_activate_tcq(scsi_dev, SAS_DEF_QD);
616 } else {
617 SAS_DPRINTK("device %llx, LUN %x doesn't support "
618 "TCQ\n", SAS_ADDR(dev->sas_addr),
619 scsi_dev->lun);
620 scsi_dev->tagged_supported = 0;
621 scsi_set_tag_type(scsi_dev, 0);
622 scsi_deactivate_tcq(scsi_dev, 1);
623 }
624
625 return 0;
626}
627
628void sas_slave_destroy(struct scsi_device *scsi_dev)
629{
630}
631
632int sas_change_queue_depth(struct scsi_device *scsi_dev, int new_depth)
633{
634 int res = min(new_depth, SAS_MAX_QD);
635
636 if (scsi_dev->tagged_supported)
637 scsi_adjust_queue_depth(scsi_dev, scsi_get_tag_type(scsi_dev),
638 res);
639 else {
640 struct domain_device *dev = sdev_to_domain_dev(scsi_dev);
641 sas_printk("device %llx LUN %x queue depth changed to 1\n",
642 SAS_ADDR(dev->sas_addr),
643 scsi_dev->lun);
644 scsi_adjust_queue_depth(scsi_dev, 0, 1);
645 res = 1;
646 }
647
648 return res;
649}
650
651int sas_change_queue_type(struct scsi_device *scsi_dev, int qt)
652{
653 if (!scsi_dev->tagged_supported)
654 return 0;
655
656 scsi_deactivate_tcq(scsi_dev, 1);
657
658 scsi_set_tag_type(scsi_dev, qt);
659 scsi_activate_tcq(scsi_dev, scsi_dev->queue_depth);
660
661 return qt;
662}
663
664int sas_bios_param(struct scsi_device *scsi_dev,
665 struct block_device *bdev,
666 sector_t capacity, int *hsc)
667{
668 hsc[0] = 255;
669 hsc[1] = 63;
670 sector_div(capacity, 255*63);
671 hsc[2] = capacity;
672
673 return 0;
674}
675
676/* ---------- Task Collector Thread implementation ---------- */
677
678static void sas_queue(struct sas_ha_struct *sas_ha)
679{
680 struct scsi_core *core = &sas_ha->core;
681 unsigned long flags;
682 LIST_HEAD(q);
683 int can_queue;
684 int res;
685 struct sas_internal *i = to_sas_internal(core->shost->transportt);
686
687 spin_lock_irqsave(&core->task_queue_lock, flags);
688 while (!core->queue_thread_kill &&
689 !list_empty(&core->task_queue)) {
690
691 can_queue = sas_ha->lldd_queue_size - core->task_queue_size;
692 if (can_queue >= 0) {
693 can_queue = core->task_queue_size;
694 list_splice_init(&core->task_queue, &q);
695 } else {
696 struct list_head *a, *n;
697
698 can_queue = sas_ha->lldd_queue_size;
699 list_for_each_safe(a, n, &core->task_queue) {
700 list_move_tail(a, &q);
701 if (--can_queue == 0)
702 break;
703 }
704 can_queue = sas_ha->lldd_queue_size;
705 }
706 core->task_queue_size -= can_queue;
707 spin_unlock_irqrestore(&core->task_queue_lock, flags);
708 {
709 struct sas_task *task = list_entry(q.next,
710 struct sas_task,
711 list);
712 list_del_init(&q);
713 res = i->dft->lldd_execute_task(task, can_queue,
714 GFP_KERNEL);
715 if (unlikely(res))
716 __list_add(&q, task->list.prev, &task->list);
717 }
718 spin_lock_irqsave(&core->task_queue_lock, flags);
719 if (res) {
720 list_splice_init(&q, &core->task_queue); /*at head*/
721 core->task_queue_size += can_queue;
722 }
723 }
724 spin_unlock_irqrestore(&core->task_queue_lock, flags);
725}
726
727static DECLARE_COMPLETION(queue_th_comp);
728
729/**
730 * sas_queue_thread -- The Task Collector thread
731 * @_sas_ha: pointer to struct sas_ha
732 */
733static int sas_queue_thread(void *_sas_ha)
734{
735 struct sas_ha_struct *sas_ha = _sas_ha;
736 struct scsi_core *core = &sas_ha->core;
737
738 daemonize("sas_queue_%d", core->shost->host_no);
739 current->flags |= PF_NOFREEZE;
740
741 complete(&queue_th_comp);
742
743 while (1) {
744 down_interruptible(&core->queue_thread_sema);
745 sas_queue(sas_ha);
746 if (core->queue_thread_kill)
747 break;
748 }
749
750 complete(&queue_th_comp);
751
752 return 0;
753}
754
755int sas_init_queue(struct sas_ha_struct *sas_ha)
756{
757 int res;
758 struct scsi_core *core = &sas_ha->core;
759
760 spin_lock_init(&core->task_queue_lock);
761 core->task_queue_size = 0;
762 INIT_LIST_HEAD(&core->task_queue);
763 init_MUTEX_LOCKED(&core->queue_thread_sema);
764
765 res = kernel_thread(sas_queue_thread, sas_ha, 0);
766 if (res >= 0)
767 wait_for_completion(&queue_th_comp);
768
769 return res < 0 ? res : 0;
770}
771
772void sas_shutdown_queue(struct sas_ha_struct *sas_ha)
773{
774 unsigned long flags;
775 struct scsi_core *core = &sas_ha->core;
776 struct sas_task *task, *n;
777
778 init_completion(&queue_th_comp);
779 core->queue_thread_kill = 1;
780 up(&core->queue_thread_sema);
781 wait_for_completion(&queue_th_comp);
782
783 if (!list_empty(&core->task_queue))
784 SAS_DPRINTK("HA: %llx: scsi core task queue is NOT empty!?\n",
785 SAS_ADDR(sas_ha->sas_addr));
786
787 spin_lock_irqsave(&core->task_queue_lock, flags);
788 list_for_each_entry_safe(task, n, &core->task_queue, list) {
789 struct scsi_cmnd *cmd = task->uldd_task;
790
791 list_del_init(&task->list);
792
793 ASSIGN_SAS_TASK(cmd, NULL);
794 sas_free_task(task);
795 cmd->result = DID_ABORT << 16;
796 cmd->scsi_done(cmd);
797 }
798 spin_unlock_irqrestore(&core->task_queue_lock, flags);
799}
800
801EXPORT_SYMBOL_GPL(sas_queuecommand);
802EXPORT_SYMBOL_GPL(sas_target_alloc);
803EXPORT_SYMBOL_GPL(sas_slave_configure);
804EXPORT_SYMBOL_GPL(sas_slave_destroy);
805EXPORT_SYMBOL_GPL(sas_change_queue_depth);
806EXPORT_SYMBOL_GPL(sas_change_queue_type);
807EXPORT_SYMBOL_GPL(sas_bios_param);