linux/drivers/scsi/libsas/sas_discover.c
<<
>>
Prefs
   1/*
   2 * Serial Attached SCSI (SAS) Discover process
   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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  22 *
  23 */
  24
  25#include <linux/scatterlist.h>
  26#include <linux/slab.h>
  27#include <linux/async.h>
  28#include <scsi/scsi_host.h>
  29#include <scsi/scsi_eh.h>
  30#include "sas_internal.h"
  31
  32#include <scsi/scsi_transport.h>
  33#include <scsi/scsi_transport_sas.h>
  34#include <scsi/sas_ata.h>
  35#include "../scsi_sas_internal.h"
  36
  37/* ---------- Basic task processing for discovery purposes ---------- */
  38
  39void sas_init_dev(struct domain_device *dev)
  40{
  41        switch (dev->dev_type) {
  42        case SAS_END_DEVICE:
  43                INIT_LIST_HEAD(&dev->ssp_dev.eh_list_node);
  44                break;
  45        case SAS_EDGE_EXPANDER_DEVICE:
  46        case SAS_FANOUT_EXPANDER_DEVICE:
  47                INIT_LIST_HEAD(&dev->ex_dev.children);
  48                mutex_init(&dev->ex_dev.cmd_mutex);
  49                break;
  50        default:
  51                break;
  52        }
  53}
  54
  55/* ---------- Domain device discovery ---------- */
  56
  57/**
  58 * sas_get_port_device -- Discover devices which caused port creation
  59 * @port: pointer to struct sas_port of interest
  60 *
  61 * Devices directly attached to a HA port, have no parent.  This is
  62 * how we know they are (domain) "root" devices.  All other devices
  63 * do, and should have their "parent" pointer set appropriately as
  64 * soon as a child device is discovered.
  65 */
  66static int sas_get_port_device(struct asd_sas_port *port)
  67{
  68        struct asd_sas_phy *phy;
  69        struct sas_rphy *rphy;
  70        struct domain_device *dev;
  71        int rc = -ENODEV;
  72
  73        dev = sas_alloc_device();
  74        if (!dev)
  75                return -ENOMEM;
  76
  77        spin_lock_irq(&port->phy_list_lock);
  78        if (list_empty(&port->phy_list)) {
  79                spin_unlock_irq(&port->phy_list_lock);
  80                sas_put_device(dev);
  81                return -ENODEV;
  82        }
  83        phy = container_of(port->phy_list.next, struct asd_sas_phy, port_phy_el);
  84        spin_lock(&phy->frame_rcvd_lock);
  85        memcpy(dev->frame_rcvd, phy->frame_rcvd, min(sizeof(dev->frame_rcvd),
  86                                             (size_t)phy->frame_rcvd_size));
  87        spin_unlock(&phy->frame_rcvd_lock);
  88        spin_unlock_irq(&port->phy_list_lock);
  89
  90        if (dev->frame_rcvd[0] == 0x34 && port->oob_mode == SATA_OOB_MODE) {
  91                struct dev_to_host_fis *fis =
  92                        (struct dev_to_host_fis *) dev->frame_rcvd;
  93                if (fis->interrupt_reason == 1 && fis->lbal == 1 &&
  94                    fis->byte_count_low==0x69 && fis->byte_count_high == 0x96
  95                    && (fis->device & ~0x10) == 0)
  96                        dev->dev_type = SAS_SATA_PM;
  97                else
  98                        dev->dev_type = SAS_SATA_DEV;
  99                dev->tproto = SAS_PROTOCOL_SATA;
 100        } else {
 101                struct sas_identify_frame *id =
 102                        (struct sas_identify_frame *) dev->frame_rcvd;
 103                dev->dev_type = id->dev_type;
 104                dev->iproto = id->initiator_bits;
 105                dev->tproto = id->target_bits;
 106        }
 107
 108        sas_init_dev(dev);
 109
 110        dev->port = port;
 111        switch (dev->dev_type) {
 112        case SAS_SATA_DEV:
 113                rc = sas_ata_init(dev);
 114                if (rc) {
 115                        rphy = NULL;
 116                        break;
 117                }
 118                /* fall through */
 119        case SAS_END_DEVICE:
 120                rphy = sas_end_device_alloc(port->port);
 121                break;
 122        case SAS_EDGE_EXPANDER_DEVICE:
 123                rphy = sas_expander_alloc(port->port,
 124                                          SAS_EDGE_EXPANDER_DEVICE);
 125                break;
 126        case SAS_FANOUT_EXPANDER_DEVICE:
 127                rphy = sas_expander_alloc(port->port,
 128                                          SAS_FANOUT_EXPANDER_DEVICE);
 129                break;
 130        default:
 131                printk("ERROR: Unidentified device type %d\n", dev->dev_type);
 132                rphy = NULL;
 133                break;
 134        }
 135
 136        if (!rphy) {
 137                sas_put_device(dev);
 138                return rc;
 139        }
 140
 141        rphy->identify.phy_identifier = phy->phy->identify.phy_identifier;
 142        memcpy(dev->sas_addr, port->attached_sas_addr, SAS_ADDR_SIZE);
 143        sas_fill_in_rphy(dev, rphy);
 144        sas_hash_addr(dev->hashed_sas_addr, dev->sas_addr);
 145        port->port_dev = dev;
 146        dev->linkrate = port->linkrate;
 147        dev->min_linkrate = port->linkrate;
 148        dev->max_linkrate = port->linkrate;
 149        dev->pathways = port->num_phys;
 150        memset(port->disc.fanout_sas_addr, 0, SAS_ADDR_SIZE);
 151        memset(port->disc.eeds_a, 0, SAS_ADDR_SIZE);
 152        memset(port->disc.eeds_b, 0, SAS_ADDR_SIZE);
 153        port->disc.max_level = 0;
 154        sas_device_set_phy(dev, port->port);
 155
 156        dev->rphy = rphy;
 157        get_device(&dev->rphy->dev);
 158
 159        if (dev_is_sata(dev) || dev->dev_type == SAS_END_DEVICE)
 160                list_add_tail(&dev->disco_list_node, &port->disco_list);
 161        else {
 162                spin_lock_irq(&port->dev_list_lock);
 163                list_add_tail(&dev->dev_list_node, &port->dev_list);
 164                spin_unlock_irq(&port->dev_list_lock);
 165        }
 166
 167        spin_lock_irq(&port->phy_list_lock);
 168        list_for_each_entry(phy, &port->phy_list, port_phy_el)
 169                sas_phy_set_target(phy, dev);
 170        spin_unlock_irq(&port->phy_list_lock);
 171
 172        return 0;
 173}
 174
 175/* ---------- Discover and Revalidate ---------- */
 176
 177int sas_notify_lldd_dev_found(struct domain_device *dev)
 178{
 179        int res = 0;
 180        struct sas_ha_struct *sas_ha = dev->port->ha;
 181        struct Scsi_Host *shost = sas_ha->core.shost;
 182        struct sas_internal *i = to_sas_internal(shost->transportt);
 183
 184        if (!i->dft->lldd_dev_found)
 185                return 0;
 186
 187        res = i->dft->lldd_dev_found(dev);
 188        if (res) {
 189                printk("sas: driver on pcidev %s cannot handle "
 190                       "device %llx, error:%d\n",
 191                       dev_name(sas_ha->dev),
 192                       SAS_ADDR(dev->sas_addr), res);
 193        }
 194        set_bit(SAS_DEV_FOUND, &dev->state);
 195        kref_get(&dev->kref);
 196        return res;
 197}
 198
 199
 200void sas_notify_lldd_dev_gone(struct domain_device *dev)
 201{
 202        struct sas_ha_struct *sas_ha = dev->port->ha;
 203        struct Scsi_Host *shost = sas_ha->core.shost;
 204        struct sas_internal *i = to_sas_internal(shost->transportt);
 205
 206        if (!i->dft->lldd_dev_gone)
 207                return;
 208
 209        if (test_and_clear_bit(SAS_DEV_FOUND, &dev->state)) {
 210                i->dft->lldd_dev_gone(dev);
 211                sas_put_device(dev);
 212        }
 213}
 214
 215static void sas_probe_devices(struct work_struct *work)
 216{
 217        struct domain_device *dev, *n;
 218        struct sas_discovery_event *ev = to_sas_discovery_event(work);
 219        struct asd_sas_port *port = ev->port;
 220
 221        clear_bit(DISCE_PROBE, &port->disc.pending);
 222
 223        /* devices must be domain members before link recovery and probe */
 224        list_for_each_entry(dev, &port->disco_list, disco_list_node) {
 225                spin_lock_irq(&port->dev_list_lock);
 226                list_add_tail(&dev->dev_list_node, &port->dev_list);
 227                spin_unlock_irq(&port->dev_list_lock);
 228        }
 229
 230        sas_probe_sata(port);
 231
 232        list_for_each_entry_safe(dev, n, &port->disco_list, disco_list_node) {
 233                int err;
 234
 235                err = sas_rphy_add(dev->rphy);
 236                if (err)
 237                        sas_fail_probe(dev, __func__, err);
 238                else
 239                        list_del_init(&dev->disco_list_node);
 240        }
 241}
 242
 243static void sas_suspend_devices(struct work_struct *work)
 244{
 245        struct asd_sas_phy *phy;
 246        struct domain_device *dev;
 247        struct sas_discovery_event *ev = to_sas_discovery_event(work);
 248        struct asd_sas_port *port = ev->port;
 249        struct Scsi_Host *shost = port->ha->core.shost;
 250        struct sas_internal *si = to_sas_internal(shost->transportt);
 251
 252        clear_bit(DISCE_SUSPEND, &port->disc.pending);
 253
 254        sas_suspend_sata(port);
 255
 256        /* lldd is free to forget the domain_device across the
 257         * suspension, we force the issue here to keep the reference
 258         * counts aligned
 259         */
 260        list_for_each_entry(dev, &port->dev_list, dev_list_node)
 261                sas_notify_lldd_dev_gone(dev);
 262
 263        /* we are suspending, so we know events are disabled and
 264         * phy_list is not being mutated
 265         */
 266        list_for_each_entry(phy, &port->phy_list, port_phy_el) {
 267                if (si->dft->lldd_port_formed)
 268                        si->dft->lldd_port_deformed(phy);
 269                phy->suspended = 1;
 270                port->suspended = 1;
 271        }
 272}
 273
 274static void sas_resume_devices(struct work_struct *work)
 275{
 276        struct sas_discovery_event *ev = to_sas_discovery_event(work);
 277        struct asd_sas_port *port = ev->port;
 278
 279        clear_bit(DISCE_RESUME, &port->disc.pending);
 280
 281        sas_resume_sata(port);
 282}
 283
 284/**
 285 * sas_discover_end_dev -- discover an end device (SSP, etc)
 286 * @end: pointer to domain device of interest
 287 *
 288 * See comment in sas_discover_sata().
 289 */
 290int sas_discover_end_dev(struct domain_device *dev)
 291{
 292        int res;
 293
 294        res = sas_notify_lldd_dev_found(dev);
 295        if (res)
 296                return res;
 297        sas_discover_event(dev->port, DISCE_PROBE);
 298
 299        return 0;
 300}
 301
 302/* ---------- Device registration and unregistration ---------- */
 303
 304void sas_free_device(struct kref *kref)
 305{
 306        struct domain_device *dev = container_of(kref, typeof(*dev), kref);
 307
 308        put_device(&dev->rphy->dev);
 309        dev->rphy = NULL;
 310
 311        if (dev->parent)
 312                sas_put_device(dev->parent);
 313
 314        sas_port_put_phy(dev->phy);
 315        dev->phy = NULL;
 316
 317        /* remove the phys and ports, everything else should be gone */
 318        if (dev->dev_type == SAS_EDGE_EXPANDER_DEVICE || dev->dev_type == SAS_FANOUT_EXPANDER_DEVICE)
 319                kfree(dev->ex_dev.ex_phy);
 320
 321        if (dev_is_sata(dev) && dev->sata_dev.ap) {
 322                ata_sas_port_destroy(dev->sata_dev.ap);
 323                dev->sata_dev.ap = NULL;
 324        }
 325
 326        kfree(dev);
 327}
 328
 329static void sas_unregister_common_dev(struct asd_sas_port *port, struct domain_device *dev)
 330{
 331        struct sas_ha_struct *ha = port->ha;
 332
 333        sas_notify_lldd_dev_gone(dev);
 334        if (!dev->parent)
 335                dev->port->port_dev = NULL;
 336        else
 337                list_del_init(&dev->siblings);
 338
 339        spin_lock_irq(&port->dev_list_lock);
 340        list_del_init(&dev->dev_list_node);
 341        if (dev_is_sata(dev))
 342                sas_ata_end_eh(dev->sata_dev.ap);
 343        spin_unlock_irq(&port->dev_list_lock);
 344
 345        spin_lock_irq(&ha->lock);
 346        if (dev->dev_type == SAS_END_DEVICE &&
 347            !list_empty(&dev->ssp_dev.eh_list_node)) {
 348                list_del_init(&dev->ssp_dev.eh_list_node);
 349                ha->eh_active--;
 350        }
 351        spin_unlock_irq(&ha->lock);
 352
 353        sas_put_device(dev);
 354}
 355
 356static void sas_destruct_devices(struct work_struct *work)
 357{
 358        struct domain_device *dev, *n;
 359        struct sas_discovery_event *ev = to_sas_discovery_event(work);
 360        struct asd_sas_port *port = ev->port;
 361
 362        clear_bit(DISCE_DESTRUCT, &port->disc.pending);
 363
 364        list_for_each_entry_safe(dev, n, &port->destroy_list, disco_list_node) {
 365                list_del_init(&dev->disco_list_node);
 366
 367                sas_remove_children(&dev->rphy->dev);
 368                sas_rphy_delete(dev->rphy);
 369                sas_unregister_common_dev(port, dev);
 370        }
 371}
 372
 373void sas_unregister_dev(struct asd_sas_port *port, struct domain_device *dev)
 374{
 375        if (!test_bit(SAS_DEV_DESTROY, &dev->state) &&
 376            !list_empty(&dev->disco_list_node)) {
 377                /* this rphy never saw sas_rphy_add */
 378                list_del_init(&dev->disco_list_node);
 379                sas_rphy_free(dev->rphy);
 380                sas_unregister_common_dev(port, dev);
 381                return;
 382        }
 383
 384        if (!test_and_set_bit(SAS_DEV_DESTROY, &dev->state)) {
 385                sas_rphy_unlink(dev->rphy);
 386                list_move_tail(&dev->disco_list_node, &port->destroy_list);
 387                sas_discover_event(dev->port, DISCE_DESTRUCT);
 388        }
 389}
 390
 391void sas_unregister_domain_devices(struct asd_sas_port *port, int gone)
 392{
 393        struct domain_device *dev, *n;
 394
 395        list_for_each_entry_safe_reverse(dev, n, &port->dev_list, dev_list_node) {
 396                if (gone)
 397                        set_bit(SAS_DEV_GONE, &dev->state);
 398                sas_unregister_dev(port, dev);
 399        }
 400
 401        list_for_each_entry_safe(dev, n, &port->disco_list, disco_list_node)
 402                sas_unregister_dev(port, dev);
 403
 404        port->port->rphy = NULL;
 405
 406}
 407
 408void sas_device_set_phy(struct domain_device *dev, struct sas_port *port)
 409{
 410        struct sas_ha_struct *ha;
 411        struct sas_phy *new_phy;
 412
 413        if (!dev)
 414                return;
 415
 416        ha = dev->port->ha;
 417        new_phy = sas_port_get_phy(port);
 418
 419        /* pin and record last seen phy */
 420        spin_lock_irq(&ha->phy_port_lock);
 421        if (new_phy) {
 422                sas_port_put_phy(dev->phy);
 423                dev->phy = new_phy;
 424        }
 425        spin_unlock_irq(&ha->phy_port_lock);
 426}
 427
 428/* ---------- Discovery and Revalidation ---------- */
 429
 430/**
 431 * sas_discover_domain -- discover the domain
 432 * @port: port to the domain of interest
 433 *
 434 * NOTE: this process _must_ quit (return) as soon as any connection
 435 * errors are encountered.  Connection recovery is done elsewhere.
 436 * Discover process only interrogates devices in order to discover the
 437 * domain.
 438 */
 439static void sas_discover_domain(struct work_struct *work)
 440{
 441        struct domain_device *dev;
 442        int error = 0;
 443        struct sas_discovery_event *ev = to_sas_discovery_event(work);
 444        struct asd_sas_port *port = ev->port;
 445
 446        clear_bit(DISCE_DISCOVER_DOMAIN, &port->disc.pending);
 447
 448        if (port->port_dev)
 449                return;
 450
 451        error = sas_get_port_device(port);
 452        if (error)
 453                return;
 454        dev = port->port_dev;
 455
 456        SAS_DPRINTK("DOING DISCOVERY on port %d, pid:%d\n", port->id,
 457                    task_pid_nr(current));
 458
 459        switch (dev->dev_type) {
 460        case SAS_END_DEVICE:
 461                error = sas_discover_end_dev(dev);
 462                break;
 463        case SAS_EDGE_EXPANDER_DEVICE:
 464        case SAS_FANOUT_EXPANDER_DEVICE:
 465                error = sas_discover_root_expander(dev);
 466                break;
 467        case SAS_SATA_DEV:
 468        case SAS_SATA_PM:
 469#ifdef CONFIG_SCSI_SAS_ATA
 470                error = sas_discover_sata(dev);
 471                break;
 472#else
 473                SAS_DPRINTK("ATA device seen but CONFIG_SCSI_SAS_ATA=N so cannot attach\n");
 474                /* Fall through */
 475#endif
 476        default:
 477                error = -ENXIO;
 478                SAS_DPRINTK("unhandled device %d\n", dev->dev_type);
 479                break;
 480        }
 481
 482        if (error) {
 483                sas_rphy_free(dev->rphy);
 484                list_del_init(&dev->disco_list_node);
 485                spin_lock_irq(&port->dev_list_lock);
 486                list_del_init(&dev->dev_list_node);
 487                spin_unlock_irq(&port->dev_list_lock);
 488
 489                sas_put_device(dev);
 490                port->port_dev = NULL;
 491        }
 492
 493        SAS_DPRINTK("DONE DISCOVERY on port %d, pid:%d, result:%d\n", port->id,
 494                    task_pid_nr(current), error);
 495}
 496
 497static void sas_revalidate_domain(struct work_struct *work)
 498{
 499        int res = 0;
 500        struct sas_discovery_event *ev = to_sas_discovery_event(work);
 501        struct asd_sas_port *port = ev->port;
 502        struct sas_ha_struct *ha = port->ha;
 503        struct domain_device *ddev = port->port_dev;
 504
 505        /* prevent revalidation from finding sata links in recovery */
 506        mutex_lock(&ha->disco_mutex);
 507        if (test_bit(SAS_HA_ATA_EH_ACTIVE, &ha->state)) {
 508                SAS_DPRINTK("REVALIDATION DEFERRED on port %d, pid:%d\n",
 509                            port->id, task_pid_nr(current));
 510                goto out;
 511        }
 512
 513        clear_bit(DISCE_REVALIDATE_DOMAIN, &port->disc.pending);
 514
 515        SAS_DPRINTK("REVALIDATING DOMAIN on port %d, pid:%d\n", port->id,
 516                    task_pid_nr(current));
 517
 518        if (ddev && (ddev->dev_type == SAS_FANOUT_EXPANDER_DEVICE ||
 519                     ddev->dev_type == SAS_EDGE_EXPANDER_DEVICE))
 520                res = sas_ex_revalidate_domain(ddev);
 521
 522        SAS_DPRINTK("done REVALIDATING DOMAIN on port %d, pid:%d, res 0x%x\n",
 523                    port->id, task_pid_nr(current), res);
 524 out:
 525        mutex_unlock(&ha->disco_mutex);
 526}
 527
 528/* ---------- Events ---------- */
 529
 530static void sas_chain_work(struct sas_ha_struct *ha, struct sas_work *sw)
 531{
 532        /* chained work is not subject to SA_HA_DRAINING or
 533         * SAS_HA_REGISTERED, because it is either submitted in the
 534         * workqueue, or known to be submitted from a context that is
 535         * not racing against draining
 536         */
 537        scsi_queue_work(ha->core.shost, &sw->work);
 538}
 539
 540static void sas_chain_event(int event, unsigned long *pending,
 541                            struct sas_work *sw,
 542                            struct sas_ha_struct *ha)
 543{
 544        if (!test_and_set_bit(event, pending)) {
 545                unsigned long flags;
 546
 547                spin_lock_irqsave(&ha->lock, flags);
 548                sas_chain_work(ha, sw);
 549                spin_unlock_irqrestore(&ha->lock, flags);
 550        }
 551}
 552
 553int sas_discover_event(struct asd_sas_port *port, enum discover_event ev)
 554{
 555        struct sas_discovery *disc;
 556
 557        if (!port)
 558                return 0;
 559        disc = &port->disc;
 560
 561        BUG_ON(ev >= DISC_NUM_EVENTS);
 562
 563        sas_chain_event(ev, &disc->pending, &disc->disc_work[ev].work, port->ha);
 564
 565        return 0;
 566}
 567
 568/**
 569 * sas_init_disc -- initialize the discovery struct in the port
 570 * @port: pointer to struct port
 571 *
 572 * Called when the ports are being initialized.
 573 */
 574void sas_init_disc(struct sas_discovery *disc, struct asd_sas_port *port)
 575{
 576        int i;
 577
 578        static const work_func_t sas_event_fns[DISC_NUM_EVENTS] = {
 579                [DISCE_DISCOVER_DOMAIN] = sas_discover_domain,
 580                [DISCE_REVALIDATE_DOMAIN] = sas_revalidate_domain,
 581                [DISCE_PROBE] = sas_probe_devices,
 582                [DISCE_SUSPEND] = sas_suspend_devices,
 583                [DISCE_RESUME] = sas_resume_devices,
 584                [DISCE_DESTRUCT] = sas_destruct_devices,
 585        };
 586
 587        disc->pending = 0;
 588        for (i = 0; i < DISC_NUM_EVENTS; i++) {
 589                INIT_SAS_WORK(&disc->disc_work[i].work, sas_event_fns[i]);
 590                disc->disc_work[i].port = port;
 591        }
 592}
 593