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/scsi_host.h> 32 #include <scsi/scsi_device.h> 33 #include <scsi/scsi_transport.h> 34 #include <scsi/scsi_transport_sas.h> 35 36 #include "sas_internal.h" 37 38 #include "../scsi_sas_internal.h" 39 40 static struct kmem_cache *sas_task_cache; 41 42 struct sas_task *sas_alloc_task(gfp_t flags) 43 { 44 struct sas_task *task = kmem_cache_zalloc(sas_task_cache, flags); 45 46 if (task) { 47 INIT_LIST_HEAD(&task->list); 48 spin_lock_init(&task->task_state_lock); 49 task->task_state_flags = SAS_TASK_STATE_PENDING; 50 init_timer(&task->timer); 51 init_completion(&task->completion); 52 } 53 54 return task; 55 } 56 EXPORT_SYMBOL_GPL(sas_alloc_task); 57 58 void sas_free_task(struct sas_task *task) 59 { 60 if (task) { 61 BUG_ON(!list_empty(&task->list)); 62 kmem_cache_free(sas_task_cache, task); 63 } 64 } 65 EXPORT_SYMBOL_GPL(sas_free_task); 66 67 /*------------ SAS addr hash -----------*/ 68 void sas_hash_addr(u8 *hashed, const u8 *sas_addr) 69 { 70 const u32 poly = 0x00DB2777; 71 u32 r = 0; 72 int i; 73 74 for (i = 0; i < 8; i++) { 75 int b; 76 for (b = 7; b >= 0; b--) { 77 r <<= 1; 78 if ((1 << b) & sas_addr[i]) { 79 if (!(r & 0x01000000)) 80 r ^= poly; 81 } else if (r & 0x01000000) 82 r ^= poly; 83 } 84 } 85 86 hashed[0] = (r >> 16) & 0xFF; 87 hashed[1] = (r >> 8) & 0xFF ; 88 hashed[2] = r & 0xFF; 89 } 90 91 92 /* ---------- HA events ---------- */ 93 94 void sas_hae_reset(struct work_struct *work) 95 { 96 struct sas_ha_event *ev = 97 container_of(work, struct sas_ha_event, work); 98 struct sas_ha_struct *ha = ev->ha; 99 100 sas_begin_event(HAE_RESET, &ha->event_lock, 101 &ha->pending); 102 } 103 104 int sas_register_ha(struct sas_ha_struct *sas_ha) 105 { 106 int error = 0; 107 108 spin_lock_init(&sas_ha->phy_port_lock); 109 sas_hash_addr(sas_ha->hashed_sas_addr, sas_ha->sas_addr); 110 111 if (sas_ha->lldd_queue_size == 0) 112 sas_ha->lldd_queue_size = 1; 113 else if (sas_ha->lldd_queue_size == -1) 114 sas_ha->lldd_queue_size = 128; /* Sanity */ 115 116 sas_ha->state = SAS_HA_REGISTERED; 117 spin_lock_init(&sas_ha->state_lock); 118 119 error = sas_register_phys(sas_ha); 120 if (error) { 121 printk(KERN_NOTICE "couldn't register sas phys:%d\n", error); 122 return error; 123 } 124 125 error = sas_register_ports(sas_ha); 126 if (error) { 127 printk(KERN_NOTICE "couldn't register sas ports:%d\n", error); 128 goto Undo_phys; 129 } 130 131 error = sas_init_events(sas_ha); 132 if (error) { 133 printk(KERN_NOTICE "couldn't start event thread:%d\n", error); 134 goto Undo_ports; 135 } 136 137 if (sas_ha->lldd_max_execute_num > 1) { 138 error = sas_init_queue(sas_ha); 139 if (error) { 140 printk(KERN_NOTICE "couldn't start queue thread:%d, " 141 "running in direct mode\n", error); 142 sas_ha->lldd_max_execute_num = 1; 143 } 144 } 145 146 INIT_LIST_HEAD(&sas_ha->eh_done_q); 147 148 return 0; 149 150 Undo_ports: 151 sas_unregister_ports(sas_ha); 152 Undo_phys: 153 154 return error; 155 } 156 157 int sas_unregister_ha(struct sas_ha_struct *sas_ha) 158 { 159 unsigned long flags; 160 161 /* Set the state to unregistered to avoid further 162 * events to be queued */ 163 spin_lock_irqsave(&sas_ha->state_lock, flags); 164 sas_ha->state = SAS_HA_UNREGISTERED; 165 spin_unlock_irqrestore(&sas_ha->state_lock, flags); 166 scsi_flush_work(sas_ha->core.shost); 167 168 sas_unregister_ports(sas_ha); 169 170 if (sas_ha->lldd_max_execute_num > 1) { 171 sas_shutdown_queue(sas_ha); 172 sas_ha->lldd_max_execute_num = 1; 173 } 174 175 return 0; 176 } 177 178 static int sas_get_linkerrors(struct sas_phy *phy) 179 { 180 if (scsi_is_sas_phy_local(phy)) { 181 struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); 182 struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(shost); 183 struct asd_sas_phy *asd_phy = sas_ha->sas_phy[phy->number]; 184 struct sas_internal *i = 185 to_sas_internal(sas_ha->core.shost->transportt); 186 187 return i->dft->lldd_control_phy(asd_phy, PHY_FUNC_GET_EVENTS, NULL); 188 } 189 190 return sas_smp_get_phy_events(phy); 191 } 192 193 int sas_phy_enable(struct sas_phy *phy, int enable) 194 { 195 int ret; 196 enum phy_func command; 197 198 if (enable) 199 command = PHY_FUNC_LINK_RESET; 200 else 201 command = PHY_FUNC_DISABLE; 202 203 if (scsi_is_sas_phy_local(phy)) { 204 struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); 205 struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(shost); 206 struct asd_sas_phy *asd_phy = sas_ha->sas_phy[phy->number]; 207 struct sas_internal *i = 208 to_sas_internal(sas_ha->core.shost->transportt); 209 210 if (!enable) { 211 sas_phy_disconnected(asd_phy); 212 sas_ha->notify_phy_event(asd_phy, PHYE_LOSS_OF_SIGNAL); 213 } 214 ret = i->dft->lldd_control_phy(asd_phy, command, NULL); 215 } else { 216 struct sas_rphy *rphy = dev_to_rphy(phy->dev.parent); 217 struct domain_device *ddev = sas_find_dev_by_rphy(rphy); 218 ret = sas_smp_phy_control(ddev, phy->number, command, NULL); 219 } 220 return ret; 221 } 222 223 int sas_phy_reset(struct sas_phy *phy, int hard_reset) 224 { 225 int ret; 226 enum phy_func reset_type; 227 228 if (hard_reset) 229 reset_type = PHY_FUNC_HARD_RESET; 230 else 231 reset_type = PHY_FUNC_LINK_RESET; 232 233 if (scsi_is_sas_phy_local(phy)) { 234 struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); 235 struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(shost); 236 struct asd_sas_phy *asd_phy = sas_ha->sas_phy[phy->number]; 237 struct sas_internal *i = 238 to_sas_internal(sas_ha->core.shost->transportt); 239 240 ret = i->dft->lldd_control_phy(asd_phy, reset_type, NULL); 241 } else { 242 struct sas_rphy *rphy = dev_to_rphy(phy->dev.parent); 243 struct domain_device *ddev = sas_find_dev_by_rphy(rphy); 244 ret = sas_smp_phy_control(ddev, phy->number, reset_type, NULL); 245 } 246 return ret; 247 } 248 249 int sas_set_phy_speed(struct sas_phy *phy, 250 struct sas_phy_linkrates *rates) 251 { 252 int ret; 253 254 if ((rates->minimum_linkrate && 255 rates->minimum_linkrate > phy->maximum_linkrate) || 256 (rates->maximum_linkrate && 257 rates->maximum_linkrate < phy->minimum_linkrate)) 258 return -EINVAL; 259 260 if (rates->minimum_linkrate && 261 rates->minimum_linkrate < phy->minimum_linkrate_hw) 262 rates->minimum_linkrate = phy->minimum_linkrate_hw; 263 264 if (rates->maximum_linkrate && 265 rates->maximum_linkrate > phy->maximum_linkrate_hw) 266 rates->maximum_linkrate = phy->maximum_linkrate_hw; 267 268 if (scsi_is_sas_phy_local(phy)) { 269 struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); 270 struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(shost); 271 struct asd_sas_phy *asd_phy = sas_ha->sas_phy[phy->number]; 272 struct sas_internal *i = 273 to_sas_internal(sas_ha->core.shost->transportt); 274 275 ret = i->dft->lldd_control_phy(asd_phy, PHY_FUNC_SET_LINK_RATE, 276 rates); 277 } else { 278 struct sas_rphy *rphy = dev_to_rphy(phy->dev.parent); 279 struct domain_device *ddev = sas_find_dev_by_rphy(rphy); 280 ret = sas_smp_phy_control(ddev, phy->number, 281 PHY_FUNC_LINK_RESET, rates); 282 283 } 284 285 return ret; 286 } 287 288 static struct sas_function_template sft = { 289 .phy_enable = sas_phy_enable, 290 .phy_reset = sas_phy_reset, 291 .set_phy_speed = sas_set_phy_speed, 292 .get_linkerrors = sas_get_linkerrors, 293 .smp_handler = sas_smp_handler, 294 }; 295 296 struct scsi_transport_template * 297 sas_domain_attach_transport(struct sas_domain_function_template *dft) 298 { 299 struct scsi_transport_template *stt = sas_attach_transport(&sft); 300 struct sas_internal *i; 301 302 if (!stt) 303 return stt; 304 305 i = to_sas_internal(stt); 306 i->dft = dft; 307 stt->create_work_queue = 1; 308 stt->eh_timed_out = sas_scsi_timed_out; 309 stt->eh_strategy_handler = sas_scsi_recover_host; 310 311 return stt; 312 } 313 EXPORT_SYMBOL_GPL(sas_domain_attach_transport); 314 315 316 void sas_domain_release_transport(struct scsi_transport_template *stt) 317 { 318 sas_release_transport(stt); 319 } 320 EXPORT_SYMBOL_GPL(sas_domain_release_transport); 321 322 /* ---------- SAS Class register/unregister ---------- */ 323 324 static int __init sas_class_init(void) 325 { 326 sas_task_cache = KMEM_CACHE(sas_task, SLAB_HWCACHE_ALIGN); 327 if (!sas_task_cache) 328 return -ENOMEM; 329 330 return 0; 331 } 332 333 static void __exit sas_class_exit(void) 334 { 335 kmem_cache_destroy(sas_task_cache); 336 } 337 338 MODULE_AUTHOR("Luben Tuikov <luben_tuikov@adaptec.com>"); 339 MODULE_DESCRIPTION("SAS Transport Layer"); 340 MODULE_LICENSE("GPL v2"); 341 342 module_init(sas_class_init); 343 module_exit(sas_class_exit); 344 345 EXPORT_SYMBOL_GPL(sas_register_ha); 346 EXPORT_SYMBOL_GPL(sas_unregister_ha); 347