linux/drivers/scsi/libsas/sas_init.c
<<
>>
Prefs
   1/*
   2 * Serial Attached SCSI (SAS) Transport Layer initialization
   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 <linux/module.h>
  27#include <linux/slab.h>
  28#include <linux/init.h>
  29#include <linux/device.h>
  30#include <linux/spinlock.h>
  31#include <scsi/sas_ata.h>
  32#include <scsi/scsi_host.h>
  33#include <scsi/scsi_device.h>
  34#include <scsi/scsi_transport.h>
  35#include <scsi/scsi_transport_sas.h>
  36
  37#include "sas_internal.h"
  38
  39#include "../scsi_sas_internal.h"
  40
  41static struct kmem_cache *sas_task_cache;
  42
  43struct sas_task *sas_alloc_task(gfp_t flags)
  44{
  45        struct sas_task *task = kmem_cache_zalloc(sas_task_cache, flags);
  46
  47        if (task) {
  48                spin_lock_init(&task->task_state_lock);
  49                task->task_state_flags = SAS_TASK_STATE_PENDING;
  50        }
  51
  52        return task;
  53}
  54EXPORT_SYMBOL_GPL(sas_alloc_task);
  55
  56struct sas_task *sas_alloc_slow_task(gfp_t flags)
  57{
  58        struct sas_task *task = sas_alloc_task(flags);
  59        struct sas_task_slow *slow = kmalloc(sizeof(*slow), flags);
  60
  61        if (!task || !slow) {
  62                if (task)
  63                        kmem_cache_free(sas_task_cache, task);
  64                kfree(slow);
  65                return NULL;
  66        }
  67
  68        task->slow_task = slow;
  69        init_timer(&slow->timer);
  70        init_completion(&slow->completion);
  71
  72        return task;
  73}
  74EXPORT_SYMBOL_GPL(sas_alloc_slow_task);
  75
  76void sas_free_task(struct sas_task *task)
  77{
  78        if (task) {
  79                kfree(task->slow_task);
  80                kmem_cache_free(sas_task_cache, task);
  81        }
  82}
  83EXPORT_SYMBOL_GPL(sas_free_task);
  84
  85/*------------ SAS addr hash -----------*/
  86void sas_hash_addr(u8 *hashed, const u8 *sas_addr)
  87{
  88        const u32 poly = 0x00DB2777;
  89        u32     r = 0;
  90        int     i;
  91
  92        for (i = 0; i < 8; i++) {
  93                int b;
  94                for (b = 7; b >= 0; b--) {
  95                        r <<= 1;
  96                        if ((1 << b) & sas_addr[i]) {
  97                                if (!(r & 0x01000000))
  98                                        r ^= poly;
  99                        } else if (r & 0x01000000)
 100                                r ^= poly;
 101                }
 102        }
 103
 104        hashed[0] = (r >> 16) & 0xFF;
 105        hashed[1] = (r >> 8) & 0xFF ;
 106        hashed[2] = r & 0xFF;
 107}
 108
 109
 110/* ---------- HA events ---------- */
 111
 112void sas_hae_reset(struct work_struct *work)
 113{
 114        struct sas_ha_event *ev = to_sas_ha_event(work);
 115        struct sas_ha_struct *ha = ev->ha;
 116
 117        clear_bit(HAE_RESET, &ha->pending);
 118}
 119
 120int sas_register_ha(struct sas_ha_struct *sas_ha)
 121{
 122        int error = 0;
 123
 124        mutex_init(&sas_ha->disco_mutex);
 125        spin_lock_init(&sas_ha->phy_port_lock);
 126        sas_hash_addr(sas_ha->hashed_sas_addr, sas_ha->sas_addr);
 127
 128        set_bit(SAS_HA_REGISTERED, &sas_ha->state);
 129        spin_lock_init(&sas_ha->lock);
 130        mutex_init(&sas_ha->drain_mutex);
 131        init_waitqueue_head(&sas_ha->eh_wait_q);
 132        INIT_LIST_HEAD(&sas_ha->defer_q);
 133        INIT_LIST_HEAD(&sas_ha->eh_dev_q);
 134
 135        error = sas_register_phys(sas_ha);
 136        if (error) {
 137                printk(KERN_NOTICE "couldn't register sas phys:%d\n", error);
 138                return error;
 139        }
 140
 141        error = sas_register_ports(sas_ha);
 142        if (error) {
 143                printk(KERN_NOTICE "couldn't register sas ports:%d\n", error);
 144                goto Undo_phys;
 145        }
 146
 147        error = sas_init_events(sas_ha);
 148        if (error) {
 149                printk(KERN_NOTICE "couldn't start event thread:%d\n", error);
 150                goto Undo_ports;
 151        }
 152
 153        INIT_LIST_HEAD(&sas_ha->eh_done_q);
 154        INIT_LIST_HEAD(&sas_ha->eh_ata_q);
 155
 156        return 0;
 157
 158Undo_ports:
 159        sas_unregister_ports(sas_ha);
 160Undo_phys:
 161
 162        return error;
 163}
 164
 165static void sas_disable_events(struct sas_ha_struct *sas_ha)
 166{
 167        /* Set the state to unregistered to avoid further unchained
 168         * events to be queued, and flush any in-progress drainers
 169         */
 170        mutex_lock(&sas_ha->drain_mutex);
 171        spin_lock_irq(&sas_ha->lock);
 172        clear_bit(SAS_HA_REGISTERED, &sas_ha->state);
 173        spin_unlock_irq(&sas_ha->lock);
 174        __sas_drain_work(sas_ha);
 175        mutex_unlock(&sas_ha->drain_mutex);
 176}
 177
 178int sas_unregister_ha(struct sas_ha_struct *sas_ha)
 179{
 180        sas_disable_events(sas_ha);
 181        sas_unregister_ports(sas_ha);
 182
 183        /* flush unregistration work */
 184        mutex_lock(&sas_ha->drain_mutex);
 185        __sas_drain_work(sas_ha);
 186        mutex_unlock(&sas_ha->drain_mutex);
 187
 188        return 0;
 189}
 190
 191static int sas_get_linkerrors(struct sas_phy *phy)
 192{
 193        if (scsi_is_sas_phy_local(phy)) {
 194                struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
 195                struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(shost);
 196                struct asd_sas_phy *asd_phy = sas_ha->sas_phy[phy->number];
 197                struct sas_internal *i =
 198                        to_sas_internal(sas_ha->core.shost->transportt);
 199
 200                return i->dft->lldd_control_phy(asd_phy, PHY_FUNC_GET_EVENTS, NULL);
 201        }
 202
 203        return sas_smp_get_phy_events(phy);
 204}
 205
 206int sas_try_ata_reset(struct asd_sas_phy *asd_phy)
 207{
 208        struct domain_device *dev = NULL;
 209
 210        /* try to route user requested link resets through libata */
 211        if (asd_phy->port)
 212                dev = asd_phy->port->port_dev;
 213
 214        /* validate that dev has been probed */
 215        if (dev)
 216                dev = sas_find_dev_by_rphy(dev->rphy);
 217
 218        if (dev && dev_is_sata(dev)) {
 219                sas_ata_schedule_reset(dev);
 220                sas_ata_wait_eh(dev);
 221                return 0;
 222        }
 223
 224        return -ENODEV;
 225}
 226
 227/**
 228 * transport_sas_phy_reset - reset a phy and permit libata to manage the link
 229 *
 230 * phy reset request via sysfs in host workqueue context so we know we
 231 * can block on eh and safely traverse the domain_device topology
 232 */
 233static int transport_sas_phy_reset(struct sas_phy *phy, int hard_reset)
 234{
 235        enum phy_func reset_type;
 236
 237        if (hard_reset)
 238                reset_type = PHY_FUNC_HARD_RESET;
 239        else
 240                reset_type = PHY_FUNC_LINK_RESET;
 241
 242        if (scsi_is_sas_phy_local(phy)) {
 243                struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
 244                struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(shost);
 245                struct asd_sas_phy *asd_phy = sas_ha->sas_phy[phy->number];
 246                struct sas_internal *i =
 247                        to_sas_internal(sas_ha->core.shost->transportt);
 248
 249                if (!hard_reset && sas_try_ata_reset(asd_phy) == 0)
 250                        return 0;
 251                return i->dft->lldd_control_phy(asd_phy, reset_type, NULL);
 252        } else {
 253                struct sas_rphy *rphy = dev_to_rphy(phy->dev.parent);
 254                struct domain_device *ddev = sas_find_dev_by_rphy(rphy);
 255                struct domain_device *ata_dev = sas_ex_to_ata(ddev, phy->number);
 256
 257                if (ata_dev && !hard_reset) {
 258                        sas_ata_schedule_reset(ata_dev);
 259                        sas_ata_wait_eh(ata_dev);
 260                        return 0;
 261                } else
 262                        return sas_smp_phy_control(ddev, phy->number, reset_type, NULL);
 263        }
 264}
 265
 266static int sas_phy_enable(struct sas_phy *phy, int enable)
 267{
 268        int ret;
 269        enum phy_func cmd;
 270
 271        if (enable)
 272                cmd = PHY_FUNC_LINK_RESET;
 273        else
 274                cmd = PHY_FUNC_DISABLE;
 275
 276        if (scsi_is_sas_phy_local(phy)) {
 277                struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
 278                struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(shost);
 279                struct asd_sas_phy *asd_phy = sas_ha->sas_phy[phy->number];
 280                struct sas_internal *i =
 281                        to_sas_internal(sas_ha->core.shost->transportt);
 282
 283                if (enable)
 284                        ret = transport_sas_phy_reset(phy, 0);
 285                else
 286                        ret = i->dft->lldd_control_phy(asd_phy, cmd, NULL);
 287        } else {
 288                struct sas_rphy *rphy = dev_to_rphy(phy->dev.parent);
 289                struct domain_device *ddev = sas_find_dev_by_rphy(rphy);
 290
 291                if (enable)
 292                        ret = transport_sas_phy_reset(phy, 0);
 293                else
 294                        ret = sas_smp_phy_control(ddev, phy->number, cmd, NULL);
 295        }
 296        return ret;
 297}
 298
 299int sas_phy_reset(struct sas_phy *phy, int hard_reset)
 300{
 301        int ret;
 302        enum phy_func reset_type;
 303
 304        if (!phy->enabled)
 305                return -ENODEV;
 306
 307        if (hard_reset)
 308                reset_type = PHY_FUNC_HARD_RESET;
 309        else
 310                reset_type = PHY_FUNC_LINK_RESET;
 311
 312        if (scsi_is_sas_phy_local(phy)) {
 313                struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
 314                struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(shost);
 315                struct asd_sas_phy *asd_phy = sas_ha->sas_phy[phy->number];
 316                struct sas_internal *i =
 317                        to_sas_internal(sas_ha->core.shost->transportt);
 318
 319                ret = i->dft->lldd_control_phy(asd_phy, reset_type, NULL);
 320        } else {
 321                struct sas_rphy *rphy = dev_to_rphy(phy->dev.parent);
 322                struct domain_device *ddev = sas_find_dev_by_rphy(rphy);
 323                ret = sas_smp_phy_control(ddev, phy->number, reset_type, NULL);
 324        }
 325        return ret;
 326}
 327
 328int sas_set_phy_speed(struct sas_phy *phy,
 329                      struct sas_phy_linkrates *rates)
 330{
 331        int ret;
 332
 333        if ((rates->minimum_linkrate &&
 334             rates->minimum_linkrate > phy->maximum_linkrate) ||
 335            (rates->maximum_linkrate &&
 336             rates->maximum_linkrate < phy->minimum_linkrate))
 337                return -EINVAL;
 338
 339        if (rates->minimum_linkrate &&
 340            rates->minimum_linkrate < phy->minimum_linkrate_hw)
 341                rates->minimum_linkrate = phy->minimum_linkrate_hw;
 342
 343        if (rates->maximum_linkrate &&
 344            rates->maximum_linkrate > phy->maximum_linkrate_hw)
 345                rates->maximum_linkrate = phy->maximum_linkrate_hw;
 346
 347        if (scsi_is_sas_phy_local(phy)) {
 348                struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
 349                struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(shost);
 350                struct asd_sas_phy *asd_phy = sas_ha->sas_phy[phy->number];
 351                struct sas_internal *i =
 352                        to_sas_internal(sas_ha->core.shost->transportt);
 353
 354                ret = i->dft->lldd_control_phy(asd_phy, PHY_FUNC_SET_LINK_RATE,
 355                                               rates);
 356        } else {
 357                struct sas_rphy *rphy = dev_to_rphy(phy->dev.parent);
 358                struct domain_device *ddev = sas_find_dev_by_rphy(rphy);
 359                ret = sas_smp_phy_control(ddev, phy->number,
 360                                          PHY_FUNC_LINK_RESET, rates);
 361
 362        }
 363
 364        return ret;
 365}
 366
 367void sas_prep_resume_ha(struct sas_ha_struct *ha)
 368{
 369        int i;
 370
 371        set_bit(SAS_HA_REGISTERED, &ha->state);
 372
 373        /* clear out any stale link events/data from the suspension path */
 374        for (i = 0; i < ha->num_phys; i++) {
 375                struct asd_sas_phy *phy = ha->sas_phy[i];
 376
 377                memset(phy->attached_sas_addr, 0, SAS_ADDR_SIZE);
 378                phy->port_events_pending = 0;
 379                phy->phy_events_pending = 0;
 380                phy->frame_rcvd_size = 0;
 381        }
 382}
 383EXPORT_SYMBOL(sas_prep_resume_ha);
 384
 385static int phys_suspended(struct sas_ha_struct *ha)
 386{
 387        int i, rc = 0;
 388
 389        for (i = 0; i < ha->num_phys; i++) {
 390                struct asd_sas_phy *phy = ha->sas_phy[i];
 391
 392                if (phy->suspended)
 393                        rc++;
 394        }
 395
 396        return rc;
 397}
 398
 399void sas_resume_ha(struct sas_ha_struct *ha)
 400{
 401        const unsigned long tmo = msecs_to_jiffies(25000);
 402        int i;
 403
 404        /* deform ports on phys that did not resume
 405         * at this point we may be racing the phy coming back (as posted
 406         * by the lldd).  So we post the event and once we are in the
 407         * libsas context check that the phy remains suspended before
 408         * tearing it down.
 409         */
 410        i = phys_suspended(ha);
 411        if (i)
 412                dev_info(ha->dev, "waiting up to 25 seconds for %d phy%s to resume\n",
 413                         i, i > 1 ? "s" : "");
 414        wait_event_timeout(ha->eh_wait_q, phys_suspended(ha) == 0, tmo);
 415        for (i = 0; i < ha->num_phys; i++) {
 416                struct asd_sas_phy *phy = ha->sas_phy[i];
 417
 418                if (phy->suspended) {
 419                        dev_warn(&phy->phy->dev, "resume timeout\n");
 420                        sas_notify_phy_event(phy, PHYE_RESUME_TIMEOUT);
 421                }
 422        }
 423
 424        /* all phys are back up or timed out, turn on i/o so we can
 425         * flush out disks that did not return
 426         */
 427        scsi_unblock_requests(ha->core.shost);
 428        sas_drain_work(ha);
 429}
 430EXPORT_SYMBOL(sas_resume_ha);
 431
 432void sas_suspend_ha(struct sas_ha_struct *ha)
 433{
 434        int i;
 435
 436        sas_disable_events(ha);
 437        scsi_block_requests(ha->core.shost);
 438        for (i = 0; i < ha->num_phys; i++) {
 439                struct asd_sas_port *port = ha->sas_port[i];
 440
 441                sas_discover_event(port, DISCE_SUSPEND);
 442        }
 443
 444        /* flush suspend events while unregistered */
 445        mutex_lock(&ha->drain_mutex);
 446        __sas_drain_work(ha);
 447        mutex_unlock(&ha->drain_mutex);
 448}
 449EXPORT_SYMBOL(sas_suspend_ha);
 450
 451static void sas_phy_release(struct sas_phy *phy)
 452{
 453        kfree(phy->hostdata);
 454        phy->hostdata = NULL;
 455}
 456
 457static void phy_reset_work(struct work_struct *work)
 458{
 459        struct sas_phy_data *d = container_of(work, typeof(*d), reset_work.work);
 460
 461        d->reset_result = transport_sas_phy_reset(d->phy, d->hard_reset);
 462}
 463
 464static void phy_enable_work(struct work_struct *work)
 465{
 466        struct sas_phy_data *d = container_of(work, typeof(*d), enable_work.work);
 467
 468        d->enable_result = sas_phy_enable(d->phy, d->enable);
 469}
 470
 471static int sas_phy_setup(struct sas_phy *phy)
 472{
 473        struct sas_phy_data *d = kzalloc(sizeof(*d), GFP_KERNEL);
 474
 475        if (!d)
 476                return -ENOMEM;
 477
 478        mutex_init(&d->event_lock);
 479        INIT_SAS_WORK(&d->reset_work, phy_reset_work);
 480        INIT_SAS_WORK(&d->enable_work, phy_enable_work);
 481        d->phy = phy;
 482        phy->hostdata = d;
 483
 484        return 0;
 485}
 486
 487static int queue_phy_reset(struct sas_phy *phy, int hard_reset)
 488{
 489        struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
 490        struct sas_ha_struct *ha = SHOST_TO_SAS_HA(shost);
 491        struct sas_phy_data *d = phy->hostdata;
 492        int rc;
 493
 494        if (!d)
 495                return -ENOMEM;
 496
 497        /* libsas workqueue coordinates ata-eh reset with discovery */
 498        mutex_lock(&d->event_lock);
 499        d->reset_result = 0;
 500        d->hard_reset = hard_reset;
 501
 502        spin_lock_irq(&ha->lock);
 503        sas_queue_work(ha, &d->reset_work);
 504        spin_unlock_irq(&ha->lock);
 505
 506        rc = sas_drain_work(ha);
 507        if (rc == 0)
 508                rc = d->reset_result;
 509        mutex_unlock(&d->event_lock);
 510
 511        return rc;
 512}
 513
 514static int queue_phy_enable(struct sas_phy *phy, int enable)
 515{
 516        struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
 517        struct sas_ha_struct *ha = SHOST_TO_SAS_HA(shost);
 518        struct sas_phy_data *d = phy->hostdata;
 519        int rc;
 520
 521        if (!d)
 522                return -ENOMEM;
 523
 524        /* libsas workqueue coordinates ata-eh reset with discovery */
 525        mutex_lock(&d->event_lock);
 526        d->enable_result = 0;
 527        d->enable = enable;
 528
 529        spin_lock_irq(&ha->lock);
 530        sas_queue_work(ha, &d->enable_work);
 531        spin_unlock_irq(&ha->lock);
 532
 533        rc = sas_drain_work(ha);
 534        if (rc == 0)
 535                rc = d->enable_result;
 536        mutex_unlock(&d->event_lock);
 537
 538        return rc;
 539}
 540
 541static struct sas_function_template sft = {
 542        .phy_enable = queue_phy_enable,
 543        .phy_reset = queue_phy_reset,
 544        .phy_setup = sas_phy_setup,
 545        .phy_release = sas_phy_release,
 546        .set_phy_speed = sas_set_phy_speed,
 547        .get_linkerrors = sas_get_linkerrors,
 548        .smp_handler = sas_smp_handler,
 549};
 550
 551struct scsi_transport_template *
 552sas_domain_attach_transport(struct sas_domain_function_template *dft)
 553{
 554        struct scsi_transport_template *stt = sas_attach_transport(&sft);
 555        struct sas_internal *i;
 556
 557        if (!stt)
 558                return stt;
 559
 560        i = to_sas_internal(stt);
 561        i->dft = dft;
 562        stt->create_work_queue = 1;
 563        stt->eh_timed_out = sas_scsi_timed_out;
 564        stt->eh_strategy_handler = sas_scsi_recover_host;
 565
 566        return stt;
 567}
 568EXPORT_SYMBOL_GPL(sas_domain_attach_transport);
 569
 570
 571void sas_domain_release_transport(struct scsi_transport_template *stt)
 572{
 573        sas_release_transport(stt);
 574}
 575EXPORT_SYMBOL_GPL(sas_domain_release_transport);
 576
 577/* ---------- SAS Class register/unregister ---------- */
 578
 579static int __init sas_class_init(void)
 580{
 581        sas_task_cache = KMEM_CACHE(sas_task, SLAB_HWCACHE_ALIGN);
 582        if (!sas_task_cache)
 583                return -ENOMEM;
 584
 585        return 0;
 586}
 587
 588static void __exit sas_class_exit(void)
 589{
 590        kmem_cache_destroy(sas_task_cache);
 591}
 592
 593MODULE_AUTHOR("Luben Tuikov <luben_tuikov@adaptec.com>");
 594MODULE_DESCRIPTION("SAS Transport Layer");
 595MODULE_LICENSE("GPL v2");
 596
 597module_init(sas_class_init);
 598module_exit(sas_class_exit);
 599
 600EXPORT_SYMBOL_GPL(sas_register_ha);
 601EXPORT_SYMBOL_GPL(sas_unregister_ha);
 602