.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * hosts.c Copyright (C) 1992 Drew Eckhardt |
---|
3 | 4 | * Copyright (C) 1993, 1994, 1995 Eric Youngdale |
---|
.. | .. |
---|
37 | 38 | #include <scsi/scsi_device.h> |
---|
38 | 39 | #include <scsi/scsi_host.h> |
---|
39 | 40 | #include <scsi/scsi_transport.h> |
---|
| 41 | +#include <scsi/scsi_cmnd.h> |
---|
40 | 42 | |
---|
41 | 43 | #include "scsi_priv.h" |
---|
42 | 44 | #include "scsi_logging.h" |
---|
.. | .. |
---|
178 | 180 | scsi_forget_host(shost); |
---|
179 | 181 | mutex_unlock(&shost->scan_mutex); |
---|
180 | 182 | scsi_proc_host_rm(shost); |
---|
| 183 | + scsi_proc_hostdir_rm(shost->hostt); |
---|
181 | 184 | |
---|
182 | 185 | spin_lock_irqsave(shost->host_lock, flags); |
---|
183 | 186 | if (scsi_host_set_state(shost, SHOST_DEL)) |
---|
.. | .. |
---|
226 | 229 | if (error) |
---|
227 | 230 | goto fail; |
---|
228 | 231 | |
---|
229 | | - if (shost_use_blk_mq(shost)) { |
---|
230 | | - error = scsi_mq_setup_tags(shost); |
---|
231 | | - if (error) |
---|
232 | | - goto fail; |
---|
233 | | - } else { |
---|
234 | | - shost->bqt = blk_init_tags(shost->can_queue, |
---|
235 | | - shost->hostt->tag_alloc_policy); |
---|
236 | | - if (!shost->bqt) { |
---|
237 | | - error = -ENOMEM; |
---|
238 | | - goto fail; |
---|
239 | | - } |
---|
240 | | - } |
---|
| 232 | + error = scsi_mq_setup_tags(shost); |
---|
| 233 | + if (error) |
---|
| 234 | + goto fail; |
---|
241 | 235 | |
---|
242 | 236 | if (!shost->shost_gendev.parent) |
---|
243 | 237 | shost->shost_gendev.parent = dev ? dev : &platform_bus; |
---|
.. | .. |
---|
282 | 276 | if (shost->transportt->create_work_queue) { |
---|
283 | 277 | snprintf(shost->work_q_name, sizeof(shost->work_q_name), |
---|
284 | 278 | "scsi_wq_%d", shost->host_no); |
---|
285 | | - shost->work_q = create_singlethread_workqueue( |
---|
286 | | - shost->work_q_name); |
---|
| 279 | + shost->work_q = alloc_workqueue("%s", |
---|
| 280 | + WQ_SYSFS | __WQ_LEGACY | WQ_MEM_RECLAIM | WQ_UNBOUND, |
---|
| 281 | + 1, shost->work_q_name); |
---|
| 282 | + |
---|
287 | 283 | if (!shost->work_q) { |
---|
288 | 284 | error = -EINVAL; |
---|
289 | | - goto out_free_shost_data; |
---|
| 285 | + goto out_del_dev; |
---|
290 | 286 | } |
---|
291 | 287 | } |
---|
292 | 288 | |
---|
293 | 289 | error = scsi_sysfs_add_host(shost); |
---|
294 | 290 | if (error) |
---|
295 | | - goto out_destroy_host; |
---|
| 291 | + goto out_del_dev; |
---|
296 | 292 | |
---|
297 | 293 | scsi_proc_host_add(shost); |
---|
298 | 294 | scsi_autopm_put_host(shost); |
---|
299 | 295 | return error; |
---|
300 | 296 | |
---|
301 | | - out_destroy_host: |
---|
302 | | - if (shost->work_q) |
---|
303 | | - destroy_workqueue(shost->work_q); |
---|
304 | | - out_free_shost_data: |
---|
305 | | - kfree(shost->shost_data); |
---|
| 297 | + /* |
---|
| 298 | + * Any host allocation in this function will be freed in |
---|
| 299 | + * scsi_host_dev_release(). |
---|
| 300 | + */ |
---|
306 | 301 | out_del_dev: |
---|
307 | 302 | device_del(&shost->shost_dev); |
---|
308 | 303 | out_del_gendev: |
---|
.. | .. |
---|
317 | 312 | pm_runtime_disable(&shost->shost_gendev); |
---|
318 | 313 | pm_runtime_set_suspended(&shost->shost_gendev); |
---|
319 | 314 | pm_runtime_put_noidle(&shost->shost_gendev); |
---|
320 | | - if (shost_use_blk_mq(shost)) |
---|
321 | | - scsi_mq_destroy_tags(shost); |
---|
322 | 315 | fail: |
---|
323 | 316 | return error; |
---|
324 | 317 | } |
---|
.. | .. |
---|
329 | 322 | struct Scsi_Host *shost = dev_to_shost(dev); |
---|
330 | 323 | struct device *parent = dev->parent; |
---|
331 | 324 | |
---|
332 | | - scsi_proc_hostdir_rm(shost->hostt); |
---|
333 | | - |
---|
334 | | - /* Wait for functions invoked through call_rcu(&shost->rcu, ...) */ |
---|
| 325 | + /* Wait for functions invoked through call_rcu(&scmd->rcu, ...) */ |
---|
335 | 326 | rcu_barrier(); |
---|
336 | 327 | |
---|
337 | 328 | if (shost->tmf_work_q) |
---|
.. | .. |
---|
352 | 343 | kfree(dev_name(&shost->shost_dev)); |
---|
353 | 344 | } |
---|
354 | 345 | |
---|
355 | | - if (shost_use_blk_mq(shost)) { |
---|
356 | | - if (shost->tag_set.tags) |
---|
357 | | - scsi_mq_destroy_tags(shost); |
---|
358 | | - } else { |
---|
359 | | - if (shost->bqt) |
---|
360 | | - blk_free_tags(shost->bqt); |
---|
361 | | - } |
---|
| 346 | + if (shost->tag_set.tags) |
---|
| 347 | + scsi_mq_destroy_tags(shost); |
---|
362 | 348 | |
---|
363 | 349 | kfree(shost->shost_data); |
---|
364 | 350 | |
---|
.. | .. |
---|
441 | 427 | shost->sg_prot_tablesize = sht->sg_prot_tablesize; |
---|
442 | 428 | shost->cmd_per_lun = sht->cmd_per_lun; |
---|
443 | 429 | shost->unchecked_isa_dma = sht->unchecked_isa_dma; |
---|
444 | | - shost->use_clustering = sht->use_clustering; |
---|
445 | 430 | shost->no_write_same = sht->no_write_same; |
---|
| 431 | + shost->host_tagset = sht->host_tagset; |
---|
446 | 432 | |
---|
447 | 433 | if (shost_eh_deadline == -1 || !sht->eh_host_reset_handler) |
---|
448 | 434 | shost->eh_deadline = -1; |
---|
.. | .. |
---|
474 | 460 | else |
---|
475 | 461 | shost->max_sectors = SCSI_DEFAULT_MAX_SECTORS; |
---|
476 | 462 | |
---|
| 463 | + if (sht->max_segment_size) |
---|
| 464 | + shost->max_segment_size = sht->max_segment_size; |
---|
| 465 | + else |
---|
| 466 | + shost->max_segment_size = BLK_MAX_SEGMENT_SIZE; |
---|
| 467 | + |
---|
477 | 468 | /* |
---|
478 | 469 | * assume a 4GB boundary, if not set |
---|
479 | 470 | */ |
---|
.. | .. |
---|
482 | 473 | else |
---|
483 | 474 | shost->dma_boundary = 0xffffffff; |
---|
484 | 475 | |
---|
485 | | - shost->use_blk_mq = scsi_use_blk_mq || shost->hostt->force_blk_mq; |
---|
| 476 | + if (sht->virt_boundary_mask) |
---|
| 477 | + shost->virt_boundary_mask = sht->virt_boundary_mask; |
---|
486 | 478 | |
---|
487 | 479 | device_initialize(&shost->shost_gendev); |
---|
488 | 480 | dev_set_name(&shost->shost_gendev, "host%d", shost->host_no); |
---|
.. | .. |
---|
506 | 498 | } |
---|
507 | 499 | |
---|
508 | 500 | shost->tmf_work_q = alloc_workqueue("scsi_tmf_%d", |
---|
509 | | - WQ_UNBOUND | WQ_MEM_RECLAIM, |
---|
| 501 | + WQ_UNBOUND | WQ_MEM_RECLAIM | WQ_SYSFS, |
---|
510 | 502 | 1, shost->host_no); |
---|
511 | 503 | if (!shost->tmf_work_q) { |
---|
512 | 504 | shost_printk(KERN_WARNING, shost, |
---|
.. | .. |
---|
575 | 567 | } |
---|
576 | 568 | EXPORT_SYMBOL(scsi_host_get); |
---|
577 | 569 | |
---|
| 570 | +static bool scsi_host_check_in_flight(struct request *rq, void *data, |
---|
| 571 | + bool reserved) |
---|
| 572 | +{ |
---|
| 573 | + int *count = data; |
---|
| 574 | + struct scsi_cmnd *cmd = blk_mq_rq_to_pdu(rq); |
---|
| 575 | + |
---|
| 576 | + if (test_bit(SCMD_STATE_INFLIGHT, &cmd->state)) |
---|
| 577 | + (*count)++; |
---|
| 578 | + |
---|
| 579 | + return true; |
---|
| 580 | +} |
---|
| 581 | + |
---|
578 | 582 | /** |
---|
579 | 583 | * scsi_host_busy - Return the host busy counter |
---|
580 | 584 | * @shost: Pointer to Scsi_Host to inc. |
---|
581 | 585 | **/ |
---|
582 | 586 | int scsi_host_busy(struct Scsi_Host *shost) |
---|
583 | 587 | { |
---|
584 | | - return atomic_read(&shost->host_busy); |
---|
| 588 | + int cnt = 0; |
---|
| 589 | + |
---|
| 590 | + blk_mq_tagset_busy_iter(&shost->tag_set, |
---|
| 591 | + scsi_host_check_in_flight, &cnt); |
---|
| 592 | + return cnt; |
---|
585 | 593 | } |
---|
586 | 594 | EXPORT_SYMBOL(scsi_host_busy); |
---|
587 | 595 | |
---|
.. | .. |
---|
654 | 662 | flush_workqueue(shost->work_q); |
---|
655 | 663 | } |
---|
656 | 664 | EXPORT_SYMBOL_GPL(scsi_flush_work); |
---|
| 665 | + |
---|
| 666 | +static bool complete_all_cmds_iter(struct request *rq, void *data, bool rsvd) |
---|
| 667 | +{ |
---|
| 668 | + struct scsi_cmnd *scmd = blk_mq_rq_to_pdu(rq); |
---|
| 669 | + int status = *(int *)data; |
---|
| 670 | + |
---|
| 671 | + scsi_dma_unmap(scmd); |
---|
| 672 | + scmd->result = status << 16; |
---|
| 673 | + scmd->scsi_done(scmd); |
---|
| 674 | + return true; |
---|
| 675 | +} |
---|
| 676 | + |
---|
| 677 | +/** |
---|
| 678 | + * scsi_host_complete_all_commands - Terminate all running commands |
---|
| 679 | + * @shost: Scsi Host on which commands should be terminated |
---|
| 680 | + * @status: Status to be set for the terminated commands |
---|
| 681 | + * |
---|
| 682 | + * There is no protection against modification of the number |
---|
| 683 | + * of outstanding commands. It is the responsibility of the |
---|
| 684 | + * caller to ensure that concurrent I/O submission and/or |
---|
| 685 | + * completion is stopped when calling this function. |
---|
| 686 | + */ |
---|
| 687 | +void scsi_host_complete_all_commands(struct Scsi_Host *shost, int status) |
---|
| 688 | +{ |
---|
| 689 | + blk_mq_tagset_busy_iter(&shost->tag_set, complete_all_cmds_iter, |
---|
| 690 | + &status); |
---|
| 691 | +} |
---|
| 692 | +EXPORT_SYMBOL_GPL(scsi_host_complete_all_commands); |
---|
| 693 | + |
---|
| 694 | +struct scsi_host_busy_iter_data { |
---|
| 695 | + bool (*fn)(struct scsi_cmnd *, void *, bool); |
---|
| 696 | + void *priv; |
---|
| 697 | +}; |
---|
| 698 | + |
---|
| 699 | +static bool __scsi_host_busy_iter_fn(struct request *req, void *priv, |
---|
| 700 | + bool reserved) |
---|
| 701 | +{ |
---|
| 702 | + struct scsi_host_busy_iter_data *iter_data = priv; |
---|
| 703 | + struct scsi_cmnd *sc = blk_mq_rq_to_pdu(req); |
---|
| 704 | + |
---|
| 705 | + return iter_data->fn(sc, iter_data->priv, reserved); |
---|
| 706 | +} |
---|
| 707 | + |
---|
| 708 | +/** |
---|
| 709 | + * scsi_host_busy_iter - Iterate over all busy commands |
---|
| 710 | + * @shost: Pointer to Scsi_Host. |
---|
| 711 | + * @fn: Function to call on each busy command |
---|
| 712 | + * @priv: Data pointer passed to @fn |
---|
| 713 | + * |
---|
| 714 | + * If locking against concurrent command completions is required |
---|
| 715 | + * ithas to be provided by the caller |
---|
| 716 | + **/ |
---|
| 717 | +void scsi_host_busy_iter(struct Scsi_Host *shost, |
---|
| 718 | + bool (*fn)(struct scsi_cmnd *, void *, bool), |
---|
| 719 | + void *priv) |
---|
| 720 | +{ |
---|
| 721 | + struct scsi_host_busy_iter_data iter_data = { |
---|
| 722 | + .fn = fn, |
---|
| 723 | + .priv = priv, |
---|
| 724 | + }; |
---|
| 725 | + |
---|
| 726 | + blk_mq_tagset_busy_iter(&shost->tag_set, __scsi_host_busy_iter_fn, |
---|
| 727 | + &iter_data); |
---|
| 728 | +} |
---|
| 729 | +EXPORT_SYMBOL_GPL(scsi_host_busy_iter); |
---|