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