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 <scsi/scsi_host.h> 27 #include <scsi/scsi_eh.h> 28 #include "sas_internal.h" 29 30 #include <scsi/scsi_transport.h> 31 #include <scsi/scsi_transport_sas.h> 32 #include "../scsi_sas_internal.h" 33 34 /* ---------- Basic task processing for discovery purposes ---------- */ 35 36 void sas_init_dev(struct domain_device *dev) 37 { 38 INIT_LIST_HEAD(&dev->siblings); 39 INIT_LIST_HEAD(&dev->dev_list_node); 40 switch (dev->dev_type) { 41 case SAS_END_DEV: 42 break; 43 case EDGE_DEV: 44 case FANOUT_DEV: 45 INIT_LIST_HEAD(&dev->ex_dev.children); 46 break; 47 case SATA_DEV: 48 case SATA_PM: 49 case SATA_PM_PORT: 50 INIT_LIST_HEAD(&dev->sata_dev.children); 51 break; 52 default: 53 break; 54 } 55 } 56 57 /* ---------- Domain device discovery ---------- */ 58 59 /** 60 * sas_get_port_device -- Discover devices which caused port creation 61 * @port: pointer to struct sas_port of interest 62 * 63 * Devices directly attached to a HA port, have no parent. This is 64 * how we know they are (domain) "root" devices. All other devices 65 * do, and should have their "parent" pointer set appropriately as 66 * soon as a child device is discovered. 67 */ 68 static int sas_get_port_device(struct asd_sas_port *port) 69 { 70 unsigned long flags; 71 struct asd_sas_phy *phy; 72 struct sas_rphy *rphy; 73 struct domain_device *dev; 74 75 dev = kzalloc(sizeof(*dev), GFP_KERNEL); 76 if (!dev) 77 return -ENOMEM; 78 79 spin_lock_irqsave(&port->phy_list_lock, flags); 80 if (list_empty(&port->phy_list)) { 81 spin_unlock_irqrestore(&port->phy_list_lock, flags); 82 kfree(dev); 83 return -ENODEV; 84 } 85 phy = container_of(port->phy_list.next, struct asd_sas_phy, port_phy_el); 86 spin_lock(&phy->frame_rcvd_lock); 87 memcpy(dev->frame_rcvd, phy->frame_rcvd, min(sizeof(dev->frame_rcvd), 88 (size_t)phy->frame_rcvd_size)); 89 spin_unlock(&phy->frame_rcvd_lock); 90 spin_unlock_irqrestore(&port->phy_list_lock, flags); 91 92 if (dev->frame_rcvd[0] == 0x34 && port->oob_mode == SATA_OOB_MODE) { 93 struct dev_to_host_fis *fis = 94 (struct dev_to_host_fis *) dev->frame_rcvd; 95 if (fis->interrupt_reason == 1 && fis->lbal == 1 && 96 fis->byte_count_low==0x69 && fis->byte_count_high == 0x96 97 && (fis->device & ~0x10) == 0) 98 dev->dev_type = SATA_PM; 99 else 100 dev->dev_type = SATA_DEV; 101 dev->tproto = SAS_PROTOCOL_SATA; 102 } else { 103 struct sas_identify_frame *id = 104 (struct sas_identify_frame *) dev->frame_rcvd; 105 dev->dev_type = id->dev_type; 106 dev->iproto = id->initiator_bits; 107 dev->tproto = id->target_bits; 108 } 109 110 sas_init_dev(dev); 111 112 switch (dev->dev_type) { 113 case SAS_END_DEV: 114 case SATA_DEV: 115 rphy = sas_end_device_alloc(port->port); 116 break; 117 case EDGE_DEV: 118 rphy = sas_expander_alloc(port->port, 119 SAS_EDGE_EXPANDER_DEVICE); 120 break; 121 case FANOUT_DEV: 122 rphy = sas_expander_alloc(port->port, 123 SAS_FANOUT_EXPANDER_DEVICE); 124 break; 125 default: 126 printk("ERROR: Unidentified device type %d\n", dev->dev_type); 127 rphy = NULL; 128 break; 129 } 130 131 if (!rphy) { 132 kfree(dev); 133 return -ENODEV; 134 } 135 rphy->identify.phy_identifier = phy->phy->identify.phy_identifier; 136 memcpy(dev->sas_addr, port->attached_sas_addr, SAS_ADDR_SIZE); 137 sas_fill_in_rphy(dev, rphy); 138 sas_hash_addr(dev->hashed_sas_addr, dev->sas_addr); 139 port->port_dev = dev; 140 dev->port = port; 141 dev->linkrate = port->linkrate; 142 dev->min_linkrate = port->linkrate; 143 dev->max_linkrate = port->linkrate; 144 dev->pathways = port->num_phys; 145 memset(port->disc.fanout_sas_addr, 0, SAS_ADDR_SIZE); 146 memset(port->disc.eeds_a, 0, SAS_ADDR_SIZE); 147 memset(port->disc.eeds_b, 0, SAS_ADDR_SIZE); 148 port->disc.max_level = 0; 149 150 dev->rphy = rphy; 151 spin_lock_irq(&port->dev_list_lock); 152 list_add_tail(&dev->dev_list_node, &port->dev_list); 153 spin_unlock_irq(&port->dev_list_lock); 154 155 return 0; 156 } 157 158 /* ---------- Discover and Revalidate ---------- */ 159 160 int sas_notify_lldd_dev_found(struct domain_device *dev) 161 { 162 int res = 0; 163 struct sas_ha_struct *sas_ha = dev->port->ha; 164 struct Scsi_Host *shost = sas_ha->core.shost; 165 struct sas_internal *i = to_sas_internal(shost->transportt); 166 167 if (i->dft->lldd_dev_found) { 168 res = i->dft->lldd_dev_found(dev); 169 if (res) { 170 printk("sas: driver on pcidev %s cannot handle " 171 "device %llx, error:%d\n", 172 sas_ha->dev->bus_id, 173 SAS_ADDR(dev->sas_addr), res); 174 } 175 } 176 return res; 177 } 178 179 180 void sas_notify_lldd_dev_gone(struct domain_device *dev) 181 { 182 struct sas_ha_struct *sas_ha = dev->port->ha; 183 struct Scsi_Host *shost = sas_ha->core.shost; 184 struct sas_internal *i = to_sas_internal(shost->transportt); 185 186 if (i->dft->lldd_dev_gone) 187 i->dft->lldd_dev_gone(dev); 188 } 189 190 /* ---------- Common/dispatchers ---------- */ 191 192 193 /** 194 * sas_discover_end_dev -- discover an end device (SSP, etc) 195 * @end: pointer to domain device of interest 196 * 197 * See comment in sas_discover_sata(). 198 */ 199 int sas_discover_end_dev(struct domain_device *dev) 200 { 201 int res; 202 203 res = sas_notify_lldd_dev_found(dev); 204 if (res) 205 goto out_err2; 206 207 res = sas_rphy_add(dev->rphy); 208 if (res) 209 goto out_err; 210 211 return 0; 212 213 out_err: 214 sas_notify_lldd_dev_gone(dev); 215 out_err2: 216 return res; 217 } 218 219 /* ---------- Device registration and unregistration ---------- */ 220 221 static inline void sas_unregister_common_dev(struct domain_device *dev) 222 { 223 sas_notify_lldd_dev_gone(dev); 224 if (!dev->parent) 225 dev->port->port_dev = NULL; 226 else 227 list_del_init(&dev->siblings); 228 list_del_init(&dev->dev_list_node); 229 } 230 231 void sas_unregister_dev(struct domain_device *dev) 232 { 233 if (dev->rphy) { 234 sas_remove_children(&dev->rphy->dev); 235 sas_rphy_delete(dev->rphy); 236 dev->rphy = NULL; 237 } 238 if (dev->dev_type == EDGE_DEV || dev->dev_type == FANOUT_DEV) { 239 /* remove the phys and ports, everything else should be gone */ 240 kfree(dev->ex_dev.ex_phy); 241 dev->ex_dev.ex_phy = NULL; 242 } 243 sas_unregister_common_dev(dev); 244 } 245 246 void sas_unregister_domain_devices(struct asd_sas_port *port) 247 { 248 struct domain_device *dev, *n; 249 250 list_for_each_entry_safe_reverse(dev,n,&port->dev_list,dev_list_node) 251 sas_unregister_dev(dev); 252 253 port->port->rphy = NULL; 254 255 } 256 257 /* ---------- Discovery and Revalidation ---------- */ 258 259 /** 260 * sas_discover_domain -- discover the domain 261 * @port: port to the domain of interest 262 * 263 * NOTE: this process _must_ quit (return) as soon as any connection 264 * errors are encountered. Connection recovery is done elsewhere. 265 * Discover process only interrogates devices in order to discover the 266 * domain. 267 */ 268 static void sas_discover_domain(struct work_struct *work) 269 { 270 struct domain_device *dev; 271 int error = 0; 272 struct sas_discovery_event *ev = 273 container_of(work, struct sas_discovery_event, work); 274 struct asd_sas_port *port = ev->port; 275 276 sas_begin_event(DISCE_DISCOVER_DOMAIN, &port->disc.disc_event_lock, 277 &port->disc.pending); 278 279 if (port->port_dev) 280 return; 281 282 error = sas_get_port_device(port); 283 if (error) 284 return; 285 dev = port->port_dev; 286 287 SAS_DPRINTK("DOING DISCOVERY on port %d, pid:%d\n", port->id, 288 task_pid_nr(current)); 289 290 switch (dev->dev_type) { 291 case SAS_END_DEV: 292 error = sas_discover_end_dev(dev); 293 break; 294 case EDGE_DEV: 295 case FANOUT_DEV: 296 error = sas_discover_root_expander(dev); 297 break; 298 case SATA_DEV: 299 case SATA_PM: 300 #ifdef CONFIG_SCSI_SAS_ATA 301 error = sas_discover_sata(dev); 302 break; 303 #else 304 SAS_DPRINTK("ATA device seen but CONFIG_SCSI_SAS_ATA=N so cannot attach\n"); 305 /* Fall through */ 306 #endif 307 default: 308 error = -ENXIO; 309 SAS_DPRINTK("unhandled device %d\n", dev->dev_type); 310 break; 311 } 312 313 if (error) { 314 sas_rphy_free(dev->rphy); 315 dev->rphy = NULL; 316 317 spin_lock_irq(&port->dev_list_lock); 318 list_del_init(&dev->dev_list_node); 319 spin_unlock_irq(&port->dev_list_lock); 320 321 kfree(dev); /* not kobject_register-ed yet */ 322 port->port_dev = NULL; 323 } 324 325 SAS_DPRINTK("DONE DISCOVERY on port %d, pid:%d, result:%d\n", port->id, 326 task_pid_nr(current), error); 327 } 328 329 static void sas_revalidate_domain(struct work_struct *work) 330 { 331 int res = 0; 332 struct sas_discovery_event *ev = 333 container_of(work, struct sas_discovery_event, work); 334 struct asd_sas_port *port = ev->port; 335 336 sas_begin_event(DISCE_REVALIDATE_DOMAIN, &port->disc.disc_event_lock, 337 &port->disc.pending); 338 339 SAS_DPRINTK("REVALIDATING DOMAIN on port %d, pid:%d\n", port->id, 340 task_pid_nr(current)); 341 if (port->port_dev) 342 res = sas_ex_revalidate_domain(port->port_dev); 343 344 SAS_DPRINTK("done REVALIDATING DOMAIN on port %d, pid:%d, res 0x%x\n", 345 port->id, task_pid_nr(current), res); 346 } 347 348 /* ---------- Events ---------- */ 349 350 int sas_discover_event(struct asd_sas_port *port, enum discover_event ev) 351 { 352 struct sas_discovery *disc; 353 354 if (!port) 355 return 0; 356 disc = &port->disc; 357 358 BUG_ON(ev >= DISC_NUM_EVENTS); 359 360 sas_queue_event(ev, &disc->disc_event_lock, &disc->pending, 361 &disc->disc_work[ev].work, port->ha); 362 363 return 0; 364 } 365 366 /** 367 * sas_init_disc -- initialize the discovery struct in the port 368 * @port: pointer to struct port 369 * 370 * Called when the ports are being initialized. 371 */ 372 void sas_init_disc(struct sas_discovery *disc, struct asd_sas_port *port) 373 { 374 int i; 375 376 static const work_func_t sas_event_fns[DISC_NUM_EVENTS] = { 377 [DISCE_DISCOVER_DOMAIN] = sas_discover_domain, 378 [DISCE_REVALIDATE_DOMAIN] = sas_revalidate_domain, 379 }; 380 381 spin_lock_init(&disc->disc_event_lock); 382 disc->pending = 0; 383 for (i = 0; i < DISC_NUM_EVENTS; i++) { 384 INIT_WORK(&disc->disc_work[i].work, sas_event_fns[i]); 385 disc->disc_work[i].port = port; 386 } 387 } 388