LCOV - code coverage report
Current view: top level - lkbce/drivers/scsi - hosts.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 104 264 39.4 %
Date: 2017-01-25 Functions: 9 17 52.9 %

          Line data    Source code
       1             : /*
       2             :  *  hosts.c Copyright (C) 1992 Drew Eckhardt
       3             :  *          Copyright (C) 1993, 1994, 1995 Eric Youngdale
       4             :  *          Copyright (C) 2002-2003 Christoph Hellwig
       5             :  *
       6             :  *  mid to lowlevel SCSI driver interface
       7             :  *      Initial versions: Drew Eckhardt
       8             :  *      Subsequent revisions: Eric Youngdale
       9             :  *
      10             :  *  <drew@colorado.edu>
      11             :  *
      12             :  *  Jiffies wrap fixes (host->resetting), 3 Dec 1998 Andrea Arcangeli
      13             :  *  Added QLOGIC QLA1280 SCSI controller kernel host support. 
      14             :  *     August 4, 1999 Fred Lewis, Intel DuPont
      15             :  *
      16             :  *  Updated to reflect the new initialization scheme for the higher 
      17             :  *  level of scsi drivers (sd/sr/st)
      18             :  *  September 17, 2000 Torben Mathiasen <tmm@image.dk>
      19             :  *
      20             :  *  Restructured scsi_host lists and associated functions.
      21             :  *  September 04, 2002 Mike Anderson (andmike@us.ibm.com)
      22             :  */
      23             : 
      24             : #include <linux/module.h>
      25             : #include <linux/blkdev.h>
      26             : #include <linux/kernel.h>
      27             : #include <linux/kthread.h>
      28             : #include <linux/string.h>
      29             : #include <linux/mm.h>
      30             : #include <linux/init.h>
      31             : #include <linux/completion.h>
      32             : #include <linux/transport_class.h>
      33             : #include <linux/platform_device.h>
      34             : 
      35             : #include <scsi/scsi_device.h>
      36             : #include <scsi/scsi_host.h>
      37             : #include <scsi/scsi_transport.h>
      38             : 
      39             : #include "scsi_priv.h"
      40             : #include "scsi_logging.h"
      41             : 
      42             : 
      43           1 : static atomic_t scsi_host_next_hn;      /* host_no for next new host */
      44             : 
      45             : 
      46             : static void scsi_host_cls_release(struct device *dev)
      47             : {
      48           3 :         put_device(&class_to_shost(dev)->shost_gendev);
      49           1 : }
      50             : 
      51           1 : static struct class shost_class = {
      52             :         .name           = "scsi_host",
      53             :         .dev_release    = scsi_host_cls_release,
      54             : };
      55             : 
      56             : /**
      57             :  *      scsi_host_set_state - Take the given host through the host state model.
      58             :  *      @shost: scsi host to change the state of.
      59             :  *      @state: state to change to.
      60             :  *
      61             :  *      Returns zero if unsuccessful or an error if the requested
      62             :  *      transition is illegal.
      63             :  **/
      64             : int scsi_host_set_state(struct Scsi_Host *shost, enum scsi_host_state state)
      65             : {
      66           2 :         enum scsi_host_state oldstate = shost->shost_state;
      67             : 
      68           2 :         if (state == oldstate)
      69           1 :                 return 0;
      70             : 
      71           1 :         switch (state) {
      72           4 :         case SHOST_CREATED:
      73             :                 /* There are no legal states that come back to
      74             :                  * created.  This is the manually initialised start
      75             :                  * state */
      76           1 :                 goto illegal;
      77           1 : 
      78           3 :         case SHOST_RUNNING:
      79             :                 switch (oldstate) {
      80           3 :                 case SHOST_CREATED:
      81           3 :                 case SHOST_RECOVERY:
      82           1 :                         break;
      83           2 :                 default:
      84           2 :                         goto illegal;
      85           1 :                 }
      86           1 :                 break;
      87           1 : 
      88           3 :         case SHOST_RECOVERY:
      89             :                 switch (oldstate) {
      90           3 :                 case SHOST_RUNNING:
      91           1 :                         break;
      92           2 :                 default:
      93           2 :                         goto illegal;
      94             :                 }
      95           1 :                 break;
      96           1 : 
      97           3 :         case SHOST_CANCEL:
      98             :                 switch (oldstate) {
      99           3 :                 case SHOST_CREATED:
     100           3 :                 case SHOST_RUNNING:
     101           3 :                 case SHOST_CANCEL_RECOVERY:
     102           1 :                         break;
     103           2 :                 default:
     104           2 :                         goto illegal;
     105           1 :                 }
     106           2 :                 break;
     107           1 : 
     108           3 :         case SHOST_DEL:
     109             :                 switch (oldstate) {
     110           3 :                 case SHOST_CANCEL:
     111           3 :                 case SHOST_DEL_RECOVERY:
     112           1 :                         break;
     113           2 :                 default:
     114           2 :                         goto illegal;
     115           1 :                 }
     116           1 :                 break;
     117           1 : 
     118           3 :         case SHOST_CANCEL_RECOVERY:
     119             :                 switch (oldstate) {
     120           3 :                 case SHOST_CANCEL:
     121           3 :                 case SHOST_RECOVERY:
     122           1 :                         break;
     123           2 :                 default:
     124           2 :                         goto illegal;
     125           1 :                 }
     126           1 :                 break;
     127           1 : 
     128           3 :         case SHOST_DEL_RECOVERY:
     129             :                 switch (oldstate) {
     130           3 :                 case SHOST_CANCEL_RECOVERY:
     131           1 :                         break;
     132           2 :                 default:
     133           2 :                         goto illegal;
     134             :                 }
     135           1 :                 break;
     136           1 :         }
     137           1 :         shost->shost_state = state;
     138           2 :         return 0;
     139           1 : 
     140             :  illegal:
     141             :         SCSI_LOG_ERROR_RECOVERY(1,
     142             :                                 shost_printk(KERN_ERR, shost,
     143             :                                              "Illegal host state transition"
     144             :                                              "%s->%s\n",
     145             :                                              scsi_host_state_name(oldstate),
     146             :                                              scsi_host_state_name(state)));
     147           1 :         return -EINVAL;
     148             : }
     149             : EXPORT_SYMBOL(scsi_host_set_state);
     150             : 
     151             : /**
     152             :  * scsi_remove_host - remove a scsi host
     153             :  * @shost:      a pointer to a scsi host to remove
     154             :  **/
     155             : void scsi_remove_host(struct Scsi_Host *shost)
     156             : {
     157           0 :         unsigned long flags;
     158           0 :         mutex_lock(&shost->scan_mutex);
     159           0 :         spin_lock_irqsave(shost->host_lock, flags);
     160           0 :         if (scsi_host_set_state(shost, SHOST_CANCEL))
     161           0 :                 if (scsi_host_set_state(shost, SHOST_CANCEL_RECOVERY)) {
     162           0 :                         spin_unlock_irqrestore(shost->host_lock, flags);
     163           0 :                         mutex_unlock(&shost->scan_mutex);
     164           0 :                         return;
     165             :                 }
     166           0 :         spin_unlock_irqrestore(shost->host_lock, flags);
     167           0 :         scsi_forget_host(shost);
     168           0 :         mutex_unlock(&shost->scan_mutex);
     169           0 :         scsi_proc_host_rm(shost);
     170             : 
     171           0 :         spin_lock_irqsave(shost->host_lock, flags);
     172           0 :         if (scsi_host_set_state(shost, SHOST_DEL))
     173           0 :                 BUG_ON(scsi_host_set_state(shost, SHOST_DEL_RECOVERY));
     174           0 :         spin_unlock_irqrestore(shost->host_lock, flags);
     175             : 
     176           0 :         transport_unregister_device(&shost->shost_gendev);
     177           0 :         device_unregister(&shost->shost_dev);
     178           0 :         device_del(&shost->shost_gendev);
     179           0 : }
     180             : EXPORT_SYMBOL(scsi_remove_host);
     181             : 
     182             : /**
     183             :  * scsi_add_host_with_dma - add a scsi host with dma device
     184             :  * @shost:      scsi host pointer to add
     185             :  * @dev:        a struct device of type scsi class
     186             :  * @dma_dev:    dma device for the host
     187             :  *
     188             :  * Note: You rarely need to worry about this unless you're in a
     189             :  * virtualised host environments, so use the simpler scsi_add_host()
     190             :  * function instead.
     191             :  *
     192             :  * Return value: 
     193             :  *      0 on success / != 0 for error
     194             :  **/
     195             : int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev,
     196             :                            struct device *dma_dev)
     197           0 : {
     198           0 :         struct scsi_host_template *sht = shost->hostt;
     199           0 :         int error = -EINVAL;
     200           0 : 
     201           0 :         printk(KERN_INFO "scsi%d : %s\n", shost->host_no,
     202             :                         sht->info ? sht->info(shost) : sht->name);
     203             : 
     204           0 :         if (!shost->can_queue) {
     205           0 :                 printk(KERN_ERR "%s: can_queue = 0 no longer supported\n",
     206             :                                 sht->name);
     207           0 :                 goto fail;
     208             :         }
     209             : 
     210           0 :         error = scsi_setup_command_freelist(shost);
     211           0 :         if (error)
     212           0 :                 goto fail;
     213             : 
     214           0 :         if (!shost->shost_gendev.parent)
     215           0 :                 shost->shost_gendev.parent = dev ? dev : &platform_bus;
     216           0 :         shost->dma_dev = dma_dev;
     217             : 
     218           0 :         error = device_add(&shost->shost_gendev);
     219           0 :         if (error)
     220           0 :                 goto out;
     221             : 
     222           0 :         scsi_host_set_state(shost, SHOST_RUNNING);
     223           0 :         get_device(shost->shost_gendev.parent);
     224             : 
     225           0 :         error = device_add(&shost->shost_dev);
     226           0 :         if (error)
     227           0 :                 goto out_del_gendev;
     228             : 
     229           0 :         get_device(&shost->shost_gendev);
     230             : 
     231           0 :         if (shost->transportt->host_size) {
     232           0 :                 shost->shost_data = kzalloc(shost->transportt->host_size,
     233             :                                          GFP_KERNEL);
     234           0 :                 if (shost->shost_data == NULL) {
     235           0 :                         error = -ENOMEM;
     236           0 :                         goto out_del_dev;
     237             :                 }
     238             :         }
     239             : 
     240           0 :         if (shost->transportt->create_work_queue) {
     241           0 :                 snprintf(shost->work_q_name, sizeof(shost->work_q_name),
     242             :                          "scsi_wq_%d", shost->host_no);
     243           0 :                 shost->work_q = create_singlethread_workqueue(
     244             :                                         shost->work_q_name);
     245           0 :                 if (!shost->work_q) {
     246           0 :                         error = -EINVAL;
     247           0 :                         goto out_free_shost_data;
     248             :                 }
     249             :         }
     250             : 
     251           0 :         error = scsi_sysfs_add_host(shost);
     252           0 :         if (error)
     253           0 :                 goto out_destroy_host;
     254             : 
     255           0 :         scsi_proc_host_add(shost);
     256           0 :         return error;
     257           0 : 
     258             :  out_destroy_host:
     259           0 :         if (shost->work_q)
     260           0 :                 destroy_workqueue(shost->work_q);
     261             :  out_free_shost_data:
     262           0 :         kfree(shost->shost_data);
     263             :  out_del_dev:
     264           0 :         device_del(&shost->shost_dev);
     265           0 :  out_del_gendev:
     266           0 :         device_del(&shost->shost_gendev);
     267             :  out:
     268           0 :         scsi_destroy_command_freelist(shost);
     269             :  fail:
     270           0 :         return error;
     271             : }
     272             : EXPORT_SYMBOL(scsi_add_host_with_dma);
     273             : 
     274             : static void scsi_host_dev_release(struct device *dev)
     275             : {
     276           4 :         struct Scsi_Host *shost = dev_to_shost(dev);
     277           2 :         struct device *parent = dev->parent;
     278           1 : 
     279           2 :         scsi_proc_hostdir_rm(shost->hostt);
     280             : 
     281           3 :         if (shost->ehandler)
     282           1 :                 kthread_stop(shost->ehandler);
     283           3 :         if (shost->work_q)
     284           1 :                 destroy_workqueue(shost->work_q);
     285           3 :         if (shost->uspace_req_q) {
     286           2 :                 kfree(shost->uspace_req_q->queuedata);
     287           2 :                 scsi_free_queue(shost->uspace_req_q);
     288             :         }
     289             : 
     290           6 :         scsi_destroy_command_freelist(shost);
     291           3 :         if (shost->bqt)
     292           1 :                 blk_free_tags(shost->bqt);
     293             : 
     294           2 :         kfree(shost->shost_data);
     295             : 
     296           2 :         if (parent)
     297           1 :                 put_device(parent);
     298           1 :         kfree(shost);
     299           1 : }
     300             : 
     301           1 : static struct device_type scsi_host_type = {
     302             :         .name =         "scsi_host",
     303             :         .release =      scsi_host_dev_release,
     304             : };
     305             : 
     306             : /**
     307             :  * scsi_host_alloc - register a scsi host adapter instance.
     308             :  * @sht:        pointer to scsi host template
     309             :  * @privsize:   extra bytes to allocate for driver
     310             :  *
     311             :  * Note:
     312             :  *      Allocate a new Scsi_Host and perform basic initialization.
     313             :  *      The host is not published to the scsi midlayer until scsi_add_host
     314             :  *      is called.
     315             :  *
     316             :  * Return value:
     317             :  *      Pointer to a new Scsi_Host
     318             :  **/
     319             : struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
     320             : {
     321           0 :         struct Scsi_Host *shost;
     322           0 :         gfp_t gfp_mask = GFP_KERNEL;
     323           0 :         int rval;
     324           0 : 
     325           0 :         if (sht->unchecked_isa_dma && privsize)
     326           0 :                 gfp_mask |= __GFP_DMA;
     327           0 : 
     328           0 :         shost = kzalloc(sizeof(struct Scsi_Host) + privsize, gfp_mask);
     329           0 :         if (!shost)
     330           0 :                 return NULL;
     331           0 : 
     332           0 :         shost->host_lock = &shost->default_lock;
     333           0 :         spin_lock_init(shost->host_lock);
     334           0 :         shost->shost_state = SHOST_CREATED;
     335           0 :         INIT_LIST_HEAD(&shost->__devices);
     336           0 :         INIT_LIST_HEAD(&shost->__targets);
     337           0 :         INIT_LIST_HEAD(&shost->eh_cmd_q);
     338           0 :         INIT_LIST_HEAD(&shost->starved_list);
     339           0 :         init_waitqueue_head(&shost->host_wait);
     340             : 
     341           0 :         mutex_init(&shost->scan_mutex);
     342             : 
     343             :         /*
     344             :          * subtract one because we increment first then return, but we need to
     345             :          * know what the next host number was before increment
     346             :          */
     347           0 :         shost->host_no = atomic_inc_return(&scsi_host_next_hn) - 1;
     348           0 :         shost->dma_channel = 0xff;
     349             : 
     350             :         /* These three are default values which can be overridden */
     351           0 :         shost->max_channel = 0;
     352           0 :         shost->max_id = 8;
     353           0 :         shost->max_lun = 8;
     354             : 
     355             :         /* Give each shost a default transportt */
     356           0 :         shost->transportt = &blank_transport_template;
     357             : 
     358             :         /*
     359             :          * All drivers right now should be able to handle 12 byte
     360             :          * commands.  Every so often there are requests for 16 byte
     361             :          * commands, but individual low-level drivers need to certify that
     362             :          * they actually do something sensible with such commands.
     363             :          */
     364           0 :         shost->max_cmd_len = 12;
     365           0 :         shost->hostt = sht;
     366           0 :         shost->this_id = sht->this_id;
     367           0 :         shost->can_queue = sht->can_queue;
     368           0 :         shost->sg_tablesize = sht->sg_tablesize;
     369           0 :         shost->cmd_per_lun = sht->cmd_per_lun;
     370           0 :         shost->unchecked_isa_dma = sht->unchecked_isa_dma;
     371           0 :         shost->use_clustering = sht->use_clustering;
     372           0 :         shost->ordered_tag = sht->ordered_tag;
     373             : 
     374           0 :         if (sht->supported_mode == MODE_UNKNOWN)
     375             :                 /* means we didn't set it ... default to INITIATOR */
     376           0 :                 shost->active_mode = MODE_INITIATOR;
     377             :         else
     378           0 :                 shost->active_mode = sht->supported_mode;
     379             : 
     380           0 :         if (sht->max_host_blocked)
     381           0 :                 shost->max_host_blocked = sht->max_host_blocked;
     382             :         else
     383           0 :                 shost->max_host_blocked = SCSI_DEFAULT_HOST_BLOCKED;
     384             : 
     385             :         /*
     386             :          * If the driver imposes no hard sector transfer limit, start at
     387             :          * machine infinity initially.
     388             :          */
     389           0 :         if (sht->max_sectors)
     390           0 :                 shost->max_sectors = sht->max_sectors;
     391             :         else
     392           0 :                 shost->max_sectors = SCSI_DEFAULT_MAX_SECTORS;
     393             : 
     394             :         /*
     395             :          * assume a 4GB boundary, if not set
     396             :          */
     397           0 :         if (sht->dma_boundary)
     398           0 :                 shost->dma_boundary = sht->dma_boundary;
     399             :         else
     400           0 :                 shost->dma_boundary = 0xffffffff;
     401             : 
     402           0 :         device_initialize(&shost->shost_gendev);
     403           0 :         dev_set_name(&shost->shost_gendev, "host%d", shost->host_no);
     404             : #ifndef CONFIG_SYSFS_DEPRECATED
     405           0 :         shost->shost_gendev.bus = &scsi_bus_type;
     406             : #endif
     407           0 :         shost->shost_gendev.type = &scsi_host_type;
     408             : 
     409           0 :         device_initialize(&shost->shost_dev);
     410           0 :         shost->shost_dev.parent = &shost->shost_gendev;
     411           0 :         shost->shost_dev.class = &shost_class;
     412           0 :         dev_set_name(&shost->shost_dev, "host%d", shost->host_no);
     413           0 :         shost->shost_dev.groups = scsi_sysfs_shost_attr_groups;
     414             : 
     415           0 :         shost->ehandler = kthread_run(scsi_error_handler, shost,
     416             :                         "scsi_eh_%d", shost->host_no);
     417           0 :         if (IS_ERR(shost->ehandler)) {
     418           0 :                 rval = PTR_ERR(shost->ehandler);
     419           0 :                 goto fail_kfree;
     420             :         }
     421             : 
     422           0 :         scsi_proc_hostdir_add(shost->hostt);
     423           0 :         return shost;
     424           0 : 
     425             :  fail_kfree:
     426           0 :         kfree(shost);
     427           0 :         return NULL;
     428             : }
     429             : EXPORT_SYMBOL(scsi_host_alloc);
     430             : 
     431             : struct Scsi_Host *scsi_register(struct scsi_host_template *sht, int privsize)
     432             : {
     433           0 :         struct Scsi_Host *shost = scsi_host_alloc(sht, privsize);
     434           0 : 
     435           0 :         if (!sht->detect) {
     436           0 :                 printk(KERN_WARNING "scsi_register() called on new-style "
     437             :                                     "template for driver %s\n", sht->name);
     438           0 :                 dump_stack();
     439             :         }
     440             : 
     441           0 :         if (shost)
     442           0 :                 list_add_tail(&shost->sht_legacy_list, &sht->legacy_hosts);
     443           0 :         return shost;
     444             : }
     445             : EXPORT_SYMBOL(scsi_register);
     446             : 
     447             : void scsi_unregister(struct Scsi_Host *shost)
     448             : {
     449           0 :         list_del(&shost->sht_legacy_list);
     450           0 :         scsi_host_put(shost);
     451           0 : }
     452             : EXPORT_SYMBOL(scsi_unregister);
     453             : 
     454             : static int __scsi_host_match(struct device *dev, void *data)
     455             : {
     456           0 :         struct Scsi_Host *p;
     457           0 :         unsigned short *hostnum = (unsigned short *)data;
     458           0 : 
     459           0 :         p = class_to_shost(dev);
     460           0 :         return p->host_no == *hostnum;
     461             : }
     462             : 
     463             : /**
     464             :  * scsi_host_lookup - get a reference to a Scsi_Host by host no
     465             :  * @hostnum:    host number to locate
     466             :  *
     467             :  * Return value:
     468             :  *      A pointer to located Scsi_Host or NULL.
     469             :  *
     470             :  *      The caller must do a scsi_host_put() to drop the reference
     471             :  *      that scsi_host_get() took. The put_device() below dropped
     472             :  *      the reference from class_find_device().
     473             :  **/
     474             : struct Scsi_Host *scsi_host_lookup(unsigned short hostnum)
     475             : {
     476           2 :         struct device *cdev;
     477           4 :         struct Scsi_Host *shost = NULL;
     478           2 : 
     479           2 :         cdev = class_find_device(&shost_class, NULL, &hostnum,
     480             :                                  __scsi_host_match);
     481           4 :         if (cdev) {
     482           6 :                 shost = scsi_host_get(class_to_shost(cdev));
     483           2 :                 put_device(cdev);
     484             :         }
     485           4 :         return shost;
     486             : }
     487             : EXPORT_SYMBOL(scsi_host_lookup);
     488             : 
     489             : /**
     490             :  * scsi_host_get - inc a Scsi_Host ref count
     491             :  * @shost:      Pointer to Scsi_Host to inc.
     492             :  **/
     493             : struct Scsi_Host *scsi_host_get(struct Scsi_Host *shost)
     494             : {
     495          14 :         if ((shost->shost_state == SHOST_DEL) ||
     496             :                 !get_device(&shost->shost_gendev))
     497           4 :                 return NULL;
     498           2 :         return shost;
     499             : }
     500             : EXPORT_SYMBOL(scsi_host_get);
     501             : 
     502             : /**
     503             :  * scsi_host_put - dec a Scsi_Host ref count
     504             :  * @shost:      Pointer to Scsi_Host to dec.
     505             :  **/
     506             : void scsi_host_put(struct Scsi_Host *shost)
     507             : {
     508           4 :         put_device(&shost->shost_gendev);
     509           4 : }
     510             : EXPORT_SYMBOL(scsi_host_put);
     511             : 
     512             : int scsi_init_hosts(void)
     513             : {
     514           3 :         return class_register(&shost_class);
     515           1 : }
     516             : 
     517             : void scsi_exit_hosts(void)
     518             : {
     519           4 :         class_unregister(&shost_class);
     520           4 : }
     521             : 
     522             : int scsi_is_host_device(const struct device *dev)
     523             : {
     524         962 :         return dev->type == &scsi_host_type;
     525             : }
     526             : EXPORT_SYMBOL(scsi_is_host_device);
     527             : 
     528             : /**
     529             :  * scsi_queue_work - Queue work to the Scsi_Host workqueue.
     530             :  * @shost:      Pointer to Scsi_Host.
     531             :  * @work:       Work to queue for execution.
     532             :  *
     533             :  * Return value:
     534             :  *      1 - work queued for execution
     535             :  *      0 - work is already queued
     536             :  *      -EINVAL - work queue doesn't exist
     537             :  **/
     538             : int scsi_queue_work(struct Scsi_Host *shost, struct work_struct *work)
     539             : {
     540           0 :         if (unlikely(!shost->work_q)) {
     541           0 :                 printk(KERN_ERR
     542             :                         "ERROR: Scsi host '%s' attempted to queue scsi-work, "
     543             :                         "when no workqueue created.\n", shost->hostt->name);
     544           0 :                 dump_stack();
     545             : 
     546           0 :                 return -EINVAL;
     547             :         }
     548             : 
     549           0 :         return queue_work(shost->work_q, work);
     550             : }
     551             : EXPORT_SYMBOL_GPL(scsi_queue_work);
     552             : 
     553             : /**
     554             :  * scsi_flush_work - Flush a Scsi_Host's workqueue.
     555             :  * @shost:      Pointer to Scsi_Host.
     556             :  **/
     557             : void scsi_flush_work(struct Scsi_Host *shost)
     558             : {
     559           0 :         if (!shost->work_q) {
     560           0 :                 printk(KERN_ERR
     561             :                         "ERROR: Scsi host '%s' attempted to flush scsi-work, "
     562             :                         "when no workqueue created.\n", shost->hostt->name);
     563           0 :                 dump_stack();
     564           0 :                 return;
     565             :         }
     566             : 
     567           0 :         flush_workqueue(shost->work_q);
     568           0 : }
     569             : EXPORT_SYMBOL_GPL(scsi_flush_work);

Generated by: LCOV version 1.10