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