- more 2.6.17 port work (still does not build)
[linux-flexiantxendom0-3.2.10.git] / drivers / scsi / sas / sas_expander.c
1 /*
2  * Serial Attached SCSI (SAS) Expander discovery and configuration
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  * $Id: //depot/sas-class/sas_expander.c#60 $
24  */
25
26 #include <linux/pci.h>
27 #include <linux/scatterlist.h>
28
29 #include "sas_internal.h"
30 #include <scsi/sas/sas_task.h>
31 #include <scsi/sas/sas_discover.h>
32
33 #include <scsi/scsi_transport.h>
34 #include <scsi/scsi_transport_sas.h>
35 #include "../scsi_sas_internal.h"
36
37 static int sas_discover_expander(struct domain_device *dev);
38 static int sas_configure_routing(struct domain_device *dev, u8 *sas_addr);
39 static int sas_disable_routing(struct domain_device *dev,  u8 *sas_addr);
40
41 #if 0
42 /* FIXME: smp needs to migrate into the sas class */
43 static ssize_t smp_portal_read(struct kobject *, char *, loff_t, size_t);
44 static ssize_t smp_portal_write(struct kobject *, char *, loff_t, size_t);
45 #endif
46
47 /* ---------- SMP task management ---------- */
48
49 static void smp_task_timedout(unsigned long _task)
50 {
51         struct sas_task *task = (void *) _task;
52         unsigned long flags;
53
54         spin_lock_irqsave(&task->task_state_lock, flags);
55         if (!(task->task_state_flags & SAS_TASK_STATE_DONE))
56                 task->task_state_flags |= SAS_TASK_STATE_ABORTED;
57         spin_unlock_irqrestore(&task->task_state_lock, flags);
58
59         complete(&task->completion);
60 }
61
62 static void smp_task_done(struct sas_task *task)
63 {
64         if (!del_timer(&task->timer))
65                 return;
66         complete(&task->completion);
67 }
68
69 /* Give it some long enough timeout. In seconds. */
70 #define SMP_TIMEOUT 10
71
72 static int smp_execute_task(struct domain_device *dev, void *req, int req_size,
73                             void *resp, int resp_size)
74 {
75         int res;
76         struct sas_task *task = sas_alloc_task(GFP_KERNEL);
77         struct sas_internal *i =
78                 to_sas_internal(dev->port->ha->core.shost->transportt);
79
80         if (!task)
81                 return -ENOMEM;
82
83         task->dev = dev;
84         task->task_proto = dev->tproto;
85         sg_init_one(&task->smp_task.smp_req, req, req_size);
86         sg_init_one(&task->smp_task.smp_resp, resp, resp_size);
87
88         task->task_done = smp_task_done;
89
90         task->timer.data = (unsigned long) task;
91         task->timer.function = smp_task_timedout;
92         task->timer.expires = jiffies + SMP_TIMEOUT*HZ;
93         add_timer(&task->timer);
94
95         res = i->dft->lldd_execute_task(task, 1, GFP_KERNEL);
96
97         if (res) {
98                 del_timer(&task->timer);
99                 SAS_DPRINTK("executing SMP task failed:%d\n", res);
100                 goto ex_err;
101         }
102
103         wait_for_completion(&task->completion);
104         res = -ETASK;
105         if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) {
106                 SAS_DPRINTK("smp task timed out or aborted\n");
107                 i->dft->lldd_abort_task(task);
108                 if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) {
109                         SAS_DPRINTK("SMP task aborted and not done\n");
110                         goto ex_err;
111                 }
112         }
113         if (task->task_status.resp == SAS_TASK_COMPLETE &&
114             task->task_status.stat == SAM_GOOD)
115                 res = 0;
116         else
117                 SAS_DPRINTK("%s: task to dev %016llx response: 0x%x "
118                             "status 0x%x\n", __FUNCTION__,
119                             SAS_ADDR(dev->sas_addr),
120                             task->task_status.resp,
121                             task->task_status.stat);
122 ex_err:
123         sas_free_task(task);
124         return res;
125 }
126
127 /* ---------- Allocations ---------- */
128
129 static inline void *alloc_smp_req(int size)
130 {
131         u8 *p = kzalloc(size, GFP_KERNEL);
132         if (p)
133                 p[0] = SMP_REQUEST;
134         return p;
135 }
136
137 static inline void *alloc_smp_resp(int size)
138 {
139         return kzalloc(size, GFP_KERNEL);
140 }
141
142 /* ---------- Expander configuration ---------- */
143
144 static void sas_set_ex_phy(struct domain_device *dev, int phy_id,
145                            void *disc_resp)
146 {
147         struct expander_device *ex = &dev->ex_dev;
148         struct ex_phy *phy = &ex->ex_phy[phy_id];
149         struct smp_resp *resp = disc_resp;
150         struct discover_resp *dr = &resp->disc;
151         struct sas_rphy *rphy = dev->rphy;
152
153         phy->phy = sas_phy_alloc(&rphy->dev, phy_id);
154         dev_printk(KERN_ERR, &phy->phy->dev, "ALLOCATED\n\n");
155
156         /* FIXME: error_handling */
157         BUG_ON(!phy->phy);
158
159         switch (resp->result) {
160         case SMP_RESP_PHY_VACANT:
161                 phy->phy_state = PHY_VACANT;
162                 return;
163         default:
164                 phy->phy_state = PHY_NOT_PRESENT;
165                 return;
166         case SMP_RESP_FUNC_ACC:
167                 phy->phy_state = PHY_EMPTY; /* do not know yet */
168                 break;
169         }
170
171         phy->phy_id = phy_id;
172         phy->attached_dev_type = dr->attached_dev_type;
173         phy->linkrate = dr->linkrate;
174         phy->attached_sata_host = dr->attached_sata_host;
175         phy->attached_sata_dev  = dr->attached_sata_dev;
176         phy->attached_sata_ps   = dr->attached_sata_ps;
177         phy->attached_iproto = dr->iproto << 1;
178         phy->attached_tproto = dr->tproto << 1;
179         memcpy(phy->attached_sas_addr, dr->attached_sas_addr, SAS_ADDR_SIZE);
180         phy->attached_phy_id = dr->attached_phy_id;
181         phy->phy_change_count = dr->change_count;
182         phy->routing_attr = dr->routing_attr;
183         phy->virtual = dr->virtual;
184         phy->last_da_index = -1;
185
186         /* FIXME: This probably isn't right, but it will do for now*/
187         phy->phy->local_attached = 1;
188
189         phy->phy->identify.initiator_port_protocols = phy->attached_iproto;
190         phy->phy->identify.target_port_protocols = phy->attached_tproto;
191         phy->phy->identify.phy_identifier = phy_id;
192         phy->phy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
193         phy->phy->maximum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
194         phy->phy->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS;
195         phy->phy->maximum_linkrate = SAS_LINK_RATE_3_0_GBPS;
196         switch (phy->linkrate) {
197         case PHY_LINKRATE_1_5:
198                 phy->phy->negotiated_linkrate = SAS_LINK_RATE_1_5_GBPS;
199                 break;
200         case PHY_LINKRATE_3:
201                 phy->phy->negotiated_linkrate = SAS_LINK_RATE_3_0_GBPS;
202                 break;
203         case PHY_LINKRATE_6:
204                 phy->phy->negotiated_linkrate = SAS_LINK_RATE_6_0_GBPS;
205                 break;
206         default:
207                 phy->phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN;
208                 break;
209         }
210
211         sas_phy_add(phy->phy);
212
213         SAS_DPRINTK("ex %016llx phy%02d:%c attached: %016llx\n",
214                     SAS_ADDR(dev->sas_addr), phy->phy_id,
215                     phy->routing_attr == TABLE_ROUTING ? 'T' :
216                     phy->routing_attr == DIRECT_ROUTING ? 'D' :
217                     phy->routing_attr == SUBTRACTIVE_ROUTING ? 'S' : '?',
218                     SAS_ADDR(phy->attached_sas_addr));
219
220         return;
221 }
222
223 #define DISCOVER_REQ_SIZE  16
224 #define DISCOVER_RESP_SIZE 56
225
226 static int sas_ex_phy_discover(struct domain_device *dev, int single)
227 {
228         struct expander_device *ex = &dev->ex_dev;
229         int  res = 0;
230         u8   *disc_req;
231         u8   *disc_resp;
232
233         disc_req = alloc_smp_req(DISCOVER_REQ_SIZE);
234         if (!disc_req)
235                 return -ENOMEM;
236
237         disc_resp = alloc_smp_req(DISCOVER_RESP_SIZE);
238         if (!disc_resp) {
239                 kfree(disc_req);
240                 return -ENOMEM;
241         }
242
243         disc_req[1] = SMP_DISCOVER;
244
245         if (0 <= single && single < ex->num_phys) {
246                 disc_req[9] = single;
247                 res = smp_execute_task(dev, disc_req, DISCOVER_REQ_SIZE,
248                                        disc_resp, DISCOVER_RESP_SIZE);
249                 if (res)
250                         goto out_err;
251                 sas_set_ex_phy(dev, single, disc_resp);
252         } else {
253                 int i;
254
255                 for (i = 0; i < ex->num_phys; i++) {
256                         disc_req[9] = i;
257                         res = smp_execute_task(dev, disc_req,
258                                                DISCOVER_REQ_SIZE, disc_resp,
259                                                DISCOVER_RESP_SIZE);
260                         if (res)
261                                 goto out_err;
262                         sas_set_ex_phy(dev, i, disc_resp);
263                 }
264         }
265 out_err:
266         kfree(disc_resp);
267         kfree(disc_req);
268         return res;
269 }
270
271 static int sas_expander_discover(struct domain_device *dev)
272 {
273         struct expander_device *ex = &dev->ex_dev;
274         int res;
275
276         ex->ex_phy = kzalloc(sizeof(*ex->ex_phy)*ex->num_phys, GFP_KERNEL);
277         if (!ex->ex_phy)
278                 return -ENOMEM;
279
280         res = sas_ex_phy_discover(dev, -1);
281         if (res)
282                 goto out_err;
283
284         return 0;
285 out_err:
286         kfree(ex->ex_phy);
287         ex->ex_phy = NULL;
288         return res;
289 }
290
291 #define MAX_EXPANDER_PHYS 128
292
293 static inline void ex_assign_report_general(struct domain_device *dev,
294                                             struct smp_resp *resp)
295 {
296         struct report_general_resp *rg = &resp->rg;
297
298         dev->ex_dev.ex_change_count = be16_to_cpu(rg->change_count);
299         dev->ex_dev.max_route_indexes = be16_to_cpu(rg->route_indexes);
300         dev->ex_dev.num_phys = min(rg->num_phys, (u8)MAX_EXPANDER_PHYS);
301         dev->ex_dev.conf_route_table = rg->conf_route_table;
302         dev->ex_dev.configuring = rg->configuring;
303         memcpy(dev->ex_dev.enclosure_logical_id, rg->enclosure_logical_id, 8);
304 }
305
306 #define RG_REQ_SIZE   8
307 #define RG_RESP_SIZE 32
308
309 static int sas_ex_general(struct domain_device *dev)
310 {
311         u8 *rg_req;
312         struct smp_resp *rg_resp;
313         int res;
314         int i;
315
316         rg_req = alloc_smp_req(RG_REQ_SIZE);
317         if (!rg_req)
318                 return -ENOMEM;
319
320         rg_resp = alloc_smp_resp(RG_RESP_SIZE);
321         if (!rg_resp) {
322                 kfree(rg_req);
323                 return -ENOMEM;
324         }
325
326         rg_req[1] = SMP_REPORT_GENERAL;
327
328         for (i = 0; i < 5; i++) {
329                 res = smp_execute_task(dev, rg_req, RG_REQ_SIZE, rg_resp,
330                                        RG_RESP_SIZE);
331
332                 if (res) {
333                         SAS_DPRINTK("RG to ex %016llx failed:0x%x\n",
334                                     SAS_ADDR(dev->sas_addr), res);
335                         goto out;
336                 } else if (rg_resp->result != SMP_RESP_FUNC_ACC) {
337                         SAS_DPRINTK("RG:ex %016llx returned SMP result:0x%x\n",
338                                     SAS_ADDR(dev->sas_addr), rg_resp->result);
339                         res = rg_resp->result;
340                         goto out;
341                 }
342
343                 ex_assign_report_general(dev, rg_resp);
344
345                 if (dev->ex_dev.configuring) {
346                         SAS_DPRINTK("RG: ex %llx self-configuring...\n",
347                                     SAS_ADDR(dev->sas_addr));
348                         schedule_timeout_interruptible(5*HZ);
349                 } else
350                         break;
351         }
352 out:
353         kfree(rg_req);
354         kfree(rg_resp);
355         return res;
356 }
357
358 static inline void ex_assign_manuf_info(struct domain_device *dev, void
359                                         *_mi_resp)
360 {
361         u8 *mi_resp = _mi_resp;
362         struct sas_rphy *rphy = dev->rphy;
363         struct sas_expander_device *edev = rphy_to_expander_device(rphy);
364
365         memcpy(edev->vendor_id, mi_resp + 12, SAS_EXPANDER_VENDOR_ID_LEN);
366         memcpy(edev->product_id, mi_resp + 20, SAS_EXPANDER_PRODUCT_ID_LEN);
367         memcpy(edev->product_rev, mi_resp + 36,
368                SAS_EXPANDER_PRODUCT_REV_LEN);
369
370         if (mi_resp[8] & 1) {
371                 memcpy(edev->component_vendor_id, mi_resp + 40,
372                        SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN);
373                 edev->component_id = mi_resp[48] << 8 | mi_resp[49];
374                 edev->component_revision_id = mi_resp[50];
375         }
376 }
377
378 #define MI_REQ_SIZE   8
379 #define MI_RESP_SIZE 64
380
381 static int sas_ex_manuf_info(struct domain_device *dev)
382 {
383         u8 *mi_req;
384         u8 *mi_resp;
385         int res;
386
387         mi_req = alloc_smp_req(MI_REQ_SIZE);
388         if (!mi_req)
389                 return -ENOMEM;
390
391         mi_resp = alloc_smp_resp(MI_RESP_SIZE);
392         if (!mi_resp) {
393                 kfree(mi_req);
394                 return -ENOMEM;
395         }
396
397         mi_req[1] = SMP_REPORT_MANUF_INFO;
398
399         res = smp_execute_task(dev, mi_req, MI_REQ_SIZE, mi_resp,MI_RESP_SIZE);
400         if (res) {
401                 SAS_DPRINTK("MI: ex %016llx failed:0x%x\n",
402                             SAS_ADDR(dev->sas_addr), res);
403                 goto out;
404         } else if (mi_resp[2] != SMP_RESP_FUNC_ACC) {
405                 SAS_DPRINTK("MI ex %016llx returned SMP result:0x%x\n",
406                             SAS_ADDR(dev->sas_addr), mi_resp[2]);
407                 goto out;
408         }
409
410         ex_assign_manuf_info(dev, mi_resp);
411 out:
412         kfree(mi_req);
413         kfree(mi_resp);
414         return res;
415 }
416
417 #define PC_REQ_SIZE  44
418 #define PC_RESP_SIZE 8
419
420 static int smp_phy_control(struct domain_device *dev, int phy_id,
421                            enum phy_func phy_func)
422 {
423         u8 *pc_req;
424         u8 *pc_resp;
425         int res;
426
427         pc_req = alloc_smp_req(PC_REQ_SIZE);
428         if (!pc_req)
429                 return -ENOMEM;
430
431         pc_resp = alloc_smp_resp(PC_RESP_SIZE);
432         if (!pc_resp) {
433                 kfree(pc_req);
434                 return -ENOMEM;
435         }
436
437         pc_req[1] = SMP_PHY_CONTROL;
438         pc_req[9] = phy_id;
439         pc_req[10]= phy_func;
440
441         res = smp_execute_task(dev, pc_req, PC_REQ_SIZE, pc_resp,PC_RESP_SIZE);
442
443         kfree(pc_resp);
444         kfree(pc_req);
445         return res;
446 }
447
448 static inline void sas_ex_disable_phy(struct domain_device *dev, int phy_id)
449 {
450         struct expander_device *ex = &dev->ex_dev;
451         struct ex_phy *phy = &ex->ex_phy[phy_id];
452
453         smp_phy_control(dev, phy_id, PHY_FUNC_DISABLE);
454         phy->linkrate = PHY_DISABLED;
455 }
456
457 static inline void sas_ex_disable_port(struct domain_device *dev, u8 *sas_addr)
458 {
459         struct expander_device *ex = &dev->ex_dev;
460         int i;
461
462         for (i = 0; i < ex->num_phys; i++) {
463                 struct ex_phy *phy = &ex->ex_phy[i];
464
465                 if (phy->phy_state == PHY_VACANT ||
466                     phy->phy_state == PHY_NOT_PRESENT)
467                         continue;
468
469                 if (SAS_ADDR(phy->attached_sas_addr) == SAS_ADDR(sas_addr))
470                         sas_ex_disable_phy(dev, i);
471         }
472 }
473
474 static inline int sas_dev_present_in_domain(struct sas_port *port,
475                                             u8 *sas_addr)
476 {
477         struct domain_device *dev;
478
479         if (SAS_ADDR(port->sas_addr) == SAS_ADDR(sas_addr))
480                 return 1;
481         list_for_each_entry(dev, &port->dev_list, dev_list_node) {
482                 if (SAS_ADDR(dev->sas_addr) == SAS_ADDR(sas_addr))
483                         return 1;
484         }
485         return 0;
486 }
487
488 #define RPS_REQ_SIZE  16
489 #define RPS_RESP_SIZE 60
490
491 static inline int sas_get_report_phy_sata(struct domain_device *dev,
492                                           int phy_id,
493                                           struct smp_resp *rps_resp)
494 {
495         int res;
496         u8 *rps_req = alloc_smp_req(RPS_REQ_SIZE);
497
498         if (!rps_req)
499                 return -ENOMEM;
500
501         rps_req[1] = SMP_REPORT_PHY_SATA;
502         rps_req[9] = phy_id;
503
504         res = smp_execute_task(dev, rps_req, RPS_REQ_SIZE,
505                                     rps_resp, RPS_RESP_SIZE);
506
507         kfree(rps_req);
508         return 0;
509 }
510
511 static inline void sas_ex_get_linkrate(struct domain_device *parent,
512                                        struct domain_device *child,
513                                        struct ex_phy *parent_phy)
514 {
515         struct expander_device *parent_ex = &parent->ex_dev;
516         int i;
517
518         child->pathways = 0;
519
520         for (i = 0; i < parent_ex->num_phys; i++) {
521                 struct ex_phy *phy = &parent_ex->ex_phy[i];
522
523                 if (phy->phy_state == PHY_VACANT ||
524                     phy->phy_state == PHY_NOT_PRESENT)
525                         continue;
526
527                 if (SAS_ADDR(phy->attached_sas_addr) ==
528                     SAS_ADDR(child->sas_addr)) {
529
530                         child->min_linkrate = min(parent->min_linkrate,
531                                                   phy->linkrate);
532                         child->max_linkrate = max(parent->max_linkrate,
533                                                   phy->linkrate);
534                         child->pathways++;
535                 }
536         }
537         child->linkrate = min(parent_phy->linkrate, child->max_linkrate);
538         child->pathways = min(child->pathways, parent->pathways);
539 }
540
541 static struct domain_device *sas_ex_discover_end_dev(
542         struct domain_device *parent, int phy_id)
543 {
544         struct expander_device *parent_ex = &parent->ex_dev;
545         struct ex_phy *phy = &parent_ex->ex_phy[phy_id];
546         struct domain_device *child = NULL;
547         struct sas_rphy *rphy;
548         int res;
549
550         if (phy->attached_sata_host || phy->attached_sata_ps)
551                 return NULL;
552
553         child = kzalloc(sizeof(*child), GFP_KERNEL);
554         if (!child)
555                 return NULL;
556
557         child->parent = parent;
558         child->port   = parent->port;
559         child->iproto = phy->attached_iproto;
560         memcpy(child->sas_addr, phy->attached_sas_addr, SAS_ADDR_SIZE);
561         sas_hash_addr(child->hashed_sas_addr, child->sas_addr);
562         sas_ex_get_linkrate(parent, child, phy);
563
564         if ((phy->attached_tproto & SAS_PROTO_STP) || phy->attached_sata_dev) {
565                 child->dev_type = SATA_DEV;
566                 if (phy->attached_tproto & SAS_PROTO_STP)
567                         child->tproto = phy->attached_tproto;
568                 if (phy->attached_sata_dev)
569                         child->tproto |= SATA_DEV;
570                 res = sas_get_report_phy_sata(parent, phy_id,
571                                               &child->sata_dev.rps_resp);
572                 if (res) {
573                         SAS_DPRINTK("report phy sata to %016llx:0x%x returned "
574                                     "0x%x\n", SAS_ADDR(parent->sas_addr),
575                                     phy_id, res);
576                         kfree(child);
577                         return NULL;
578                 }
579                 memcpy(child->frame_rcvd, &child->sata_dev.rps_resp.rps.fis,
580                        sizeof(struct dev_to_host_fis));
581                 sas_init_dev(child);
582                 res = sas_discover_sata(child);
583                 if (res) {
584                         SAS_DPRINTK("sas_discover_sata() for device %16llx at "
585                                     "%016llx:0x%x returned 0x%x\n",
586                                     SAS_ADDR(child->sas_addr),
587                                     SAS_ADDR(parent->sas_addr), phy_id, res);
588                         kfree(child);
589                         return NULL;
590                 }
591         } else if (phy->attached_tproto & SAS_PROTO_SSP) {
592                 child->dev_type = SAS_END_DEV;
593                 rphy = sas_end_device_alloc(phy->phy);
594                 /* FIXME: error handling */
595                 BUG_ON(!rphy);
596                 child->tproto = phy->attached_tproto;
597                 sas_init_dev(child);
598
599                 child->rphy = rphy;
600                 rphy->identify.phy_identifier = phy->phy->identify.phy_identifier;
601                 rphy->identify.device_type = SAS_END_DEVICE;
602                 rphy->identify.sas_address = SAS_ADDR(child->sas_addr);
603                 rphy->identify.initiator_port_protocols = child->iproto;
604                 rphy->identify.target_port_protocols = child->tproto;
605
606                 spin_lock(&parent->port->dev_list_lock);
607                 list_add_tail(&child->dev_list_node, &parent->port->dev_list);
608                 spin_unlock(&parent->port->dev_list_lock);
609
610                 res = sas_discover_end_dev(child);
611                 if (res) {
612                         SAS_DPRINTK("sas_discover_end_dev() for device %16llx "
613                                     "at %016llx:0x%x returned 0x%x\n",
614                                     SAS_ADDR(child->sas_addr),
615                                     SAS_ADDR(parent->sas_addr), phy_id, res);
616                         kfree(child);
617                         return NULL;
618                 }
619         } else {
620                 SAS_DPRINTK("target proto 0x%x at %016llx:0x%x not handled\n",
621                             phy->attached_tproto, SAS_ADDR(parent->sas_addr),
622                             phy_id);
623         }
624
625         list_add_tail(&child->siblings, &parent_ex->children);
626         return child;
627 }
628
629 static struct domain_device *sas_ex_discover_expander(
630         struct domain_device *parent, int phy_id)
631 {
632         struct sas_expander_device *parent_ex = rphy_to_expander_device(parent->rphy);
633         struct ex_phy *phy = &parent->ex_dev.ex_phy[phy_id];
634         struct domain_device *child = NULL;
635         struct sas_rphy *rphy;
636         struct sas_expander_device *edev;
637         int res;
638
639         if (phy->routing_attr == DIRECT_ROUTING) {
640                 SAS_DPRINTK("ex %016llx:0x%x:D <--> ex %016llx:0x%x is not "
641                             "allowed\n",
642                             SAS_ADDR(parent->sas_addr), phy_id,
643                             SAS_ADDR(phy->attached_sas_addr),
644                             phy->attached_phy_id);
645                 return NULL;
646         }
647         child = kzalloc(sizeof(*child), GFP_KERNEL);
648         if (!child)
649                 return NULL;
650         switch (phy->attached_dev_type) {
651         case EDGE_DEV:
652                 rphy = sas_expander_alloc(phy->phy, SAS_EDGE_EXPANDER_DEVICE);
653                 break;
654         case FANOUT_DEV:
655                 rphy = sas_expander_alloc(phy->phy, SAS_FANOUT_EXPANDER_DEVICE);
656                 break;
657         default:
658                 rphy = NULL;    /* shut gcc up */
659                 BUG();
660         }
661         child->rphy = rphy;
662         edev = rphy_to_expander_device(rphy);
663         child->dev_type = phy->attached_dev_type;
664         child->parent = parent;
665         child->port = parent->port;
666         child->iproto = phy->attached_iproto;
667         child->tproto = phy->attached_tproto;
668         memcpy(child->sas_addr, phy->attached_sas_addr, SAS_ADDR_SIZE);
669         sas_hash_addr(child->hashed_sas_addr, child->sas_addr);
670         sas_ex_get_linkrate(parent, child, phy);
671         edev->level = parent_ex->level + 1;
672         parent->port->disc.max_level = max(parent->port->disc.max_level,
673                                            edev->level);
674         sas_init_dev(child);
675         res = sas_discover_expander(child);
676         if (res) {
677                 kfree(child);
678                 return NULL;
679         }
680         return child;
681 }
682
683 static int sas_ex_discover_dev(struct domain_device *dev, int phy_id)
684 {
685         struct expander_device *ex = &dev->ex_dev;
686         struct ex_phy *ex_phy = &ex->ex_phy[phy_id];
687         struct domain_device *child = NULL;
688         int res = 0;
689
690         /* Phy state */
691         if (ex_phy->linkrate == PHY_SPINUP_HOLD) {
692                 if (!smp_phy_control(dev, phy_id, PHY_FUNC_LINK_RESET))
693                         res = sas_ex_phy_discover(dev, phy_id);
694                 if (res)
695                         return res;
696         }
697
698         /* Parent and domain coherency */
699         if (!dev->parent && (SAS_ADDR(ex_phy->attached_sas_addr) ==
700                              SAS_ADDR(dev->port->sas_addr)))
701                 return 0;
702         if (dev->parent && (SAS_ADDR(ex_phy->attached_sas_addr) ==
703                             SAS_ADDR(dev->parent->sas_addr)))
704                 return 0;
705         if (sas_dev_present_in_domain(dev->port, ex_phy->attached_sas_addr))
706                 sas_ex_disable_port(dev, ex_phy->attached_sas_addr);
707
708         if (ex_phy->attached_dev_type == NO_DEVICE) {
709                 if (ex_phy->routing_attr == DIRECT_ROUTING) {
710                         memset(ex_phy->attached_sas_addr, 0, SAS_ADDR_SIZE);
711                         sas_configure_routing(dev, ex_phy->attached_sas_addr);
712                 }
713                 return 0;
714         } else if (ex_phy->linkrate == PHY_LINKRATE_UNKNOWN)
715                 return 0;
716
717         if (ex_phy->attached_dev_type != SAS_END_DEV &&
718             ex_phy->attached_dev_type != FANOUT_DEV &&
719             ex_phy->attached_dev_type != EDGE_DEV) {
720                 SAS_DPRINTK("unknown device type(0x%x) attached to ex %016llx "
721                             "phy 0x%x\n", ex_phy->attached_dev_type,
722                             SAS_ADDR(dev->sas_addr),
723                             phy_id);
724                 return 0;
725         }
726
727         res = sas_configure_routing(dev, ex_phy->attached_sas_addr);
728         if (res) {
729                 SAS_DPRINTK("configure routing for dev %016llx "
730                             "reported 0x%x. Forgotten\n",
731                             SAS_ADDR(ex_phy->attached_sas_addr), res);
732                 sas_disable_routing(dev, ex_phy->attached_sas_addr);
733                 return res;
734         }
735
736         switch (ex_phy->attached_dev_type) {
737         case SAS_END_DEV:
738                 child = sas_ex_discover_end_dev(dev, phy_id);
739                 break;
740         case FANOUT_DEV:
741                 if (SAS_ADDR(dev->port->disc.fanout_sas_addr)) {
742                         SAS_DPRINTK("second fanout expander %016llx phy 0x%x "
743                                     "attached to ex %016llx phy 0x%x\n",
744                                     SAS_ADDR(ex_phy->attached_sas_addr),
745                                     ex_phy->attached_phy_id,
746                                     SAS_ADDR(dev->sas_addr),
747                                     phy_id);
748                         sas_ex_disable_phy(dev, phy_id);
749                         break;
750                 } else
751                         memcpy(dev->port->disc.fanout_sas_addr,
752                                ex_phy->attached_sas_addr, SAS_ADDR_SIZE);
753                 /* fallthrough */
754         case EDGE_DEV:
755                 child = sas_ex_discover_expander(dev, phy_id);
756                 break;
757         default:
758                 break;
759         }
760
761         if (child) {
762                 int i;
763
764                 for (i = 0; i < ex->num_phys; i++) {
765                         if (ex->ex_phy[i].phy_state == PHY_VACANT ||
766                             ex->ex_phy[i].phy_state == PHY_NOT_PRESENT)
767                                 continue;
768
769                         if (SAS_ADDR(ex->ex_phy[i].attached_sas_addr) ==
770                             SAS_ADDR(child->sas_addr))
771                                 ex->ex_phy[i].phy_state= PHY_DEVICE_DISCOVERED;
772                 }
773         }
774
775         return res;
776 }
777
778 static inline int sas_find_sub_addr(struct domain_device *dev, u8 *sub_addr)
779 {
780         struct expander_device *ex = &dev->ex_dev;
781         int i;
782
783         for (i = 0; i < ex->num_phys; i++) {
784                 struct ex_phy *phy = &ex->ex_phy[i];
785
786                 if (phy->phy_state == PHY_VACANT ||
787                     phy->phy_state == PHY_NOT_PRESENT)
788                         continue;
789
790                 if ((phy->attached_dev_type == EDGE_DEV ||
791                      phy->attached_dev_type == FANOUT_DEV) &&
792                     phy->routing_attr == SUBTRACTIVE_ROUTING) {
793
794                         memcpy(sub_addr, phy->attached_sas_addr,SAS_ADDR_SIZE);
795
796                         return 1;
797                 }
798         }
799         return 0;
800 }
801
802 static int sas_check_level_subtractive_boundary(struct domain_device *dev)
803 {
804         struct expander_device *ex = &dev->ex_dev;
805         struct domain_device *child;
806         u8 sub_addr[8] = {0, };
807
808         list_for_each_entry(child, &ex->children, siblings) {
809                 if (child->dev_type != EDGE_DEV &&
810                     child->dev_type != FANOUT_DEV)
811                         continue;
812                 if (sub_addr[0] == 0) {
813                         sas_find_sub_addr(child, sub_addr);
814                         continue;
815                 } else {
816                         u8 s2[8];
817
818                         if (sas_find_sub_addr(child, s2) &&
819                             (SAS_ADDR(sub_addr) != SAS_ADDR(s2))) {
820
821                                 SAS_DPRINTK("ex %016llx->%016llx-?->%016llx "
822                                             "diverges from subtractive "
823                                             "boundary %016llx\n",
824                                             SAS_ADDR(dev->sas_addr),
825                                             SAS_ADDR(child->sas_addr),
826                                             SAS_ADDR(s2),
827                                             SAS_ADDR(sub_addr));
828
829                                 sas_ex_disable_port(child, s2);
830                         }
831                 }
832         }
833         return 0;
834 }
835 /**
836  * sas_ex_discover_devices -- discover devices attached to this expander
837  * dev: pointer to the expander domain device
838  * single: if you want to do a single phy, else set to -1;
839  *
840  * Configure this expander for use with its devices and register the
841  * devices of this expander.
842  */
843 static int sas_ex_discover_devices(struct domain_device *dev, int single)
844 {
845         struct expander_device *ex = &dev->ex_dev;
846         int i = 0, end = ex->num_phys;
847         int res = 0;
848
849         if (0 <= single && single < end) {
850                 i = single;
851                 end = i+1;
852         }
853
854         for ( ; i < end; i++) {
855                 struct ex_phy *ex_phy = &ex->ex_phy[i];
856
857                 if (ex_phy->phy_state == PHY_VACANT ||
858                     ex_phy->phy_state == PHY_NOT_PRESENT ||
859                     ex_phy->phy_state == PHY_DEVICE_DISCOVERED)
860                         continue;
861
862                 switch (ex_phy->linkrate) {
863                 case PHY_DISABLED:
864                 case PHY_RESET_PROBLEM:
865                 case PHY_PORT_SELECTOR:
866                         continue;
867                 default:
868                         res = sas_ex_discover_dev(dev, i);
869                         if (res)
870                                 break;
871                         continue;
872                 }
873         }
874
875         if (!res)
876                 sas_check_level_subtractive_boundary(dev);
877
878         return res;
879 }
880
881 static int sas_check_ex_subtractive_boundary(struct domain_device *dev)
882 {
883         struct expander_device *ex = &dev->ex_dev;
884         int i;
885         u8  *sub_sas_addr = NULL;
886
887         if (dev->dev_type != EDGE_DEV)
888                 return 0;
889
890         for (i = 0; i < ex->num_phys; i++) {
891                 struct ex_phy *phy = &ex->ex_phy[i];
892
893                 if (phy->phy_state == PHY_VACANT ||
894                     phy->phy_state == PHY_NOT_PRESENT)
895                         continue;
896
897                 if ((phy->attached_dev_type == FANOUT_DEV ||
898                      phy->attached_dev_type == EDGE_DEV) &&
899                     phy->routing_attr == SUBTRACTIVE_ROUTING) {
900
901                         if (!sub_sas_addr)
902                                 sub_sas_addr = &phy->attached_sas_addr[0];
903                         else if (SAS_ADDR(sub_sas_addr) !=
904                                  SAS_ADDR(phy->attached_sas_addr)) {
905
906                                 SAS_DPRINTK("ex %016llx phy 0x%x "
907                                             "diverges(%016llx) on subtractive "
908                                             "boundary(%016llx). Disabled\n",
909                                             SAS_ADDR(dev->sas_addr), i,
910                                             SAS_ADDR(phy->attached_sas_addr),
911                                             SAS_ADDR(sub_sas_addr));
912                                 sas_ex_disable_phy(dev, i);
913                         }
914                 }
915         }
916         return 0;
917 }
918
919 static inline void sas_print_parent_topology_bug(struct domain_device *child,
920                                                  struct ex_phy *parent_phy,
921                                                  struct ex_phy *child_phy)
922 {
923         static const char ra_char[] = {
924                 [DIRECT_ROUTING] = 'D',
925                 [SUBTRACTIVE_ROUTING] = 'S',
926                 [TABLE_ROUTING] = 'T',
927         };
928         static const char *ex_type[] = {
929                 [EDGE_DEV] = "edge",
930                 [FANOUT_DEV] = "fanout",
931         };
932         struct domain_device *parent = child->parent;
933
934         sas_printk("%s ex %016llx phy 0x%x <--> %s ex %016llx phy 0x%x "
935                    "has %c:%c routing link!\n",
936
937                    ex_type[parent->dev_type],
938                    SAS_ADDR(parent->sas_addr),
939                    parent_phy->phy_id,
940
941                    ex_type[child->dev_type],
942                    SAS_ADDR(child->sas_addr),
943                    child_phy->phy_id,
944
945                    ra_char[parent_phy->routing_attr],
946                    ra_char[child_phy->routing_attr]);
947 }
948
949 static inline int sas_check_eeds(struct domain_device *child,
950                                  struct ex_phy *parent_phy,
951                                  struct ex_phy *child_phy)
952 {
953         int res = 0;
954         struct domain_device *parent = child->parent;
955
956         if (SAS_ADDR(parent->port->disc.fanout_sas_addr) != 0) {
957                 res = -ENODEV;
958                 SAS_DPRINTK("edge ex %016llx phy S:0x%x <--> edge ex %016llx "
959                             "phy S:0x%x, while there is a fanout ex %016llx\n",
960                             SAS_ADDR(parent->sas_addr),
961                             parent_phy->phy_id,
962                             SAS_ADDR(child->sas_addr),
963                             child_phy->phy_id,
964                             SAS_ADDR(parent->port->disc.fanout_sas_addr));
965         } else if (SAS_ADDR(parent->port->disc.eeds_a) == 0) {
966                 memcpy(parent->port->disc.eeds_a, parent->sas_addr,
967                        SAS_ADDR_SIZE);
968                 memcpy(parent->port->disc.eeds_b, child->sas_addr,
969                        SAS_ADDR_SIZE);
970         } else if (((SAS_ADDR(parent->port->disc.eeds_a) ==
971                     SAS_ADDR(parent->sas_addr)) ||
972                    (SAS_ADDR(parent->port->disc.eeds_a) ==
973                     SAS_ADDR(child->sas_addr)))
974                    &&
975                    ((SAS_ADDR(parent->port->disc.eeds_b) ==
976                      SAS_ADDR(parent->sas_addr)) ||
977                     (SAS_ADDR(parent->port->disc.eeds_b) ==
978                      SAS_ADDR(child->sas_addr))))
979                 ;
980         else {
981                 res = -ENODEV;
982                 SAS_DPRINTK("edge ex %016llx phy 0x%x <--> edge ex %016llx "
983                             "phy 0x%x link forms a third EEDS!\n",
984                             SAS_ADDR(parent->sas_addr),
985                             parent_phy->phy_id,
986                             SAS_ADDR(child->sas_addr),
987                             child_phy->phy_id);
988         }
989
990         return res;
991 }
992
993 /* Here we spill over 80 columns.  It is intentional.
994  */
995 static int sas_check_parent_topology(struct domain_device *child)
996 {
997         struct expander_device *child_ex = &child->ex_dev;
998         struct expander_device *parent_ex;
999         int i;
1000         int res = 0;
1001
1002         if (!child->parent)
1003                 return 0;
1004
1005         if (child->parent->dev_type != EDGE_DEV &&
1006             child->parent->dev_type != FANOUT_DEV)
1007                 return 0;
1008
1009         parent_ex = &child->parent->ex_dev;
1010
1011         for (i = 0; i < parent_ex->num_phys; i++) {
1012                 struct ex_phy *parent_phy = &parent_ex->ex_phy[i];
1013                 struct ex_phy *child_phy;
1014
1015                 if (parent_phy->phy_state == PHY_VACANT ||
1016                     parent_phy->phy_state == PHY_NOT_PRESENT)
1017                         continue;
1018
1019                 if (SAS_ADDR(parent_phy->attached_sas_addr) != SAS_ADDR(child->sas_addr))
1020                         continue;
1021
1022                 child_phy = &child_ex->ex_phy[parent_phy->attached_phy_id];
1023
1024                 switch (child->parent->dev_type) {
1025                 case EDGE_DEV:
1026                         if (child->dev_type == FANOUT_DEV) {
1027                                 if (parent_phy->routing_attr != SUBTRACTIVE_ROUTING ||
1028                                     child_phy->routing_attr != TABLE_ROUTING) {
1029                                         sas_print_parent_topology_bug(child, parent_phy, child_phy);
1030                                         res = -ENODEV;
1031                                 }
1032                         } else if (parent_phy->routing_attr == SUBTRACTIVE_ROUTING) {
1033                                 if (child_phy->routing_attr == SUBTRACTIVE_ROUTING) {
1034                                         res = sas_check_eeds(child, parent_phy, child_phy);
1035                                 } else if (child_phy->routing_attr != TABLE_ROUTING) {
1036                                         sas_print_parent_topology_bug(child, parent_phy, child_phy);
1037                                         res = -ENODEV;
1038                                 }
1039                         } else if (parent_phy->routing_attr == TABLE_ROUTING &&
1040                                    child_phy->routing_attr != SUBTRACTIVE_ROUTING) {
1041                                 sas_print_parent_topology_bug(child, parent_phy, child_phy);
1042                                 res = -ENODEV;
1043                         }
1044                         break;
1045                 case FANOUT_DEV:
1046                         if (parent_phy->routing_attr != TABLE_ROUTING ||
1047                             child_phy->routing_attr != SUBTRACTIVE_ROUTING) {
1048                                 sas_print_parent_topology_bug(child, parent_phy, child_phy);
1049                                 res = -ENODEV;
1050                         }
1051                         break;
1052                 default:
1053                         break;
1054                 }
1055         }
1056
1057         return res;
1058 }
1059
1060 #define RRI_REQ_SIZE  16
1061 #define RRI_RESP_SIZE 44
1062
1063 static int sas_configure_present(struct domain_device *dev, int phy_id,
1064                                  u8 *sas_addr, int *index, int *present)
1065 {
1066         int i, res = 0;
1067         struct expander_device *ex = &dev->ex_dev;
1068         struct ex_phy *phy = &ex->ex_phy[phy_id];
1069         u8 *rri_req;
1070         u8 *rri_resp;
1071
1072         *present = 0;
1073         *index = 0;
1074
1075         rri_req = alloc_smp_req(RRI_REQ_SIZE);
1076         if (!rri_req)
1077                 return -ENOMEM;
1078
1079         rri_resp = alloc_smp_resp(RRI_RESP_SIZE);
1080         if (!rri_resp) {
1081                 kfree(rri_req);
1082                 return -ENOMEM;
1083         }
1084
1085         rri_req[1] = SMP_REPORT_ROUTE_INFO;
1086         rri_req[9] = phy_id;
1087
1088         for (i = 0; i < ex->max_route_indexes ; i++) {
1089                 *(__be16 *)(rri_req+6) = cpu_to_be16(i);
1090                 res = smp_execute_task(dev, rri_req, RRI_REQ_SIZE, rri_resp,
1091                                        RRI_RESP_SIZE);
1092                 if (res)
1093                         goto out;
1094                 res = rri_resp[2];
1095                 if (res == SMP_RESP_NO_INDEX) {
1096                         SAS_DPRINTK("overflow of indexes: dev %016llx "
1097                                     "phy 0x%x index 0x%x\n",
1098                                     SAS_ADDR(dev->sas_addr), phy_id, i);
1099                         goto out;
1100                 } else if (res != SMP_RESP_FUNC_ACC) {
1101                         SAS_DPRINTK("%s: dev %016llx phy 0x%x index 0x%x "
1102                                     "result 0x%x\n", __FUNCTION__,
1103                                     SAS_ADDR(dev->sas_addr), phy_id, i, res);
1104                         goto out;
1105                 }
1106                 if (SAS_ADDR(sas_addr) != 0) {
1107                         if (SAS_ADDR(rri_resp+16) == SAS_ADDR(sas_addr)) {
1108                                 *index = i;
1109                                 if ((rri_resp[12] & 0x80) == 0x80)
1110                                         *present = 0;
1111                                 else
1112                                         *present = 1;
1113                                 goto out;
1114                         } else if (SAS_ADDR(rri_resp+16) == 0) {
1115                                 *index = i;
1116                                 *present = 0;
1117                                 goto out;
1118                         }
1119                 } else if (SAS_ADDR(rri_resp+16) == 0 &&
1120                            phy->last_da_index < i) {
1121                         phy->last_da_index = i;
1122                         *index = i;
1123                         *present = 0;
1124                         goto out;
1125                 }
1126         }
1127         res = -1;
1128 out:
1129         kfree(rri_req);
1130         kfree(rri_resp);
1131         return res;
1132 }
1133
1134 #define CRI_REQ_SIZE  44
1135 #define CRI_RESP_SIZE  8
1136
1137 static int sas_configure_set(struct domain_device *dev, int phy_id,
1138                              u8 *sas_addr, int index, int include)
1139 {
1140         int res;
1141         u8 *cri_req;
1142         u8 *cri_resp;
1143
1144         cri_req = alloc_smp_req(CRI_REQ_SIZE);
1145         if (!cri_req)
1146                 return -ENOMEM;
1147
1148         cri_resp = alloc_smp_resp(CRI_RESP_SIZE);
1149         if (!cri_resp) {
1150                 kfree(cri_req);
1151                 return -ENOMEM;
1152         }
1153
1154         cri_req[1] = SMP_CONF_ROUTE_INFO;
1155         *(__be16 *)(cri_req+6) = cpu_to_be16(index);
1156         cri_req[9] = phy_id;
1157         if (SAS_ADDR(sas_addr) == 0 || !include)
1158                 cri_req[12] |= 0x80;
1159         memcpy(cri_req+16, sas_addr, SAS_ADDR_SIZE);
1160
1161         res = smp_execute_task(dev, cri_req, CRI_REQ_SIZE, cri_resp,
1162                                CRI_RESP_SIZE);
1163         if (res)
1164                 goto out;
1165         res = cri_resp[2];
1166         if (res == SMP_RESP_NO_INDEX) {
1167                 SAS_DPRINTK("overflow of indexes: dev %016llx phy 0x%x "
1168                             "index 0x%x\n",
1169                             SAS_ADDR(dev->sas_addr), phy_id, index);
1170         }
1171 out:
1172         kfree(cri_req);
1173         kfree(cri_resp);
1174         return res;
1175 }
1176
1177 static inline int sas_configure_phy(struct domain_device *dev, int phy_id,
1178                                     u8 *sas_addr, int include)
1179 {
1180         int index;
1181         int present;
1182         int res;
1183
1184         res = sas_configure_present(dev, phy_id, sas_addr, &index, &present);
1185         if (res)
1186                 return res;
1187         if (include ^ present)
1188                 return sas_configure_set(dev, phy_id, sas_addr, index,include);
1189
1190         return res;
1191 }
1192
1193 /**
1194  * sas_configure_parent -- configure routing table of parent
1195  * parent: parent expander
1196  * child: child expander
1197  * sas_addr: SAS port identifier of device directly attached to child
1198  */
1199 static int sas_configure_parent(struct domain_device *parent,
1200                                 struct domain_device *child,
1201                                 u8 *sas_addr, int include)
1202 {
1203         struct expander_device *ex_parent = &parent->ex_dev;
1204         int res = 0;
1205         int i;
1206
1207         if (parent->parent) {
1208                 res = sas_configure_parent(parent->parent, parent, sas_addr,
1209                                            include);
1210                 if (res)
1211                         return res;
1212         }
1213
1214         if (ex_parent->conf_route_table == 0) {
1215                 SAS_DPRINTK("ex %016llx has self-configuring routing table\n",
1216                             SAS_ADDR(parent->sas_addr));
1217                 return 0;
1218         }
1219
1220         for (i = 0; i < ex_parent->num_phys; i++) {
1221                 struct ex_phy *phy = &ex_parent->ex_phy[i];
1222
1223                 if ((phy->routing_attr == TABLE_ROUTING) &&
1224                     (SAS_ADDR(phy->attached_sas_addr) ==
1225                      SAS_ADDR(child->sas_addr))) {
1226                         res = sas_configure_phy(parent, i, sas_addr, include);
1227                         if (res)
1228                                 return res;
1229                 }
1230         }
1231
1232         return res;
1233 }
1234
1235 /**
1236  * sas_configure_routing -- configure routing
1237  * dev: expander device
1238  * sas_addr: port identifier of device directly attached to the expander device
1239  */
1240 static int sas_configure_routing(struct domain_device *dev, u8 *sas_addr)
1241 {
1242         if (dev->parent)
1243                 return sas_configure_parent(dev->parent, dev, sas_addr, 1);
1244         return 0;
1245 }
1246
1247 static int sas_disable_routing(struct domain_device *dev,  u8 *sas_addr)
1248 {
1249         if (dev->parent)
1250                 return sas_configure_parent(dev->parent, dev, sas_addr, 0);
1251         return 0;
1252 }
1253
1254 #if 0
1255 #define SMP_BIN_ATTR_NAME "smp_portal"
1256
1257 static void sas_ex_smp_hook(struct domain_device *dev)
1258 {
1259         struct expander_device *ex_dev = &dev->ex_dev;
1260         struct bin_attribute *bin_attr = &ex_dev->smp_bin_attr;
1261
1262         memset(bin_attr, 0, sizeof(*bin_attr));
1263
1264         bin_attr->attr.name = SMP_BIN_ATTR_NAME;
1265         bin_attr->attr.owner = THIS_MODULE;
1266         bin_attr->attr.mode = 0600;
1267
1268         bin_attr->size = 0;
1269         bin_attr->private = NULL;
1270         bin_attr->read = smp_portal_read;
1271         bin_attr->write= smp_portal_write;
1272         bin_attr->mmap = NULL;
1273
1274         ex_dev->smp_portal_pid = -1;
1275         init_MUTEX(&ex_dev->smp_sema);
1276 }
1277 #endif
1278
1279 /**
1280  * sas_discover_expander -- expander discovery
1281  * @ex: pointer to expander domain device
1282  *
1283  * See comment in sas_discover_sata().
1284  */
1285 static int sas_discover_expander(struct domain_device *dev)
1286 {
1287         int res;
1288
1289         res = sas_notify_lldd_dev_found(dev);
1290         if (res)
1291                 return res;
1292
1293         res = sas_ex_general(dev);
1294         if (res)
1295                 goto out_err;
1296         res = sas_ex_manuf_info(dev);
1297         if (res)
1298                 goto out_err;
1299
1300         res = sas_expander_discover(dev);
1301         if (res) {
1302                 SAS_DPRINTK("expander %016llx discovery failed(0x%x)\n",
1303                             SAS_ADDR(dev->sas_addr), res);
1304                 goto out_err;
1305         }
1306
1307         sas_check_ex_subtractive_boundary(dev);
1308         res = sas_check_parent_topology(dev);
1309         if (res)
1310                 goto out_err;
1311         return 0;
1312 out_err:
1313         sas_notify_lldd_dev_gone(dev);
1314         return res;
1315 }
1316
1317 static int sas_ex_level_discovery(struct sas_port *port, const int level)
1318 {
1319         int res = 0;
1320         struct domain_device *dev;
1321
1322         list_for_each_entry(dev, &port->dev_list, dev_list_node) {
1323                 if (dev->dev_type == EDGE_DEV ||
1324                     dev->dev_type == FANOUT_DEV) {
1325                         struct sas_expander_device *ex =
1326                                 rphy_to_expander_device(dev->rphy);
1327
1328                         if (level == ex->level)
1329                                 res = sas_ex_discover_devices(dev, -1);
1330                 }
1331         }
1332
1333         return res;
1334 }
1335
1336 static int sas_ex_bfs_disc(struct sas_port *port)
1337 {
1338         int res;
1339         int level;
1340
1341         do {
1342                 level = port->disc.max_level;
1343                 res = sas_ex_level_discovery(port, level);
1344                 mb();
1345         } while (level < port->disc.max_level);
1346
1347         return res;
1348 }
1349
1350 int sas_discover_root_expander(struct domain_device *dev)
1351 {
1352         int res;
1353         struct sas_expander_device *ex = rphy_to_expander_device(dev->rphy);
1354
1355         sas_rphy_add(dev->rphy);
1356
1357         ex->level = dev->port->disc.max_level; /* 0 */
1358         res = sas_discover_expander(dev);
1359         if (!res)
1360                 sas_ex_bfs_disc(dev->port);
1361
1362         return res;
1363 }
1364
1365 /* ---------- Domain revalidation ---------- */
1366
1367 static int sas_get_phy_discover(struct domain_device *dev,
1368                                 int phy_id, struct smp_resp *disc_resp)
1369 {
1370         int res;
1371         u8 *disc_req;
1372
1373         disc_req = alloc_smp_req(DISCOVER_REQ_SIZE);
1374         if (!disc_req)
1375                 return -ENOMEM;
1376
1377         disc_req[1] = SMP_DISCOVER;
1378         disc_req[9] = phy_id;
1379
1380         res = smp_execute_task(dev, disc_req, DISCOVER_REQ_SIZE,
1381                                disc_resp, DISCOVER_RESP_SIZE);
1382         if (res)
1383                 goto out;
1384         else if (disc_resp->result != SMP_RESP_FUNC_ACC) {
1385                 res = disc_resp->result;
1386                 goto out;
1387         }
1388 out:
1389         kfree(disc_req);
1390         return res;
1391 }
1392
1393 static int sas_get_phy_change_count(struct domain_device *dev,
1394                                     int phy_id, int *pcc)
1395 {
1396         int res;
1397         struct smp_resp *disc_resp;
1398
1399         disc_resp = alloc_smp_resp(DISCOVER_RESP_SIZE);
1400         if (!disc_resp)
1401                 return -ENOMEM;
1402
1403         res = sas_get_phy_discover(dev, phy_id, disc_resp);
1404         if (!res)
1405                 *pcc = disc_resp->disc.change_count;
1406
1407         kfree(disc_resp);
1408         return res;
1409 }
1410
1411 static int sas_get_phy_attached_sas_addr(struct domain_device *dev,
1412                                          int phy_id, u8 *attached_sas_addr)
1413 {
1414         int res;
1415         struct smp_resp *disc_resp;
1416
1417         disc_resp = alloc_smp_resp(DISCOVER_RESP_SIZE);
1418         if (!disc_resp)
1419                 return -ENOMEM;
1420
1421         res = sas_get_phy_discover(dev, phy_id, disc_resp);
1422         if (!res)
1423                 memcpy(attached_sas_addr,disc_resp->disc.attached_sas_addr,8);
1424
1425         kfree(disc_resp);
1426         return res;
1427 }
1428
1429 static int sas_find_bcast_phy(struct domain_device *dev, int *phy_id,
1430                               int from_phy)
1431 {
1432         struct expander_device *ex = &dev->ex_dev;
1433         int res = 0;
1434         int i;
1435
1436         for (i = from_phy; i < ex->num_phys; i++) {
1437                 int phy_change_count = 0;
1438
1439                 res = sas_get_phy_change_count(dev, i, &phy_change_count);
1440                 if (res)
1441                         goto out;
1442                 else if (phy_change_count != ex->ex_phy[i].phy_change_count) {
1443                         ex->ex_phy[i].phy_change_count = phy_change_count;
1444                         *phy_id = i;
1445                         return 0;
1446                 }
1447         }
1448 out:
1449         return res;
1450 }
1451
1452 static int sas_get_ex_change_count(struct domain_device *dev, int *ecc)
1453 {
1454         int res;
1455         u8  *rg_req;
1456         struct smp_resp  *rg_resp;
1457
1458         rg_req = alloc_smp_req(RG_REQ_SIZE);
1459         if (!rg_req)
1460                 return -ENOMEM;
1461
1462         rg_resp = alloc_smp_resp(RG_RESP_SIZE);
1463         if (!rg_resp) {
1464                 kfree(rg_req);
1465                 return -ENOMEM;
1466         }
1467
1468         rg_req[1] = SMP_REPORT_GENERAL;
1469
1470         res = smp_execute_task(dev, rg_req, RG_REQ_SIZE, rg_resp,
1471                                RG_RESP_SIZE);
1472         if (res)
1473                 goto out;
1474         if (rg_resp->result != SMP_RESP_FUNC_ACC) {
1475                 res = rg_resp->result;
1476                 goto out;
1477         }
1478
1479         *ecc = be16_to_cpu(rg_resp->rg.change_count);
1480 out:
1481         kfree(rg_resp);
1482         kfree(rg_req);
1483         return res;
1484 }
1485
1486 static int sas_find_bcast_dev(struct domain_device *dev,
1487                               struct domain_device **src_dev)
1488 {
1489         struct expander_device *ex = &dev->ex_dev;
1490         int ex_change_count = -1;
1491         int res;
1492
1493         res = sas_get_ex_change_count(dev, &ex_change_count);
1494         if (res)
1495                 goto out;
1496         if (ex_change_count != -1 &&
1497             ex_change_count != ex->ex_change_count) {
1498                 *src_dev = dev;
1499                 ex->ex_change_count = ex_change_count;
1500         } else {
1501                 struct domain_device *ch;
1502
1503                 list_for_each_entry(ch, &ex->children, siblings) {
1504                         if (ch->dev_type == EDGE_DEV ||
1505                             ch->dev_type == FANOUT_DEV) {
1506                                 res = sas_find_bcast_dev(ch, src_dev);
1507                                 if (src_dev)
1508                                         return res;
1509                         }
1510                 }
1511         }
1512 out:
1513         return res;
1514 }
1515
1516 static void sas_unregister_ex_tree(struct domain_device *dev)
1517 {
1518         struct expander_device *ex = &dev->ex_dev;
1519         struct domain_device *child, *n;
1520
1521         list_for_each_entry_safe(child, n, &ex->children, siblings) {
1522                 if (child->dev_type == EDGE_DEV ||
1523                     child->dev_type == FANOUT_DEV)
1524                         sas_unregister_ex_tree(child);
1525                 else
1526                         sas_unregister_dev(child);
1527         }
1528         sas_unregister_dev(dev);
1529 }
1530
1531 static void sas_unregister_devs_sas_addr(struct domain_device *parent,
1532                                          int phy_id)
1533 {
1534         struct expander_device *ex_dev = &parent->ex_dev;
1535         struct ex_phy *phy = &ex_dev->ex_phy[phy_id];
1536         struct domain_device *child, *n;
1537
1538         list_for_each_entry_safe(child, n, &ex_dev->children, siblings) {
1539                 if (SAS_ADDR(child->sas_addr) ==
1540                     SAS_ADDR(phy->attached_sas_addr)) {
1541                         if (child->dev_type == EDGE_DEV ||
1542                             child->dev_type == FANOUT_DEV)
1543                                 sas_unregister_ex_tree(child);
1544                         else
1545                                 sas_unregister_dev(child);
1546                         break;
1547                 }
1548         }
1549         sas_disable_routing(parent, phy->attached_sas_addr);
1550         memset(phy->attached_sas_addr, 0, SAS_ADDR_SIZE);
1551 }
1552
1553 static int sas_discover_bfs_by_root_level(struct domain_device *root,
1554                                           const int level)
1555 {
1556         struct expander_device *ex_root = &root->ex_dev;
1557         struct domain_device *child;
1558         int res = 0;
1559
1560         list_for_each_entry(child, &ex_root->children, siblings) {
1561                 if (child->dev_type == EDGE_DEV ||
1562                     child->dev_type == FANOUT_DEV) {
1563                         struct sas_expander_device *ex =
1564                                 rphy_to_expander_device(child->rphy);
1565
1566                         if (level > ex->level)
1567                                 res = sas_discover_bfs_by_root_level(child,
1568                                                                      level);
1569                         else if (level == ex->level)
1570                                 res = sas_ex_discover_devices(child, -1);
1571                 }
1572         }
1573         return res;
1574 }
1575
1576 static int sas_discover_bfs_by_root(struct domain_device *dev)
1577 {
1578         int res;
1579         struct sas_expander_device *ex = rphy_to_expander_device(dev->rphy);
1580         int level = ex->level+1;
1581
1582         res = sas_ex_discover_devices(dev, -1);
1583         if (res)
1584                 goto out;
1585         do {
1586                 res = sas_discover_bfs_by_root_level(dev, level);
1587                 mb();
1588                 level += 1;
1589         } while (level <= dev->port->disc.max_level);
1590 out:
1591         return res;
1592 }
1593
1594 static inline int sas_discover_new(struct domain_device *dev, int phy_id)
1595 {
1596         struct ex_phy *ex_phy = &dev->ex_dev.ex_phy[phy_id];
1597         struct domain_device *child;
1598         int res;
1599
1600         SAS_DPRINTK("ex %016llx phy%d new device attached\n",
1601                     SAS_ADDR(dev->sas_addr), phy_id);
1602         res = sas_ex_phy_discover(dev, phy_id);
1603         if (res)
1604                 goto out;
1605         res = sas_ex_discover_devices(dev, phy_id);
1606         if (res)
1607                 goto out;
1608         list_for_each_entry(child, &dev->ex_dev.children, siblings) {
1609                 if (SAS_ADDR(child->sas_addr) ==
1610                     SAS_ADDR(ex_phy->attached_sas_addr)) {
1611                         if (child->dev_type == EDGE_DEV ||
1612                             child->dev_type == FANOUT_DEV)
1613                                 res = sas_discover_bfs_by_root(child);
1614                         break;
1615                 }
1616         }
1617 out:
1618         return res;
1619 }
1620
1621 static int sas_rediscover_dev(struct domain_device *dev, int phy_id)
1622 {
1623         struct expander_device *ex = &dev->ex_dev;
1624         struct ex_phy *phy = &ex->ex_phy[phy_id];
1625         u8 attached_sas_addr[8];
1626         int res;
1627
1628         res = sas_get_phy_attached_sas_addr(dev, phy_id, attached_sas_addr);
1629         switch (res) {
1630         case SMP_RESP_NO_PHY:
1631                 phy->phy_state = PHY_NOT_PRESENT;
1632                 sas_unregister_devs_sas_addr(dev, phy_id);
1633                 goto out; break;
1634         case SMP_RESP_PHY_VACANT:
1635                 phy->phy_state = PHY_VACANT;
1636                 sas_unregister_devs_sas_addr(dev, phy_id);
1637                 goto out; break;
1638         case SMP_RESP_FUNC_ACC:
1639                 break;
1640         }
1641
1642         if (SAS_ADDR(attached_sas_addr) == 0) {
1643                 phy->phy_state = PHY_EMPTY;
1644                 sas_unregister_devs_sas_addr(dev, phy_id);
1645         } else if (SAS_ADDR(attached_sas_addr) ==
1646                    SAS_ADDR(phy->attached_sas_addr)) {
1647                 SAS_DPRINTK("ex %016llx phy 0x%x broadcast flutter\n",
1648                             SAS_ADDR(dev->sas_addr), phy_id);
1649         } else
1650                 res = sas_discover_new(dev, phy_id);
1651 out:
1652         return res;
1653 }
1654
1655 static int sas_rediscover(struct domain_device *dev, const int phy_id)
1656 {
1657         struct expander_device *ex = &dev->ex_dev;
1658         struct ex_phy *changed_phy = &ex->ex_phy[phy_id];
1659         int res = 0;
1660         int i;
1661
1662         SAS_DPRINTK("ex %016llx phy%d originated BROADCAST(CHANGE)\n",
1663                     SAS_ADDR(dev->sas_addr), phy_id);
1664
1665         if (SAS_ADDR(changed_phy->attached_sas_addr) != 0) {
1666                 for (i = 0; i < ex->num_phys; i++) {
1667                         struct ex_phy *phy = &ex->ex_phy[i];
1668
1669                         if (i == phy_id)
1670                                 continue;
1671                         if (SAS_ADDR(phy->attached_sas_addr) ==
1672                             SAS_ADDR(changed_phy->attached_sas_addr)) {
1673                                 SAS_DPRINTK("phy%d part of wide port with "
1674                                             "phy%d\n", phy_id, i);
1675                                 goto out;
1676                         }
1677                 }
1678                 res = sas_rediscover_dev(dev, phy_id);
1679         } else
1680                 res = sas_discover_new(dev, phy_id);
1681 out:
1682         return res;
1683 }
1684
1685 /**
1686  * sas_revalidate_domain -- revalidate the domain
1687  * @port: port to the domain of interest
1688  *
1689  * NOTE: this process _must_ quit (return) as soon as any connection
1690  * errors are encountered.  Connection recovery is done elsewhere.
1691  * Discover process only interrogates devices in order to discover the
1692  * domain.
1693  */
1694 int sas_ex_revalidate_domain(struct domain_device *port_dev)
1695 {
1696         int res;
1697         struct domain_device *dev = NULL;
1698
1699         res = sas_find_bcast_dev(port_dev, &dev);
1700         if (res)
1701                 goto out;
1702         if (dev) {
1703                 struct expander_device *ex = &dev->ex_dev;
1704                 int i = 0, phy_id;
1705
1706                 do {
1707                         phy_id = -1;
1708                         res = sas_find_bcast_phy(dev, &phy_id, i);
1709                         if (phy_id == -1)
1710                                 break;
1711                         res = sas_rediscover(dev, phy_id);
1712                         i = phy_id + 1;
1713                 } while (i < ex->num_phys);
1714         }
1715 out:
1716         return res;
1717 }
1718
1719 #if 0
1720 /* ---------- SMP portal ---------- */
1721
1722 static ssize_t smp_portal_write(struct kobject *kobj, char *buf, loff_t offs,
1723                                 size_t size)
1724 {
1725         struct domain_device *dev = to_dom_device(kobj);
1726         struct expander_device *ex = &dev->ex_dev;
1727
1728         if (offs != 0)
1729                 return -EFBIG;
1730         else if (size == 0)
1731                 return 0;
1732
1733         down_interruptible(&ex->smp_sema);
1734         if (ex->smp_req)
1735                 kfree(ex->smp_req);
1736         ex->smp_req = kzalloc(size, GFP_USER);
1737         if (!ex->smp_req) {
1738                 up(&ex->smp_sema);
1739                 return -ENOMEM;
1740         }
1741         memcpy(ex->smp_req, buf, size);
1742         ex->smp_req_size = size;
1743         ex->smp_portal_pid = current->pid;
1744         up(&ex->smp_sema);
1745
1746         return size;
1747 }
1748
1749 static ssize_t smp_portal_read(struct kobject *kobj, char *buf, loff_t offs,
1750                                size_t size)
1751 {
1752         struct domain_device *dev = to_dom_device(kobj);
1753         struct expander_device *ex = &dev->ex_dev;
1754         u8 *smp_resp;
1755         int res = -EINVAL;
1756
1757         /* XXX: sysfs gives us an offset of 0x10 or 0x8 while in fact
1758          *  it should be 0.
1759          */
1760
1761         down_interruptible(&ex->smp_sema);
1762         if (!ex->smp_req || ex->smp_portal_pid != current->pid)
1763                 goto out;
1764
1765         res = 0;
1766         if (size == 0)
1767                 goto out;
1768
1769         res = -ENOMEM;
1770         smp_resp = alloc_smp_resp(size);
1771         if (!smp_resp)
1772                 goto out;
1773         res = smp_execute_task(dev, ex->smp_req, ex->smp_req_size,
1774                                smp_resp, size);
1775         if (!res) {
1776                 memcpy(buf, smp_resp, size);
1777                 res = size;
1778         }
1779
1780         kfree(smp_resp);
1781 out:
1782         kfree(ex->smp_req);
1783         ex->smp_req = NULL;
1784         ex->smp_req_size = 0;
1785         ex->smp_portal_pid = -1;
1786         up(&ex->smp_sema);
1787         return res;
1788 }
1789 #endif