Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]
Version: [ 2.6.11.8 ] [ 2.6.25 ] [ 2.6.25.8 ] [ 2.6.31.13 ] Architecture: [ i386 ]

Diff markup

Differences between /linux/drivers/scsi/libsas/sas_expander.c (Version 2.6.31.13) and /linux/drivers/scsi/libsas/sas_expander.c (Version 2.6.11.8)


  1 /*                                                  1 
  2  * Serial Attached SCSI (SAS) Expander discove    
  3  *                                                
  4  * Copyright (C) 2005 Adaptec, Inc.  All right    
  5  * Copyright (C) 2005 Luben Tuikov <luben_tuik    
  6  *                                                
  7  * This file is licensed under GPLv2.             
  8  *                                                
  9  * This program is free software; you can redi    
 10  * modify it under the terms of the GNU Genera    
 11  * published by the Free Software Foundation;     
 12  * License, or (at your option) any later vers    
 13  *                                                
 14  * This program is distributed in the hope tha    
 15  * WITHOUT ANY WARRANTY; without even the impl    
 16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR    
 17  * General Public License for more details.       
 18  *                                                
 19  * You should have received a copy of the GNU     
 20  * along with this program; if not, write to t    
 21  * Foundation, Inc., 51 Franklin St, Fifth Flo    
 22  *                                                
 23  */                                               
 24                                                   
 25 #include <linux/scatterlist.h>                    
 26 #include <linux/blkdev.h>                         
 27                                                   
 28 #include "sas_internal.h"                         
 29                                                   
 30 #include <scsi/scsi_transport.h>                  
 31 #include <scsi/scsi_transport_sas.h>              
 32 #include "../scsi_sas_internal.h"                 
 33                                                   
 34 static int sas_discover_expander(struct domain    
 35 static int sas_configure_routing(struct domain    
 36 static int sas_configure_phy(struct domain_dev    
 37                              u8 *sas_addr, int    
 38 static int sas_disable_routing(struct domain_d    
 39                                                   
 40 /* ---------- SMP task management ---------- *    
 41                                                   
 42 static void smp_task_timedout(unsigned long _t    
 43 {                                                 
 44         struct sas_task *task = (void *) _task    
 45         unsigned long flags;                      
 46                                                   
 47         spin_lock_irqsave(&task->task_state_lo    
 48         if (!(task->task_state_flags & SAS_TAS    
 49                 task->task_state_flags |= SAS_    
 50         spin_unlock_irqrestore(&task->task_sta    
 51                                                   
 52         complete(&task->completion);              
 53 }                                                 
 54                                                   
 55 static void smp_task_done(struct sas_task *tas    
 56 {                                                 
 57         if (!del_timer(&task->timer))             
 58                 return;                           
 59         complete(&task->completion);              
 60 }                                                 
 61                                                   
 62 /* Give it some long enough timeout. In second    
 63 #define SMP_TIMEOUT 10                            
 64                                                   
 65 static int smp_execute_task(struct domain_devi    
 66                             void *resp, int re    
 67 {                                                 
 68         int res, retry;                           
 69         struct sas_task *task = NULL;             
 70         struct sas_internal *i =                  
 71                 to_sas_internal(dev->port->ha-    
 72                                                   
 73         for (retry = 0; retry < 3; retry++) {     
 74                 task = sas_alloc_task(GFP_KERN    
 75                 if (!task)                        
 76                         return -ENOMEM;           
 77                                                   
 78                 task->dev = dev;                  
 79                 task->task_proto = dev->tproto    
 80                 sg_init_one(&task->smp_task.sm    
 81                 sg_init_one(&task->smp_task.sm    
 82                                                   
 83                 task->task_done = smp_task_don    
 84                                                   
 85                 task->timer.data = (unsigned l    
 86                 task->timer.function = smp_tas    
 87                 task->timer.expires = jiffies     
 88                 add_timer(&task->timer);          
 89                                                   
 90                 res = i->dft->lldd_execute_tas    
 91                                                   
 92                 if (res) {                        
 93                         del_timer(&task->timer    
 94                         SAS_DPRINTK("executing    
 95                         goto ex_err;              
 96                 }                                 
 97                                                   
 98                 wait_for_completion(&task->com    
 99                 res = -ECOMM;                     
100                 if ((task->task_state_flags &     
101                         SAS_DPRINTK("smp task     
102                         i->dft->lldd_abort_tas    
103                         if (!(task->task_state    
104                                 SAS_DPRINTK("S    
105                                 goto ex_err;      
106                         }                         
107                 }                                 
108                 if (task->task_status.resp ==     
109                     task->task_status.stat ==     
110                         res = 0;                  
111                         break;                    
112                 } if (task->task_status.resp =    
113                       task->task_status.stat =    
114                         /* no error, but retur    
115                          * underrun */            
116                         res = task->task_statu    
117                         break;                    
118                 } if (task->task_status.resp =    
119                       task->task_status.stat =    
120                         res = -EMSGSIZE;          
121                         break;                    
122                 } else {                          
123                         SAS_DPRINTK("%s: task     
124                                     "status 0x    
125                                     SAS_ADDR(d    
126                                     task->task    
127                                     task->task    
128                         sas_free_task(task);      
129                         task = NULL;              
130                 }                                 
131         }                                         
132 ex_err:                                           
133         BUG_ON(retry == 3 && task != NULL);       
134         if (task != NULL) {                       
135                 sas_free_task(task);              
136         }                                         
137         return res;                               
138 }                                                 
139                                                   
140 /* ---------- Allocations ---------- */           
141                                                   
142 static inline void *alloc_smp_req(int size)       
143 {                                                 
144         u8 *p = kzalloc(size, GFP_KERNEL);        
145         if (p)                                    
146                 p[0] = SMP_REQUEST;               
147         return p;                                 
148 }                                                 
149                                                   
150 static inline void *alloc_smp_resp(int size)      
151 {                                                 
152         return kzalloc(size, GFP_KERNEL);         
153 }                                                 
154                                                   
155 /* ---------- Expander configuration ---------    
156                                                   
157 static void sas_set_ex_phy(struct domain_devic    
158                            void *disc_resp)       
159 {                                                 
160         struct expander_device *ex = &dev->ex_    
161         struct ex_phy *phy = &ex->ex_phy[phy_i    
162         struct smp_resp *resp = disc_resp;        
163         struct discover_resp *dr = &resp->disc    
164         struct sas_rphy *rphy = dev->rphy;        
165         int rediscover = (phy->phy != NULL);      
166                                                   
167         if (!rediscover) {                        
168                 phy->phy = sas_phy_alloc(&rphy    
169                                                   
170                 /* FIXME: error_handling */       
171                 BUG_ON(!phy->phy);                
172         }                                         
173                                                   
174         switch (resp->result) {                   
175         case SMP_RESP_PHY_VACANT:                 
176                 phy->phy_state = PHY_VACANT;      
177                 return;                           
178         default:                                  
179                 phy->phy_state = PHY_NOT_PRESE    
180                 return;                           
181         case SMP_RESP_FUNC_ACC:                   
182                 phy->phy_state = PHY_EMPTY; /*    
183                 break;                            
184         }                                         
185                                                   
186         phy->phy_id = phy_id;                     
187         phy->attached_dev_type = dr->attached_    
188         phy->linkrate = dr->linkrate;             
189         phy->attached_sata_host = dr->attached    
190         phy->attached_sata_dev  = dr->attached    
191         phy->attached_sata_ps   = dr->attached    
192         phy->attached_iproto = dr->iproto << 1    
193         phy->attached_tproto = dr->tproto << 1    
194         memcpy(phy->attached_sas_addr, dr->att    
195         phy->attached_phy_id = dr->attached_ph    
196         phy->phy_change_count = dr->change_cou    
197         phy->routing_attr = dr->routing_attr;     
198         phy->virtual = dr->virtual;               
199         phy->last_da_index = -1;                  
200                                                   
201         phy->phy->identify.initiator_port_prot    
202         phy->phy->identify.target_port_protoco    
203         phy->phy->identify.phy_identifier = ph    
204         phy->phy->minimum_linkrate_hw = dr->hm    
205         phy->phy->maximum_linkrate_hw = dr->hm    
206         phy->phy->minimum_linkrate = dr->pmin_    
207         phy->phy->maximum_linkrate = dr->pmax_    
208         phy->phy->negotiated_linkrate = phy->l    
209                                                   
210         if (!rediscover)                          
211                 sas_phy_add(phy->phy);            
212                                                   
213         SAS_DPRINTK("ex %016llx phy%02d:%c att    
214                     SAS_ADDR(dev->sas_addr), p    
215                     phy->routing_attr == TABLE    
216                     phy->routing_attr == DIREC    
217                     phy->routing_attr == SUBTR    
218                     SAS_ADDR(phy->attached_sas    
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_helper(struct d    
227                                       u8 *disc    
228 {                                                 
229         int i, res;                               
230                                                   
231         disc_req[9] = single;                     
232         for (i = 1 ; i < 3; i++) {                
233                 struct discover_resp *dr;         
234                                                   
235                 res = smp_execute_task(dev, di    
236                                        disc_re    
237                 if (res)                          
238                         return res;               
239                 /* This is detecting a failure    
240                  * dev to host FIS as describe    
241                  * sas-2 r 04b */                 
242                 dr = &((struct smp_resp *)disc    
243                 if (!(dr->attached_dev_type ==    
244                       dr->attached_sata_dev))     
245                         break;                    
246                 /* In order to generate the de    
247                  * send a link reset to the ex    
248                 sas_smp_phy_control(dev, singl    
249                 /* Wait for the reset to trigg    
250                 msleep(500);                      
251         }                                         
252         sas_set_ex_phy(dev, single, disc_resp)    
253         return 0;                                 
254 }                                                 
255                                                   
256 static int sas_ex_phy_discover(struct domain_d    
257 {                                                 
258         struct expander_device *ex = &dev->ex_    
259         int  res = 0;                             
260         u8   *disc_req;                           
261         u8   *disc_resp;                          
262                                                   
263         disc_req = alloc_smp_req(DISCOVER_REQ_    
264         if (!disc_req)                            
265                 return -ENOMEM;                   
266                                                   
267         disc_resp = alloc_smp_req(DISCOVER_RES    
268         if (!disc_resp) {                         
269                 kfree(disc_req);                  
270                 return -ENOMEM;                   
271         }                                         
272                                                   
273         disc_req[1] = SMP_DISCOVER;               
274                                                   
275         if (0 <= single && single < ex->num_ph    
276                 res = sas_ex_phy_discover_help    
277         } else {                                  
278                 int i;                            
279                                                   
280                 for (i = 0; i < ex->num_phys;     
281                         res = sas_ex_phy_disco    
282                                                   
283                         if (res)                  
284                                 goto out_err;     
285                 }                                 
286         }                                         
287 out_err:                                          
288         kfree(disc_resp);                         
289         kfree(disc_req);                          
290         return res;                               
291 }                                                 
292                                                   
293 static int sas_expander_discover(struct domain    
294 {                                                 
295         struct expander_device *ex = &dev->ex_    
296         int res = -ENOMEM;                        
297                                                   
298         ex->ex_phy = kzalloc(sizeof(*ex->ex_ph    
299         if (!ex->ex_phy)                          
300                 return -ENOMEM;                   
301                                                   
302         res = sas_ex_phy_discover(dev, -1);       
303         if (res)                                  
304                 goto out_err;                     
305                                                   
306         return 0;                                 
307  out_err:                                         
308         kfree(ex->ex_phy);                        
309         ex->ex_phy = NULL;                        
310         return res;                               
311 }                                                 
312                                                   
313 #define MAX_EXPANDER_PHYS 128                     
314                                                   
315 static void ex_assign_report_general(struct do    
316                                             st    
317 {                                                 
318         struct report_general_resp *rg = &resp    
319                                                   
320         dev->ex_dev.ex_change_count = be16_to_    
321         dev->ex_dev.max_route_indexes = be16_t    
322         dev->ex_dev.num_phys = min(rg->num_phy    
323         dev->ex_dev.conf_route_table = rg->con    
324         dev->ex_dev.configuring = rg->configur    
325         memcpy(dev->ex_dev.enclosure_logical_i    
326 }                                                 
327                                                   
328 #define RG_REQ_SIZE   8                           
329 #define RG_RESP_SIZE 32                           
330                                                   
331 static int sas_ex_general(struct domain_device    
332 {                                                 
333         u8 *rg_req;                               
334         struct smp_resp *rg_resp;                 
335         int res;                                  
336         int i;                                    
337                                                   
338         rg_req = alloc_smp_req(RG_REQ_SIZE);      
339         if (!rg_req)                              
340                 return -ENOMEM;                   
341                                                   
342         rg_resp = alloc_smp_resp(RG_RESP_SIZE)    
343         if (!rg_resp) {                           
344                 kfree(rg_req);                    
345                 return -ENOMEM;                   
346         }                                         
347                                                   
348         rg_req[1] = SMP_REPORT_GENERAL;           
349                                                   
350         for (i = 0; i < 5; i++) {                 
351                 res = smp_execute_task(dev, rg    
352                                        RG_RESP    
353                                                   
354                 if (res) {                        
355                         SAS_DPRINTK("RG to ex     
356                                     SAS_ADDR(d    
357                         goto out;                 
358                 } else if (rg_resp->result !=     
359                         SAS_DPRINTK("RG:ex %01    
360                                     SAS_ADDR(d    
361                         res = rg_resp->result;    
362                         goto out;                 
363                 }                                 
364                                                   
365                 ex_assign_report_general(dev,     
366                                                   
367                 if (dev->ex_dev.configuring) {    
368                         SAS_DPRINTK("RG: ex %l    
369                                     SAS_ADDR(d    
370                         schedule_timeout_inter    
371                 } else                            
372                         break;                    
373         }                                         
374 out:                                              
375         kfree(rg_req);                            
376         kfree(rg_resp);                           
377         return res;                               
378 }                                                 
379                                                   
380 static void ex_assign_manuf_info(struct domain    
381                                         *_mi_r    
382 {                                                 
383         u8 *mi_resp = _mi_resp;                   
384         struct sas_rphy *rphy = dev->rphy;        
385         struct sas_expander_device *edev = rph    
386                                                   
387         memcpy(edev->vendor_id, mi_resp + 12,     
388         memcpy(edev->product_id, mi_resp + 20,    
389         memcpy(edev->product_rev, mi_resp + 36    
390                SAS_EXPANDER_PRODUCT_REV_LEN);     
391                                                   
392         if (mi_resp[8] & 1) {                     
393                 memcpy(edev->component_vendor_    
394                        SAS_EXPANDER_COMPONENT_    
395                 edev->component_id = mi_resp[4    
396                 edev->component_revision_id =     
397         }                                         
398 }                                                 
399                                                   
400 #define MI_REQ_SIZE   8                           
401 #define MI_RESP_SIZE 64                           
402                                                   
403 static int sas_ex_manuf_info(struct domain_dev    
404 {                                                 
405         u8 *mi_req;                               
406         u8 *mi_resp;                              
407         int res;                                  
408                                                   
409         mi_req = alloc_smp_req(MI_REQ_SIZE);      
410         if (!mi_req)                              
411                 return -ENOMEM;                   
412                                                   
413         mi_resp = alloc_smp_resp(MI_RESP_SIZE)    
414         if (!mi_resp) {                           
415                 kfree(mi_req);                    
416                 return -ENOMEM;                   
417         }                                         
418                                                   
419         mi_req[1] = SMP_REPORT_MANUF_INFO;        
420                                                   
421         res = smp_execute_task(dev, mi_req, MI    
422         if (res) {                                
423                 SAS_DPRINTK("MI: ex %016llx fa    
424                             SAS_ADDR(dev->sas_    
425                 goto out;                         
426         } else if (mi_resp[2] != SMP_RESP_FUNC    
427                 SAS_DPRINTK("MI ex %016llx ret    
428                             SAS_ADDR(dev->sas_    
429                 goto out;                         
430         }                                         
431                                                   
432         ex_assign_manuf_info(dev, mi_resp);       
433 out:                                              
434         kfree(mi_req);                            
435         kfree(mi_resp);                           
436         return res;                               
437 }                                                 
438                                                   
439 #define PC_REQ_SIZE  44                           
440 #define PC_RESP_SIZE 8                            
441                                                   
442 int sas_smp_phy_control(struct domain_device *    
443                         enum phy_func phy_func    
444                         struct sas_phy_linkrat    
445 {                                                 
446         u8 *pc_req;                               
447         u8 *pc_resp;                              
448         int res;                                  
449                                                   
450         pc_req = alloc_smp_req(PC_REQ_SIZE);      
451         if (!pc_req)                              
452                 return -ENOMEM;                   
453                                                   
454         pc_resp = alloc_smp_resp(PC_RESP_SIZE)    
455         if (!pc_resp) {                           
456                 kfree(pc_req);                    
457                 return -ENOMEM;                   
458         }                                         
459                                                   
460         pc_req[1] = SMP_PHY_CONTROL;              
461         pc_req[9] = phy_id;                       
462         pc_req[10]= phy_func;                     
463         if (rates) {                              
464                 pc_req[32] = rates->minimum_li    
465                 pc_req[33] = rates->maximum_li    
466         }                                         
467                                                   
468         res = smp_execute_task(dev, pc_req, PC    
469                                                   
470         kfree(pc_resp);                           
471         kfree(pc_req);                            
472         return res;                               
473 }                                                 
474                                                   
475 static void sas_ex_disable_phy(struct domain_d    
476 {                                                 
477         struct expander_device *ex = &dev->ex_    
478         struct ex_phy *phy = &ex->ex_phy[phy_i    
479                                                   
480         sas_smp_phy_control(dev, phy_id, PHY_F    
481         phy->linkrate = SAS_PHY_DISABLED;         
482 }                                                 
483                                                   
484 static void sas_ex_disable_port(struct domain_    
485 {                                                 
486         struct expander_device *ex = &dev->ex_    
487         int i;                                    
488                                                   
489         for (i = 0; i < ex->num_phys; i++) {      
490                 struct ex_phy *phy = &ex->ex_p    
491                                                   
492                 if (phy->phy_state == PHY_VACA    
493                     phy->phy_state == PHY_NOT_    
494                         continue;                 
495                                                   
496                 if (SAS_ADDR(phy->attached_sas    
497                         sas_ex_disable_phy(dev    
498         }                                         
499 }                                                 
500                                                   
501 static int sas_dev_present_in_domain(struct as    
502                                             u8    
503 {                                                 
504         struct domain_device *dev;                
505                                                   
506         if (SAS_ADDR(port->sas_addr) == SAS_AD    
507                 return 1;                         
508         list_for_each_entry(dev, &port->dev_li    
509                 if (SAS_ADDR(dev->sas_addr) ==    
510                         return 1;                 
511         }                                         
512         return 0;                                 
513 }                                                 
514                                                   
515 #define RPEL_REQ_SIZE   16                        
516 #define RPEL_RESP_SIZE  32                        
517 int sas_smp_get_phy_events(struct sas_phy *phy    
518 {                                                 
519         int res;                                  
520         u8 *req;                                  
521         u8 *resp;                                 
522         struct sas_rphy *rphy = dev_to_rphy(ph    
523         struct domain_device *dev = sas_find_d    
524                                                   
525         req = alloc_smp_req(RPEL_REQ_SIZE);       
526         if (!req)                                 
527                 return -ENOMEM;                   
528                                                   
529         resp = alloc_smp_resp(RPEL_RESP_SIZE);    
530         if (!resp) {                              
531                 kfree(req);                       
532                 return -ENOMEM;                   
533         }                                         
534                                                   
535         req[1] = SMP_REPORT_PHY_ERR_LOG;          
536         req[9] = phy->number;                     
537                                                   
538         res = smp_execute_task(dev, req, RPEL_    
539                                     resp, RPEL    
540                                                   
541         if (!res)                                 
542                 goto out;                         
543                                                   
544         phy->invalid_dword_count = scsi_to_u32    
545         phy->running_disparity_error_count = s    
546         phy->loss_of_dword_sync_count = scsi_t    
547         phy->phy_reset_problem_count = scsi_to    
548                                                   
549  out:                                             
550         kfree(resp);                              
551         return res;                               
552                                                   
553 }                                                 
554                                                   
555 #ifdef CONFIG_SCSI_SAS_ATA                        
556                                                   
557 #define RPS_REQ_SIZE  16                          
558 #define RPS_RESP_SIZE 60                          
559                                                   
560 static int sas_get_report_phy_sata(struct doma    
561                                           int     
562                                           stru    
563 {                                                 
564         int res;                                  
565         u8 *rps_req = alloc_smp_req(RPS_REQ_SI    
566         u8 *resp = (u8 *)rps_resp;                
567                                                   
568         if (!rps_req)                             
569                 return -ENOMEM;                   
570                                                   
571         rps_req[1] = SMP_REPORT_PHY_SATA;         
572         rps_req[9] = phy_id;                      
573                                                   
574         res = smp_execute_task(dev, rps_req, R    
575                                     rps_resp,     
576                                                   
577         /* 0x34 is the FIS type for the D2H fi    
578          * standards cockup here.  sas-2 expli    
579          * should be encoded so that FIS type     
580          * However, some expanders endian reve    
581          * reversal here */                       
582         if (!res && resp[27] == 0x34 && resp[2    
583                 int i;                            
584                                                   
585                 for (i = 0; i < 5; i++) {         
586                         int j = 24 + (i*4);       
587                         u8 a, b;                  
588                         a = resp[j + 0];          
589                         b = resp[j + 1];          
590                         resp[j + 0] = resp[j +    
591                         resp[j + 1] = resp[j +    
592                         resp[j + 2] = b;          
593                         resp[j + 3] = a;          
594                 }                                 
595         }                                         
596                                                   
597         kfree(rps_req);                           
598         return res;                               
599 }                                                 
600 #endif                                            
601                                                   
602 static void sas_ex_get_linkrate(struct domain_    
603                                        struct     
604                                        struct     
605 {                                                 
606         struct expander_device *parent_ex = &p    
607         struct sas_port *port;                    
608         int i;                                    
609                                                   
610         child->pathways = 0;                      
611                                                   
612         port = parent_phy->port;                  
613                                                   
614         for (i = 0; i < parent_ex->num_phys; i    
615                 struct ex_phy *phy = &parent_e    
616                                                   
617                 if (phy->phy_state == PHY_VACA    
618                     phy->phy_state == PHY_NOT_    
619                         continue;                 
620                                                   
621                 if (SAS_ADDR(phy->attached_sas    
622                     SAS_ADDR(child->sas_addr))    
623                                                   
624                         child->min_linkrate =     
625                                                   
626                         child->max_linkrate =     
627                                                   
628                         child->pathways++;        
629                         sas_port_add_phy(port,    
630                 }                                 
631         }                                         
632         child->linkrate = min(parent_phy->link    
633         child->pathways = min(child->pathways,    
634 }                                                 
635                                                   
636 static struct domain_device *sas_ex_discover_e    
637         struct domain_device *parent, int phy_    
638 {                                                 
639         struct expander_device *parent_ex = &p    
640         struct ex_phy *phy = &parent_ex->ex_ph    
641         struct domain_device *child = NULL;       
642         struct sas_rphy *rphy;                    
643         int res;                                  
644                                                   
645         if (phy->attached_sata_host || phy->at    
646                 return NULL;                      
647                                                   
648         child = kzalloc(sizeof(*child), GFP_KE    
649         if (!child)                               
650                 return NULL;                      
651                                                   
652         child->parent = parent;                   
653         child->port   = parent->port;             
654         child->iproto = phy->attached_iproto;     
655         memcpy(child->sas_addr, phy->attached_    
656         sas_hash_addr(child->hashed_sas_addr,     
657         if (!phy->port) {                         
658                 phy->port = sas_port_alloc(&pa    
659                 if (unlikely(!phy->port))         
660                         goto out_err;             
661                 if (unlikely(sas_port_add(phy-    
662                         sas_port_free(phy->por    
663                         goto out_err;             
664                 }                                 
665         }                                         
666         sas_ex_get_linkrate(parent, child, phy    
667                                                   
668 #ifdef CONFIG_SCSI_SAS_ATA                        
669         if ((phy->attached_tproto & SAS_PROTOC    
670                 child->dev_type = SATA_DEV;       
671                 if (phy->attached_tproto & SAS    
672                         child->tproto = phy->a    
673                 if (phy->attached_sata_dev)       
674                         child->tproto |= SATA_    
675                 res = sas_get_report_phy_sata(    
676                                                   
677                 if (res) {                        
678                         SAS_DPRINTK("report ph    
679                                     "0x%x\n",     
680                                     phy_id, re    
681                         goto out_free;            
682                 }                                 
683                 memcpy(child->frame_rcvd, &chi    
684                        sizeof(struct dev_to_ho    
685                                                   
686                 rphy = sas_end_device_alloc(ph    
687                 if (unlikely(!rphy))              
688                         goto out_free;            
689                                                   
690                 sas_init_dev(child);              
691                                                   
692                 child->rphy = rphy;               
693                                                   
694                 spin_lock_irq(&parent->port->d    
695                 list_add_tail(&child->dev_list    
696                 spin_unlock_irq(&parent->port-    
697                                                   
698                 res = sas_discover_sata(child)    
699                 if (res) {                        
700                         SAS_DPRINTK("sas_disco    
701                                     "%016llx:0    
702                                     SAS_ADDR(c    
703                                     SAS_ADDR(p    
704                         goto out_list_del;        
705                 }                                 
706         } else                                    
707 #endif                                            
708           if (phy->attached_tproto & SAS_PROTO    
709                 child->dev_type = SAS_END_DEV;    
710                 rphy = sas_end_device_alloc(ph    
711                 /* FIXME: error handling */       
712                 if (unlikely(!rphy))              
713                         goto out_free;            
714                 child->tproto = phy->attached_    
715                 sas_init_dev(child);              
716                                                   
717                 child->rphy = rphy;               
718                 sas_fill_in_rphy(child, rphy);    
719                                                   
720                 spin_lock_irq(&parent->port->d    
721                 list_add_tail(&child->dev_list    
722                 spin_unlock_irq(&parent->port-    
723                                                   
724                 res = sas_discover_end_dev(chi    
725                 if (res) {                        
726                         SAS_DPRINTK("sas_disco    
727                                     "at %016ll    
728                                     SAS_ADDR(c    
729                                     SAS_ADDR(p    
730                         goto out_list_del;        
731                 }                                 
732         } else {                                  
733                 SAS_DPRINTK("target proto 0x%x    
734                             phy->attached_tpro    
735                             phy_id);              
736                 goto out_free;                    
737         }                                         
738                                                   
739         list_add_tail(&child->siblings, &paren    
740         return child;                             
741                                                   
742  out_list_del:                                    
743         sas_rphy_free(child->rphy);               
744         child->rphy = NULL;                       
745         list_del(&child->dev_list_node);          
746  out_free:                                        
747         sas_port_delete(phy->port);               
748  out_err:                                         
749         phy->port = NULL;                         
750         kfree(child);                             
751         return NULL;                              
752 }                                                 
753                                                   
754 /* See if this phy is part of a wide port */      
755 static int sas_ex_join_wide_port(struct domain    
756 {                                                 
757         struct ex_phy *phy = &parent->ex_dev.e    
758         int i;                                    
759                                                   
760         for (i = 0; i < parent->ex_dev.num_phy    
761                 struct ex_phy *ephy = &parent-    
762                                                   
763                 if (ephy == phy)                  
764                         continue;                 
765                                                   
766                 if (!memcmp(phy->attached_sas_    
767                             SAS_ADDR_SIZE) &&     
768                         sas_port_add_phy(ephy-    
769                         phy->port = ephy->port    
770                         phy->phy_state = PHY_D    
771                         return 0;                 
772                 }                                 
773         }                                         
774                                                   
775         return -ENODEV;                           
776 }                                                 
777                                                   
778 static struct domain_device *sas_ex_discover_e    
779         struct domain_device *parent, int phy_    
780 {                                                 
781         struct sas_expander_device *parent_ex     
782         struct ex_phy *phy = &parent->ex_dev.e    
783         struct domain_device *child = NULL;       
784         struct sas_rphy *rphy;                    
785         struct sas_expander_device *edev;         
786         struct asd_sas_port *port;                
787         int res;                                  
788                                                   
789         if (phy->routing_attr == DIRECT_ROUTIN    
790                 SAS_DPRINTK("ex %016llx:0x%x:D    
791                             "allowed\n",          
792                             SAS_ADDR(parent->s    
793                             SAS_ADDR(phy->atta    
794                             phy->attached_phy_    
795                 return NULL;                      
796         }                                         
797         child = kzalloc(sizeof(*child), GFP_KE    
798         if (!child)                               
799                 return NULL;                      
800                                                   
801         phy->port = sas_port_alloc(&parent->rp    
802         /* FIXME: better error handling */        
803         BUG_ON(sas_port_add(phy->port) != 0);     
804                                                   
805                                                   
806         switch (phy->attached_dev_type) {         
807         case EDGE_DEV:                            
808                 rphy = sas_expander_alloc(phy-    
809                                           SAS_    
810                 break;                            
811         case FANOUT_DEV:                          
812                 rphy = sas_expander_alloc(phy-    
813                                           SAS_    
814                 break;                            
815         default:                                  
816                 rphy = NULL;    /* shut gcc up    
817                 BUG();                            
818         }                                         
819         port = parent->port;                      
820         child->rphy = rphy;                       
821         edev = rphy_to_expander_device(rphy);     
822         child->dev_type = phy->attached_dev_ty    
823         child->parent = parent;                   
824         child->port = port;                       
825         child->iproto = phy->attached_iproto;     
826         child->tproto = phy->attached_tproto;     
827         memcpy(child->sas_addr, phy->attached_    
828         sas_hash_addr(child->hashed_sas_addr,     
829         sas_ex_get_linkrate(parent, child, phy    
830         edev->level = parent_ex->level + 1;       
831         parent->port->disc.max_level = max(par    
832                                            ede    
833         sas_init_dev(child);                      
834         sas_fill_in_rphy(child, rphy);            
835         sas_rphy_add(rphy);                       
836                                                   
837         spin_lock_irq(&parent->port->dev_list_    
838         list_add_tail(&child->dev_list_node, &    
839         spin_unlock_irq(&parent->port->dev_lis    
840                                                   
841         res = sas_discover_expander(child);       
842         if (res) {                                
843                 kfree(child);                     
844                 return NULL;                      
845         }                                         
846         list_add_tail(&child->siblings, &paren    
847         return child;                             
848 }                                                 
849                                                   
850 static int sas_ex_discover_dev(struct domain_d    
851 {                                                 
852         struct expander_device *ex = &dev->ex_    
853         struct ex_phy *ex_phy = &ex->ex_phy[ph    
854         struct domain_device *child = NULL;       
855         int res = 0;                              
856                                                   
857         /* Phy state */                           
858         if (ex_phy->linkrate == SAS_SATA_SPINU    
859                 if (!sas_smp_phy_control(dev,     
860                         res = sas_ex_phy_disco    
861                 if (res)                          
862                         return res;               
863         }                                         
864                                                   
865         /* Parent and domain coherency */         
866         if (!dev->parent && (SAS_ADDR(ex_phy->    
867                              SAS_ADDR(dev->por    
868                 sas_add_parent_port(dev, phy_i    
869                 return 0;                         
870         }                                         
871         if (dev->parent && (SAS_ADDR(ex_phy->a    
872                             SAS_ADDR(dev->pare    
873                 sas_add_parent_port(dev, phy_i    
874                 if (ex_phy->routing_attr == TA    
875                         sas_configure_phy(dev,    
876                 return 0;                         
877         }                                         
878                                                   
879         if (sas_dev_present_in_domain(dev->por    
880                 sas_ex_disable_port(dev, ex_ph    
881                                                   
882         if (ex_phy->attached_dev_type == NO_DE    
883                 if (ex_phy->routing_attr == DI    
884                         memset(ex_phy->attache    
885                         sas_configure_routing(    
886                 }                                 
887                 return 0;                         
888         } else if (ex_phy->linkrate == SAS_LIN    
889                 return 0;                         
890                                                   
891         if (ex_phy->attached_dev_type != SAS_E    
892             ex_phy->attached_dev_type != FANOU    
893             ex_phy->attached_dev_type != EDGE_    
894                 SAS_DPRINTK("unknown device ty    
895                             "phy 0x%x\n", ex_p    
896                             SAS_ADDR(dev->sas_    
897                             phy_id);              
898                 return 0;                         
899         }                                         
900                                                   
901         res = sas_configure_routing(dev, ex_ph    
902         if (res) {                                
903                 SAS_DPRINTK("configure routing    
904                             "reported 0x%x. Fo    
905                             SAS_ADDR(ex_phy->a    
906                 sas_disable_routing(dev, ex_ph    
907                 return res;                       
908         }                                         
909                                                   
910         res = sas_ex_join_wide_port(dev, phy_i    
911         if (!res) {                               
912                 SAS_DPRINTK("Attaching ex phy%    
913                             phy_id, SAS_ADDR(e    
914                 return res;                       
915         }                                         
916                                                   
917         switch (ex_phy->attached_dev_type) {      
918         case SAS_END_DEV:                         
919                 child = sas_ex_discover_end_de    
920                 break;                            
921         case FANOUT_DEV:                          
922                 if (SAS_ADDR(dev->port->disc.f    
923                         SAS_DPRINTK("second fa    
924                                     "attached     
925                                     SAS_ADDR(e    
926                                     ex_phy->at    
927                                     SAS_ADDR(d    
928                                     phy_id);      
929                         sas_ex_disable_phy(dev    
930                         break;                    
931                 } else                            
932                         memcpy(dev->port->disc    
933                                ex_phy->attache    
934                 /* fallthrough */                 
935         case EDGE_DEV:                            
936                 child = sas_ex_discover_expand    
937                 break;                            
938         default:                                  
939                 break;                            
940         }                                         
941                                                   
942         if (child) {                              
943                 int i;                            
944                                                   
945                 for (i = 0; i < ex->num_phys;     
946                         if (ex->ex_phy[i].phy_    
947                             ex->ex_phy[i].phy_    
948                                 continue;         
949                         /*                        
950                          * Due to races, the p    
951                          * wide port, so we ad    
952                          */                       
953                         if (SAS_ADDR(ex->ex_ph    
954                             SAS_ADDR(child->sa    
955                                 ex->ex_phy[i].    
956                                 res = sas_ex_j    
957                                 if (!res)         
958                                         SAS_DP    
959                                                   
960                                                   
961                         }                         
962                 }                                 
963                 res = 0;                          
964         }                                         
965                                                   
966         return res;                               
967 }                                                 
968                                                   
969 static int sas_find_sub_addr(struct domain_dev    
970 {                                                 
971         struct expander_device *ex = &dev->ex_    
972         int i;                                    
973                                                   
974         for (i = 0; i < ex->num_phys; i++) {      
975                 struct ex_phy *phy = &ex->ex_p    
976                                                   
977                 if (phy->phy_state == PHY_VACA    
978                     phy->phy_state == PHY_NOT_    
979                         continue;                 
980                                                   
981                 if ((phy->attached_dev_type ==    
982                      phy->attached_dev_type ==    
983                     phy->routing_attr == SUBTR    
984                                                   
985                         memcpy(sub_addr, phy->    
986                                                   
987                         return 1;                 
988                 }                                 
989         }                                         
990         return 0;                                 
991 }                                                 
992                                                   
993 static int sas_check_level_subtractive_boundar    
994 {                                                 
995         struct expander_device *ex = &dev->ex_    
996         struct domain_device *child;              
997         u8 sub_addr[8] = {0, };                   
998                                                   
999         list_for_each_entry(child, &ex->childr    
1000                 if (child->dev_type != EDGE_D    
1001                     child->dev_type != FANOUT    
1002                         continue;                
1003                 if (sub_addr[0] == 0) {          
1004                         sas_find_sub_addr(chi    
1005                         continue;                
1006                 } else {                         
1007                         u8 s2[8];                
1008                                                  
1009                         if (sas_find_sub_addr    
1010                             (SAS_ADDR(sub_add    
1011                                                  
1012                                 SAS_DPRINTK("    
1013                                             "    
1014                                             "    
1015                                             S    
1016                                             S    
1017                                             S    
1018                                             S    
1019                                                  
1020                                 sas_ex_disabl    
1021                         }                        
1022                 }                                
1023         }                                        
1024         return 0;                                
1025 }                                                
1026 /**                                              
1027  * sas_ex_discover_devices -- discover device    
1028  * dev: pointer to the expander domain device    
1029  * single: if you want to do a single phy, el    
1030  *                                               
1031  * Configure this expander for use with its d    
1032  * devices of this expander.                     
1033  */                                              
1034 static int sas_ex_discover_devices(struct dom    
1035 {                                                
1036         struct expander_device *ex = &dev->ex    
1037         int i = 0, end = ex->num_phys;           
1038         int res = 0;                             
1039                                                  
1040         if (0 <= single && single < end) {       
1041                 i = single;                      
1042                 end = i+1;                       
1043         }                                        
1044                                                  
1045         for ( ; i < end; i++) {                  
1046                 struct ex_phy *ex_phy = &ex->    
1047                                                  
1048                 if (ex_phy->phy_state == PHY_    
1049                     ex_phy->phy_state == PHY_    
1050                     ex_phy->phy_state == PHY_    
1051                         continue;                
1052                                                  
1053                 switch (ex_phy->linkrate) {      
1054                 case SAS_PHY_DISABLED:           
1055                 case SAS_PHY_RESET_PROBLEM:      
1056                 case SAS_SATA_PORT_SELECTOR:     
1057                         continue;                
1058                 default:                         
1059                         res = sas_ex_discover    
1060                         if (res)                 
1061                                 break;           
1062                         continue;                
1063                 }                                
1064         }                                        
1065                                                  
1066         if (!res)                                
1067                 sas_check_level_subtractive_b    
1068                                                  
1069         return res;                              
1070 }                                                
1071                                                  
1072 static int sas_check_ex_subtractive_boundary(    
1073 {                                                
1074         struct expander_device *ex = &dev->ex    
1075         int i;                                   
1076         u8  *sub_sas_addr = NULL;                
1077                                                  
1078         if (dev->dev_type != EDGE_DEV)           
1079                 return 0;                        
1080                                                  
1081         for (i = 0; i < ex->num_phys; i++) {     
1082                 struct ex_phy *phy = &ex->ex_    
1083                                                  
1084                 if (phy->phy_state == PHY_VAC    
1085                     phy->phy_state == PHY_NOT    
1086                         continue;                
1087                                                  
1088                 if ((phy->attached_dev_type =    
1089                      phy->attached_dev_type =    
1090                     phy->routing_attr == SUBT    
1091                                                  
1092                         if (!sub_sas_addr)       
1093                                 sub_sas_addr     
1094                         else if (SAS_ADDR(sub    
1095                                  SAS_ADDR(phy    
1096                                                  
1097                                 SAS_DPRINTK("    
1098                                             "    
1099                                             "    
1100                                             S    
1101                                             S    
1102                                             S    
1103                                 sas_ex_disabl    
1104                         }                        
1105                 }                                
1106         }                                        
1107         return 0;                                
1108 }                                                
1109                                                  
1110 static void sas_print_parent_topology_bug(str    
1111                                                  
1112                                                  
1113 {                                                
1114         static const char ra_char[] = {          
1115                 [DIRECT_ROUTING] = 'D',          
1116                 [SUBTRACTIVE_ROUTING] = 'S',     
1117                 [TABLE_ROUTING] = 'T',           
1118         };                                       
1119         static const char *ex_type[] = {         
1120                 [EDGE_DEV] = "edge",             
1121                 [FANOUT_DEV] = "fanout",         
1122         };                                       
1123         struct domain_device *parent = child-    
1124                                                  
1125         sas_printk("%s ex %016llx phy 0x%x <-    
1126                    "has %c:%c routing link!\n    
1127                                                  
1128                    ex_type[parent->dev_type],    
1129                    SAS_ADDR(parent->sas_addr)    
1130                    parent_phy->phy_id,           
1131                                                  
1132                    ex_type[child->dev_type],     
1133                    SAS_ADDR(child->sas_addr),    
1134                    child_phy->phy_id,            
1135                                                  
1136                    ra_char[parent_phy->routin    
1137                    ra_char[child_phy->routing    
1138 }                                                
1139                                                  
1140 static int sas_check_eeds(struct domain_devic    
1141                                  struct ex_ph    
1142                                  struct ex_ph    
1143 {                                                
1144         int res = 0;                             
1145         struct domain_device *parent = child-    
1146                                                  
1147         if (SAS_ADDR(parent->port->disc.fanou    
1148                 res = -ENODEV;                   
1149                 SAS_DPRINTK("edge ex %016llx     
1150                             "phy S:0x%x, whil    
1151                             SAS_ADDR(parent->    
1152                             parent_phy->phy_i    
1153                             SAS_ADDR(child->s    
1154                             child_phy->phy_id    
1155                             SAS_ADDR(parent->    
1156         } else if (SAS_ADDR(parent->port->dis    
1157                 memcpy(parent->port->disc.eed    
1158                        SAS_ADDR_SIZE);           
1159                 memcpy(parent->port->disc.eed    
1160                        SAS_ADDR_SIZE);           
1161         } else if (((SAS_ADDR(parent->port->d    
1162                     SAS_ADDR(parent->sas_addr    
1163                    (SAS_ADDR(parent->port->di    
1164                     SAS_ADDR(child->sas_addr)    
1165                    &&                            
1166                    ((SAS_ADDR(parent->port->d    
1167                      SAS_ADDR(parent->sas_add    
1168                     (SAS_ADDR(parent->port->d    
1169                      SAS_ADDR(child->sas_addr    
1170                 ;                                
1171         else {                                   
1172                 res = -ENODEV;                   
1173                 SAS_DPRINTK("edge ex %016llx     
1174                             "phy 0x%x link fo    
1175                             SAS_ADDR(parent->    
1176                             parent_phy->phy_i    
1177                             SAS_ADDR(child->s    
1178                             child_phy->phy_id    
1179         }                                        
1180                                                  
1181         return res;                              
1182 }                                                
1183                                                  
1184 /* Here we spill over 80 columns.  It is inte    
1185  */                                              
1186 static int sas_check_parent_topology(struct d    
1187 {                                                
1188         struct expander_device *child_ex = &c    
1189         struct expander_device *parent_ex;       
1190         int i;                                   
1191         int res = 0;                             
1192                                                  
1193         if (!child->parent)                      
1194                 return 0;                        
1195                                                  
1196         if (child->parent->dev_type != EDGE_D    
1197             child->parent->dev_type != FANOUT    
1198                 return 0;                        
1199                                                  
1200         parent_ex = &child->parent->ex_dev;      
1201                                                  
1202         for (i = 0; i < parent_ex->num_phys;     
1203                 struct ex_phy *parent_phy = &    
1204                 struct ex_phy *child_phy;        
1205                                                  
1206                 if (parent_phy->phy_state ==     
1207                     parent_phy->phy_state ==     
1208                         continue;                
1209                                                  
1210                 if (SAS_ADDR(parent_phy->atta    
1211                         continue;                
1212                                                  
1213                 child_phy = &child_ex->ex_phy    
1214                                                  
1215                 switch (child->parent->dev_ty    
1216                 case EDGE_DEV:                   
1217                         if (child->dev_type =    
1218                                 if (parent_ph    
1219                                     child_phy    
1220                                         sas_p    
1221                                         res =    
1222                                 }                
1223                         } else if (parent_phy    
1224                                 if (child_phy    
1225                                         res =    
1226                                 } else if (ch    
1227                                         sas_p    
1228                                         res =    
1229                                 }                
1230                         } else if (parent_phy    
1231                                    child_phy-    
1232                                 sas_print_par    
1233                                 res = -ENODEV    
1234                         }                        
1235                         break;                   
1236                 case FANOUT_DEV:                 
1237                         if (parent_phy->routi    
1238                             child_phy->routin    
1239                                 sas_print_par    
1240                                 res = -ENODEV    
1241                         }                        
1242                         break;                   
1243                 default:                         
1244                         break;                   
1245                 }                                
1246         }                                        
1247                                                  
1248         return res;                              
1249 }                                                
1250                                                  
1251 #define RRI_REQ_SIZE  16                         
1252 #define RRI_RESP_SIZE 44                         
1253                                                  
1254 static int sas_configure_present(struct domai    
1255                                  u8 *sas_addr    
1256 {                                                
1257         int i, res = 0;                          
1258         struct expander_device *ex = &dev->ex    
1259         struct ex_phy *phy = &ex->ex_phy[phy_    
1260         u8 *rri_req;                             
1261         u8 *rri_resp;                            
1262                                                  
1263         *present = 0;                            
1264         *index = 0;                              
1265                                                  
1266         rri_req = alloc_smp_req(RRI_REQ_SIZE)    
1267         if (!rri_req)                            
1268                 return -ENOMEM;                  
1269                                                  
1270         rri_resp = alloc_smp_resp(RRI_RESP_SI    
1271         if (!rri_resp) {                         
1272                 kfree(rri_req);                  
1273                 return -ENOMEM;                  
1274         }                                        
1275                                                  
1276         rri_req[1] = SMP_REPORT_ROUTE_INFO;      
1277         rri_req[9] = phy_id;                     
1278                                                  
1279         for (i = 0; i < ex->max_route_indexes    
1280                 *(__be16 *)(rri_req+6) = cpu_    
1281                 res = smp_execute_task(dev, r    
1282                                        RRI_RE    
1283                 if (res)                         
1284                         goto out;                
1285                 res = rri_resp[2];               
1286                 if (res == SMP_RESP_NO_INDEX)    
1287                         SAS_DPRINTK("overflow    
1288                                     "phy 0x%x    
1289                                     SAS_ADDR(    
1290                         goto out;                
1291                 } else if (res != SMP_RESP_FU    
1292                         SAS_DPRINTK("%s: dev     
1293                                     "result 0    
1294                                     SAS_ADDR(    
1295                         goto out;                
1296                 }                                
1297                 if (SAS_ADDR(sas_addr) != 0)     
1298                         if (SAS_ADDR(rri_resp    
1299                                 *index = i;      
1300                                 if ((rri_resp    
1301                                         *pres    
1302                                 else             
1303                                         *pres    
1304                                 goto out;        
1305                         } else if (SAS_ADDR(r    
1306                                 *index = i;      
1307                                 *present = 0;    
1308                                 goto out;        
1309                         }                        
1310                 } else if (SAS_ADDR(rri_resp+    
1311                            phy->last_da_index    
1312                         phy->last_da_index =     
1313                         *index = i;              
1314                         *present = 0;            
1315                         goto out;                
1316                 }                                
1317         }                                        
1318         res = -1;                                
1319 out:                                             
1320         kfree(rri_req);                          
1321         kfree(rri_resp);                         
1322         return res;                              
1323 }                                                
1324                                                  
1325 #define CRI_REQ_SIZE  44                         
1326 #define CRI_RESP_SIZE  8                         
1327                                                  
1328 static int sas_configure_set(struct domain_de    
1329                              u8 *sas_addr, in    
1330 {                                                
1331         int res;                                 
1332         u8 *cri_req;                             
1333         u8 *cri_resp;                            
1334                                                  
1335         cri_req = alloc_smp_req(CRI_REQ_SIZE)    
1336         if (!cri_req)                            
1337                 return -ENOMEM;                  
1338                                                  
1339         cri_resp = alloc_smp_resp(CRI_RESP_SI    
1340         if (!cri_resp) {                         
1341                 kfree(cri_req);                  
1342                 return -ENOMEM;                  
1343         }                                        
1344                                                  
1345         cri_req[1] = SMP_CONF_ROUTE_INFO;        
1346         *(__be16 *)(cri_req+6) = cpu_to_be16(    
1347         cri_req[9] = phy_id;                     
1348         if (SAS_ADDR(sas_addr) == 0 || !inclu    
1349                 cri_req[12] |= 0x80;             
1350         memcpy(cri_req+16, sas_addr, SAS_ADDR    
1351                                                  
1352         res = smp_execute_task(dev, cri_req,     
1353                                CRI_RESP_SIZE)    
1354         if (res)                                 
1355                 goto out;                        
1356         res = cri_resp[2];                       
1357         if (res == SMP_RESP_NO_INDEX) {          
1358                 SAS_DPRINTK("overflow of inde    
1359                             "index 0x%x\n",      
1360                             SAS_ADDR(dev->sas    
1361         }                                        
1362 out:                                             
1363         kfree(cri_req);                          
1364         kfree(cri_resp);                         
1365         return res;                              
1366 }                                                
1367                                                  
1368 static int sas_configure_phy(struct domain_de    
1369                                     u8 *sas_a    
1370 {                                                
1371         int index;                               
1372         int present;                             
1373         int res;                                 
1374                                                  
1375         res = sas_configure_present(dev, phy_    
1376         if (res)                                 
1377                 return res;                      
1378         if (include ^ present)                   
1379                 return sas_configure_set(dev,    
1380                                                  
1381         return res;                              
1382 }                                                
1383                                                  
1384 /**                                              
1385  * sas_configure_parent -- configure routing     
1386  * parent: parent expander                       
1387  * child: child expander                         
1388  * sas_addr: SAS port identifier of device di    
1389  */                                              
1390 static int sas_configure_parent(struct domain    
1391                                 struct domain    
1392                                 u8 *sas_addr,    
1393 {                                                
1394         struct expander_device *ex_parent = &    
1395         int res = 0;                             
1396         int i;                                   
1397                                                  
1398         if (parent->parent) {                    
1399                 res = sas_configure_parent(pa    
1400                                            in    
1401                 if (res)                         
1402                         return res;              
1403         }                                        
1404                                                  
1405         if (ex_parent->conf_route_table == 0)    
1406                 SAS_DPRINTK("ex %016llx has s    
1407                             SAS_ADDR(parent->    
1408                 return 0;                        
1409         }                                        
1410                                                  
1411         for (i = 0; i < ex_parent->num_phys;     
1412                 struct ex_phy *phy = &ex_pare    
1413                                                  
1414                 if ((phy->routing_attr == TAB    
1415                     (SAS_ADDR(phy->attached_s    
1416                      SAS_ADDR(child->sas_addr    
1417                         res = sas_configure_p    
1418                         if (res)                 
1419                                 return res;      
1420                 }                                
1421         }                                        
1422                                                  
1423         return res;                              
1424 }                                                
1425                                                  
1426 /**                                              
1427  * sas_configure_routing -- configure routing    
1428  * dev: expander device                          
1429  * sas_addr: port identifier of device direct    
1430  */                                              
1431 static int sas_configure_routing(struct domai    
1432 {                                                
1433         if (dev->parent)                         
1434                 return sas_configure_parent(d    
1435         return 0;                                
1436 }                                                
1437                                                  
1438 static int sas_disable_routing(struct domain_    
1439 {                                                
1440         if (dev->parent)                         
1441                 return sas_configure_parent(d    
1442         return 0;                                
1443 }                                                
1444                                                  
1445 /**                                              
1446  * sas_discover_expander -- expander discover    
1447  * @ex: pointer to expander domain device        
1448  *                                               
1449  * See comment in sas_discover_sata().           
1450  */                                              
1451 static int sas_discover_expander(struct domai    
1452 {                                                
1453         int res;                                 
1454                                                  
1455         res = sas_notify_lldd_dev_found(dev);    
1456         if (res)                                 
1457                 return res;                      
1458                                                  
1459         res = sas_ex_general(dev);               
1460         if (res)                                 
1461                 goto out_err;                    
1462         res = sas_ex_manuf_info(dev);            
1463         if (res)                                 
1464                 goto out_err;                    
1465                                                  
1466         res = sas_expander_discover(dev);        
1467         if (res) {                               
1468                 SAS_DPRINTK("expander %016llx    
1469                             SAS_ADDR(dev->sas    
1470                 goto out_err;                    
1471         }                                        
1472                                                  
1473         sas_check_ex_subtractive_boundary(dev    
1474         res = sas_check_parent_topology(dev);    
1475         if (res)                                 
1476                 goto out_err;                    
1477         return 0;                                
1478 out_err:                                         
1479         sas_notify_lldd_dev_gone(dev);           
1480         return res;                              
1481 }                                                
1482                                                  
1483 static int sas_ex_level_discovery(struct asd_    
1484 {                                                
1485         int res = 0;                             
1486         struct domain_device *dev;               
1487                                                  
1488         list_for_each_entry(dev, &port->dev_l    
1489                 if (dev->dev_type == EDGE_DEV    
1490                     dev->dev_type == FANOUT_D    
1491                         struct sas_expander_d    
1492                                 rphy_to_expan    
1493                                                  
1494                         if (level == ex->leve    
1495                                 res = sas_ex_    
1496                         else if (level > 0)      
1497                                 res = sas_ex_    
1498                                                  
1499                 }                                
1500         }                                        
1501                                                  
1502         return res;                              
1503 }                                                
1504                                                  
1505 static int sas_ex_bfs_disc(struct asd_sas_por    
1506 {                                                
1507         int res;                                 
1508         int level;                               
1509                                                  
1510         do {                                     
1511                 level = port->disc.max_level;    
1512                 res = sas_ex_level_discovery(    
1513                 mb();                            
1514         } while (level < port->disc.max_level    
1515                                                  
1516         return res;                              
1517 }                                                
1518                                                  
1519 int sas_discover_root_expander(struct domain_    
1520 {                                                
1521         int res;                                 
1522         struct sas_expander_device *ex = rphy    
1523                                                  
1524         res = sas_rphy_add(dev->rphy);           
1525         if (res)                                 
1526                 goto out_err;                    
1527                                                  
1528         ex->level = dev->port->disc.max_level    
1529         res = sas_discover_expander(dev);        
1530         if (res)                                 
1531                 goto out_err2;                   
1532                                                  
1533         sas_ex_bfs_disc(dev->port);              
1534                                                  
1535         return res;                              
1536                                                  
1537 out_err2:                                        
1538         sas_rphy_remove(dev->rphy);              
1539 out_err:                                         
1540         return res;                              
1541 }                                                
1542                                                  
1543 /* ---------- Domain revalidation ----------     
1544                                                  
1545 static int sas_get_phy_discover(struct domain    
1546                                 int phy_id, s    
1547 {                                                
1548         int res;                                 
1549         u8 *disc_req;                            
1550                                                  
1551         disc_req = alloc_smp_req(DISCOVER_REQ    
1552         if (!disc_req)                           
1553                 return -ENOMEM;                  
1554                                                  
1555         disc_req[1] = SMP_DISCOVER;              
1556         disc_req[9] = phy_id;                    
1557                                                  
1558         res = smp_execute_task(dev, disc_req,    
1559                                disc_resp, DIS    
1560         if (res)                                 
1561                 goto out;                        
1562         else if (disc_resp->result != SMP_RES    
1563                 res = disc_resp->result;         
1564                 goto out;                        
1565         }                                        
1566 out:                                             
1567         kfree(disc_req);                         
1568         return res;                              
1569 }                                                
1570                                                  
1571 static int sas_get_phy_change_count(struct do    
1572                                     int phy_i    
1573 {                                                
1574         int res;                                 
1575         struct smp_resp *disc_resp;              
1576                                                  
1577         disc_resp = alloc_smp_resp(DISCOVER_R    
1578         if (!disc_resp)                          
1579                 return -ENOMEM;                  
1580                                                  
1581         res = sas_get_phy_discover(dev, phy_i    
1582         if (!res)                                
1583                 *pcc = disc_resp->disc.change    
1584                                                  
1585         kfree(disc_resp);                        
1586         return res;                              
1587 }                                                
1588                                                  
1589 static int sas_get_phy_attached_sas_addr(stru    
1590                                          int     
1591 {                                                
1592         int res;                                 
1593         struct smp_resp *disc_resp;              
1594         struct discover_resp *dr;                
1595                                                  
1596         disc_resp = alloc_smp_resp(DISCOVER_R    
1597         if (!disc_resp)                          
1598                 return -ENOMEM;                  
1599         dr = &disc_resp->disc;                   
1600                                                  
1601         res = sas_get_phy_discover(dev, phy_i    
1602         if (!res) {                              
1603                 memcpy(attached_sas_addr,disc    
1604                 if (dr->attached_dev_type ==     
1605                         memset(attached_sas_a    
1606         }                                        
1607         kfree(disc_resp);                        
1608         return res;                              
1609 }                                                
1610                                                  
1611 static int sas_find_bcast_phy(struct domain_d    
1612                               int from_phy, b    
1613 {                                                
1614         struct expander_device *ex = &dev->ex    
1615         int res = 0;                             
1616         int i;                                   
1617                                                  
1618         for (i = from_phy; i < ex->num_phys;     
1619                 int phy_change_count = 0;        
1620                                                  
1621                 res = sas_get_phy_change_coun    
1622                 if (res)                         
1623                         goto out;                
1624                 else if (phy_change_count !=     
1625                         if (update)              
1626                                 ex->ex_phy[i]    
1627                                         phy_c    
1628                         *phy_id = i;             
1629                         return 0;                
1630                 }                                
1631         }                                        
1632 out:                                             
1633         return res;                              
1634 }                                                
1635                                                  
1636 static int sas_get_ex_change_count(struct dom    
1637 {                                                
1638         int res;                                 
1639         u8  *rg_req;                             
1640         struct smp_resp  *rg_resp;               
1641                                                  
1642         rg_req = alloc_smp_req(RG_REQ_SIZE);     
1643         if (!rg_req)                             
1644                 return -ENOMEM;                  
1645                                                  
1646         rg_resp = alloc_smp_resp(RG_RESP_SIZE    
1647         if (!rg_resp) {                          
1648                 kfree(rg_req);                   
1649                 return -ENOMEM;                  
1650         }                                        
1651                                                  
1652         rg_req[1] = SMP_REPORT_GENERAL;          
1653                                                  
1654         res = smp_execute_task(dev, rg_req, R    
1655                                RG_RESP_SIZE);    
1656         if (res)                                 
1657                 goto out;                        
1658         if (rg_resp->result != SMP_RESP_FUNC_    
1659                 res = rg_resp->result;           
1660                 goto out;                        
1661         }                                        
1662                                                  
1663         *ecc = be16_to_cpu(rg_resp->rg.change    
1664 out:                                             
1665         kfree(rg_resp);                          
1666         kfree(rg_req);                           
1667         return res;                              
1668 }                                                
1669 /**                                              
1670  * sas_find_bcast_dev -  find the device issu    
1671  * @dev:domain device to be detect.              
1672  * @src_dev: the device which originated BROA    
1673  *                                               
1674  * Add self-configuration expander suport. Su    
1675  * when the first level expander is self-conf    
1676  * second level expander, BROADCAST(CHANGE) w    
1677  * in the second level expander, but also be     
1678  * expander (see SAS protocol SAS 2r-14, 7.11    
1679  * expander changed count in two level expand    
1680  * once, but the phy which chang count has ch    
1681  * we concerned.                                 
1682  */                                              
1683                                                  
1684 static int sas_find_bcast_dev(struct domain_d    
1685                               struct domain_d    
1686 {                                                
1687         struct expander_device *ex = &dev->ex    
1688         int ex_change_count = -1;                
1689         int phy_id = -1;                         
1690         int res;                                 
1691         struct domain_device *ch;                
1692                                                  
1693         res = sas_get_ex_change_count(dev, &e    
1694         if (res)                                 
1695                 goto out;                        
1696         if (ex_change_count != -1 && ex_chang    
1697                 /* Just detect if this expand    
1698                 * in order to determine if th    
1699                 * and do not update phy chang    
1700                 */                               
1701                 res = sas_find_bcast_phy(dev,    
1702                 if (phy_id != -1) {              
1703                         *src_dev = dev;          
1704                         ex->ex_change_count =    
1705                         SAS_DPRINTK("Expander    
1706                         return res;              
1707                 } else                           
1708                         SAS_DPRINTK("Expander    
1709         }                                        
1710         list_for_each_entry(ch, &ex->children    
1711                 if (ch->dev_type == EDGE_DEV     
1712                         res = sas_find_bcast_    
1713                         if (src_dev)             
1714                                 return res;      
1715                 }                                
1716         }                                        
1717 out:                                             
1718         return res;                              
1719 }                                                
1720                                                  
1721 static void sas_unregister_ex_tree(struct dom    
1722 {                                                
1723         struct expander_device *ex = &dev->ex    
1724         struct domain_device *child, *n;         
1725                                                  
1726         list_for_each_entry_safe(child, n, &e    
1727                 if (child->dev_type == EDGE_D    
1728                     child->dev_type == FANOUT    
1729                         sas_unregister_ex_tre    
1730                 else                             
1731                         sas_unregister_dev(ch    
1732         }                                        
1733         sas_unregister_dev(dev);                 
1734 }                                                
1735                                                  
1736 static void sas_unregister_devs_sas_addr(stru    
1737                                          int     
1738 {                                                
1739         struct expander_device *ex_dev = &par    
1740         struct ex_phy *phy = &ex_dev->ex_phy[    
1741         struct domain_device *child, *n;         
1742         if (last) {                              
1743                 list_for_each_entry_safe(chil    
1744                         &ex_dev->children, si    
1745                         if (SAS_ADDR(child->s    
1746                             SAS_ADDR(phy->att    
1747                                 if (child->de    
1748                                     child->de    
1749                                         sas_u    
1750                                 else             
1751                                         sas_u    
1752                                 break;           
1753                         }                        
1754                 }                                
1755                 sas_disable_routing(parent, p    
1756         }                                        
1757         memset(phy->attached_sas_addr, 0, SAS    
1758         sas_port_delete_phy(phy->port, phy->p    
1759         if (phy->port->num_phys == 0)            
1760                 sas_port_delete(phy->port);      
1761         phy->port = NULL;                        
1762 }                                                
1763                                                  
1764 static int sas_discover_bfs_by_root_level(str    
1765                                           con    
1766 {                                                
1767         struct expander_device *ex_root = &ro    
1768         struct domain_device *child;             
1769         int res = 0;                             
1770                                                  
1771         list_for_each_entry(child, &ex_root->    
1772                 if (child->dev_type == EDGE_D    
1773                     child->dev_type == FANOUT    
1774                         struct sas_expander_d    
1775                                 rphy_to_expan    
1776                                                  
1777                         if (level > ex->level    
1778                                 res = sas_dis    
1779                                                  
1780                         else if (level == ex-    
1781                                 res = sas_ex_    
1782                 }                                
1783         }                                        
1784         return res;                              
1785 }                                                
1786                                                  
1787 static int sas_discover_bfs_by_root(struct do    
1788 {                                                
1789         int res;                                 
1790         struct sas_expander_device *ex = rphy    
1791         int level = ex->level+1;                 
1792                                                  
1793         res = sas_ex_discover_devices(dev, -1    
1794         if (res)                                 
1795                 goto out;                        
1796         do {                                     
1797                 res = sas_discover_bfs_by_roo    
1798                 mb();                            
1799                 level += 1;                      
1800         } while (level <= dev->port->disc.max    
1801 out:                                             
1802         return res;                              
1803 }                                                
1804                                                  
1805 static int sas_discover_new(struct domain_dev    
1806 {                                                
1807         struct ex_phy *ex_phy = &dev->ex_dev.    
1808         struct domain_device *child;             
1809         bool found = false;                      
1810         int res, i;                              
1811                                                  
1812         SAS_DPRINTK("ex %016llx phy%d new dev    
1813                     SAS_ADDR(dev->sas_addr),     
1814         res = sas_ex_phy_discover(dev, phy_id    
1815         if (res)                                 
1816                 goto out;                        
1817         /* to support the wide port inserted     
1818         for (i = 0; i < dev->ex_dev.num_phys;    
1819                 struct ex_phy *ex_phy_temp =     
1820                 if (i == phy_id)                 
1821                         continue;                
1822                 if (SAS_ADDR(ex_phy_temp->att    
1823                     SAS_ADDR(ex_phy->attached    
1824                         found = true;            
1825                         break;                   
1826                 }                                
1827         }                                        
1828         if (found) {                             
1829                 sas_ex_join_wide_port(dev, ph    
1830                 return 0;                        
1831         }                                        
1832         res = sas_ex_discover_devices(dev, ph    
1833         if (!res)                                
1834                 goto out;                        
1835         list_for_each_entry(child, &dev->ex_d    
1836                 if (SAS_ADDR(child->sas_addr)    
1837                     SAS_ADDR(ex_phy->attached    
1838                         if (child->dev_type =    
1839                             child->dev_type =    
1840                                 res = sas_dis    
1841                         break;                   
1842                 }                                
1843         }                                        
1844 out:                                             
1845         return res;                              
1846 }                                                
1847                                                  
1848 static int sas_rediscover_dev(struct domain_d    
1849 {                                                
1850         struct expander_device *ex = &dev->ex    
1851         struct ex_phy *phy = &ex->ex_phy[phy_    
1852         u8 attached_sas_addr[8];                 
1853         int res;                                 
1854                                                  
1855         res = sas_get_phy_attached_sas_addr(d    
1856         switch (res) {                           
1857         case SMP_RESP_NO_PHY:                    
1858                 phy->phy_state = PHY_NOT_PRES    
1859                 sas_unregister_devs_sas_addr(    
1860                 goto out; break;                 
1861         case SMP_RESP_PHY_VACANT:                
1862                 phy->phy_state = PHY_VACANT;     
1863                 sas_unregister_devs_sas_addr(    
1864                 goto out; break;                 
1865         case SMP_RESP_FUNC_ACC:                  
1866                 break;                           
1867         }                                        
1868                                                  
1869         if (SAS_ADDR(attached_sas_addr) == 0)    
1870                 phy->phy_state = PHY_EMPTY;      
1871                 sas_unregister_devs_sas_addr(    
1872         } else if (SAS_ADDR(attached_sas_addr    
1873                    SAS_ADDR(phy->attached_sas    
1874                 SAS_DPRINTK("ex %016llx phy 0    
1875                             SAS_ADDR(dev->sas    
1876                 sas_ex_phy_discover(dev, phy_    
1877         } else                                   
1878                 res = sas_discover_new(dev, p    
1879 out:                                             
1880         return res;                              
1881 }                                                
1882                                                  
1883 /**                                              
1884  * sas_rediscover - revalidate the domain.       
1885  * @dev:domain device to be detect.              
1886  * @phy_id: the phy id will be detected.         
1887  *                                               
1888  * NOTE: this process _must_ quit (return) as    
1889  * errors are encountered.  Connection recove    
1890  * Discover process only interrogates devices    
1891  * domain.For plugging out, we un-register th    
1892  * the last phy in the port, for other phys i    
1893  * from the port.For inserting, we do discove    
1894  * first phy,for other phys in this port, we     
1895  * forming the wide-port.                        
1896  */                                              
1897 static int sas_rediscover(struct domain_devic    
1898 {                                                
1899         struct expander_device *ex = &dev->ex    
1900         struct ex_phy *changed_phy = &ex->ex_    
1901         int res = 0;                             
1902         int i;                                   
1903         bool last = true;       /* is this th    
1904                                                  
1905         SAS_DPRINTK("ex %016llx phy%d origina    
1906                     SAS_ADDR(dev->sas_addr),     
1907                                                  
1908         if (SAS_ADDR(changed_phy->attached_sa    
1909                 for (i = 0; i < ex->num_phys;    
1910                         struct ex_phy *phy =     
1911                                                  
1912                         if (i == phy_id)         
1913                                 continue;        
1914                         if (SAS_ADDR(phy->att    
1915                             SAS_ADDR(changed_    
1916                                 SAS_DPRINTK("    
1917                                             "    
1918                                 last = false;    
1919                                 break;           
1920                         }                        
1921                 }                                
1922                 res = sas_rediscover_dev(dev,    
1923         } else                                   
1924                 res = sas_discover_new(dev, p    
1925         return res;                              
1926 }                                                
1927                                                  
1928 /**                                              
1929  * sas_revalidate_domain -- revalidate the do    
1930  * @port: port to the domain of interest         
1931  *                                               
1932  * NOTE: this process _must_ quit (return) as    
1933  * errors are encountered.  Connection recove    
1934  * Discover process only interrogates devices    
1935  * domain.                                       
1936  */                                              
1937 int sas_ex_revalidate_domain(struct domain_de    
1938 {                                                
1939         int res;                                 
1940         struct domain_device *dev = NULL;        
1941                                                  
1942         res = sas_find_bcast_dev(port_dev, &d    
1943         if (res)                                 
1944                 goto out;                        
1945         if (dev) {                               
1946                 struct expander_device *ex =     
1947                 int i = 0, phy_id;               
1948                                                  
1949                 do {                             
1950                         phy_id = -1;             
1951                         res = sas_find_bcast_    
1952                         if (phy_id == -1)        
1953                                 break;           
1954                         res = sas_rediscover(    
1955                         i = phy_id + 1;          
1956                 } while (i < ex->num_phys);      
1957         }                                        
1958 out:                                             
1959         return res;                              
1960 }                                                
1961                                                  
1962 int sas_smp_handler(struct Scsi_Host *shost,     
1963                     struct request *req)         
1964 {                                                
1965         struct domain_device *dev;               
1966         int ret, type;                           
1967         struct request *rsp = req->next_rq;      
1968                                                  
1969         if (!rsp) {                              
1970                 printk("%s: space for a smp r    
1971                        __func__);                
1972                 return -EINVAL;                  
1973         }                                        
1974                                                  
1975         /* no rphy means no smp target suppor    
1976         if (!rphy)                               
1977                 return sas_smp_host_handler(s    
1978                                                  
1979         type = rphy->identify.device_type;       
1980                                                  
1981         if (type != SAS_EDGE_EXPANDER_DEVICE     
1982             type != SAS_FANOUT_EXPANDER_DEVIC    
1983                 printk("%s: can we send a smp    
1984                        __func__);                
1985                 return -EINVAL;                  
1986         }                                        
1987                                                  
1988         dev = sas_find_dev_by_rphy(rphy);        
1989         if (!dev) {                              
1990                 printk("%s: fail to find a do    
1991                 return -EINVAL;                  
1992         }                                        
1993                                                  
1994         /* do we need to support multiple seg    
1995         if (req->bio->bi_vcnt > 1 || rsp->bio    
1996                 printk("%s: multiple segments    
1997                        __func__, req->bio->bi    
1998                        rsp->bio->bi_vcnt, blk    
1999                 return -EINVAL;                  
2000         }                                        
2001                                                  
2002         ret = smp_execute_task(dev, bio_data(    
2003                                bio_data(rsp->    
2004         if (ret > 0) {                           
2005                 /* positive number is the unt    
2006                 rsp->resid_len = ret;            
2007                 req->resid_len = 0;              
2008                 ret = 0;                         
2009         } else if (ret == 0) {                   
2010                 rsp->resid_len = 0;              
2011                 req->resid_len = 0;              
2012         }                                        
2013                                                  
2014         return ret;                              
2015 }                                                
2016                                                  
  This page was automatically generated by the LXR engine.