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