This commit was manufactured by cvs2svn to create tag
[opensuse:hwinfo.git] / src / hd / s390.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4
5 #include "hd.h"
6 #include "hd_int.h"
7 #include "hddb.h"
8 #include "s390.h"
9
10 #if defined(__s390__) || defined(__s390x__)
11
12 #include <sysfs/libsysfs.h>
13 #include <sysfs/dlist.h>
14
15 #define BUSNAME "ccw"
16 #define BUSNAME_GROUP "ccwgroup"
17 #define BUSNAME_IUCV "iucv"
18
19 static void hd_scan_s390_ex(hd_data_t *hd_data, int disks_only)
20 {
21   hd_t* hd;
22   hd_res_t* res;
23   struct sysfs_bus *bus;
24   struct sysfs_bus *bus_group;
25   struct sysfs_device *curdev = NULL;
26   struct dlist *attributes = NULL;
27   struct sysfs_attribute *curattr = NULL;
28   struct dlist *devlist = NULL;
29   struct dlist *devlist_group = NULL;
30   int virtual_machine=0;
31
32   unsigned int devtype=0,devmod=0,cutype=0,cumod=0;
33
34   /* list of each channel's cutype, used for finding multichannel devices */
35   int cutypes[1<<16]={0};
36   int i;
37
38   hd_data->module=mod_s390;
39
40   remove_hd_entries(hd_data);
41
42   bus=sysfs_open_bus(BUSNAME);
43   bus_group=sysfs_open_bus(BUSNAME_GROUP);
44
45   if (!bus)
46   {
47     ADD2LOG("unable to open" BUSNAME "bus");
48     return;
49   }
50
51   devlist=sysfs_get_bus_devices(bus);
52   if(bus_group) devlist_group=sysfs_get_bus_devices(bus_group);
53   
54   if(!devlist)
55   {
56         ADD2LOG("unable to get devices on bus " BUSNAME);
57         return;
58   }
59   
60   /* build cutypes list */
61   dlist_for_each_data(devlist, curdev, struct sysfs_device)
62   {
63     int channel=strtol(rindex(curdev->bus_id,'.')+1,NULL,16);
64     attributes = sysfs_get_device_attributes(curdev);
65     dlist_for_each_data(attributes,curattr,struct sysfs_attribute)
66     {
67       if(strcmp("cutype",curattr->name)==0)
68         cutype=strtol(curattr->value,NULL,16);
69     }
70     cutypes[channel]=cutype;
71   }
72   /* check for each channel if it must be skipped and identify virtual reader/punch */
73   for(i=0;i<(1<<16);i++)
74   {
75     if(cutypes[i]==0x3088)      /* It seems that QDIO devices only appear once */
76       cutypes[i+1]*=-1; /* negative cutype -> skip */
77
78     if(cutypes[i]==0x2540)
79     {
80       virtual_machine=1;        /* we are running in VM */
81       cutypes[i]=-2;    /* reader */
82       cutypes[i+1]=-3;  /* punch */
83     }
84   }
85   
86   /* identify grouped channels */
87   if(devlist_group) dlist_for_each_data(devlist_group, curdev, struct sysfs_device)
88   {
89     struct sysfs_directory* d;
90     struct dlist* dl;
91     struct sysfs_link* cl;
92     //printf("ccwg %s\n",curdev->path);
93     d=sysfs_open_directory(curdev->path);
94     dl=sysfs_get_dir_links(d);
95     dlist_for_each_data(dl,cl,struct sysfs_link)        /* iterate over this channel group */
96     {
97         int channel=strtol(rindex(cl->target,'.')+1,NULL,16);
98         //printf("channel %x name %s target %s\n",channel,cl->name,cl->target);
99         if(strncmp("cdev",cl->name,4)==0)
100         {
101                 if(cl->name[4]=='0')    /* first channel in group gets an entry */
102                 {
103                         if(cutypes[channel]<0) cutypes[channel]*=-1;    /* make sure its positive */
104                 }
105                 else                    /* other channels in group are skipped */
106                         if(cutypes[channel]>0) cutypes[channel]*=-1;    /* make sure its negative */
107         }
108                 
109     }
110   }
111   
112   dlist_for_each_data(devlist, curdev, struct sysfs_device)
113   {
114     int readonly=0;
115     res=new_mem(sizeof *res);
116
117     attributes = sysfs_get_device_attributes(curdev);
118     dlist_for_each_data(attributes,curattr, struct sysfs_attribute)
119     {
120       if (strcmp("online",curattr->name)==0)
121         res->io.enabled=atoi(curattr->value);
122       else if (strcmp("cutype",curattr->name)==0)
123       {
124         cutype=strtol(curattr->value,NULL,16);
125         cumod=strtol(index(curattr->value,'/')+1,NULL,16);
126       } else if (strcmp("devtype",curattr->name)==0)
127       {
128         devtype=strtol(curattr->value,NULL,16);
129         devmod=strtol(index(curattr->value,'/')+1,NULL,16);
130       } else if (strcmp("readonly",curattr->name)==0)
131       {
132         readonly=atoi(curattr->value);
133       }
134     }
135     
136     res->io.type=res_io;
137     res->io.access=readonly?acc_ro:acc_rw;
138     res->io.base=strtol(rindex(curdev->bus_id,'.')+1,NULL,16);
139
140     /* Skip additional channels for multi-channel devices */
141     if(cutypes[res->io.base] < -3)
142       continue;
143
144     if(disks_only && cutype!=0x3990 &&
145        (cutype != 0x1731 || devtype != 0x1732 || cumod != 3))
146       continue;
147
148     res->io.range=1;
149     switch (cutype)
150     {
151       /* three channels */
152       case 0x1731:    /* QDIO (QETH, HSI, zFCP) */
153         res->io.range++;
154       /* two channels */
155       case 0x3088:    /* CU3088 (CTC, LCS) */
156         res->io.range++;
157     }
158
159     hd=add_hd_entry(hd_data,__LINE__,0);
160     add_res_entry(&hd->res,res);
161     hd->vendor.id=MAKE_ID(TAG_SPECIAL,0x6001); /* IBM */
162     hd->device.id=MAKE_ID(TAG_SPECIAL,cutype);
163     hd->sub_device.id=MAKE_ID(TAG_SPECIAL,devtype);
164     hd->bus.id=bus_ccw;
165     hd->sysfs_device_link = new_str(hd_sysfs_id(curdev->path));
166     hd->sysfs_bus_id = new_str(strrchr(curdev->path,'/')+1);
167     
168     if(cutypes[res->io.base]==-2)       /* virtual reader */
169     {
170       hd->base_class.id=bc_scanner;
171     }
172     if(cutypes[res->io.base]==-3)       /* virtual punch */
173     {
174       hd->base_class.id=bc_printer;
175     }
176     /* all other device data (names, classes etc.) comes from the s390 ID file */
177
178     hd->detail=free_hd_detail(hd->detail);
179     hd->detail=new_mem(sizeof *hd->detail);
180     hd->detail->ccw.type=hd_detail_ccw;
181     hd->detail->ccw.data=new_mem(sizeof(ccw_t));
182     hd->detail->ccw.data->cu_model=cumod;
183     hd->detail->ccw.data->dev_model=devmod;
184     hd->detail->ccw.data->lcss=(strtol(curdev->bus_id,0,16) << 8) + strtol(curdev->bus_id+2,0,16);
185     hddb_add_info(hd_data,hd);
186   }
187
188   if(virtual_machine)
189   {
190         /* add an unactivated IUCV device */
191         hd=add_hd_entry(hd_data,__LINE__,0);
192         hd->vendor.id=MAKE_ID(TAG_SPECIAL,0x6001); /* IBM */
193         hd->device.id=MAKE_ID(TAG_SPECIAL,0x0005); /* IUCV */
194         hd->bus.id=bus_iucv;
195         hd->base_class.id=bc_network;
196         hd->status.active=status_no;
197         hddb_add_info(hd_data,hd);
198         
199         /* add activated IUCV devices */
200         bus=sysfs_open_bus(BUSNAME_IUCV);
201         if(bus)
202         {
203           devlist=sysfs_get_bus_devices(bus);
204           if(devlist)
205           {
206             dlist_for_each_data(devlist, curdev, struct sysfs_device)
207             {
208               hd=add_hd_entry(hd_data,__LINE__,0);
209               hd->vendor.id=MAKE_ID(TAG_SPECIAL,0x6001); /* IBM */
210               hd->device.id=MAKE_ID(TAG_SPECIAL,0x0005); /* IUCV */
211               hd->bus.id=bus_iucv;
212               hd->base_class.id=bc_network;
213               hd->status.active=status_yes;
214               attributes = sysfs_get_device_attributes(curdev);
215               dlist_for_each_data(attributes,curattr,struct sysfs_attribute)
216               {
217                 if(strcmp("user",curattr->name)==0)
218                   hd->rom_id=new_str(curattr->value);
219               }
220               hd->sysfs_device_link = new_str(hd_sysfs_id(curdev->path));
221               hd->sysfs_bus_id = new_str(strrchr(curdev->path,'/')+1);
222               hddb_add_info(hd_data,hd);
223             }
224           }
225         }
226                       
227   }
228 }
229
230 void hd_scan_s390(hd_data_t *hd_data)
231 {
232   if (!hd_probe_feature(hd_data, pr_s390)) return;
233   hd_scan_s390_ex(hd_data, 0);
234 }
235
236 void hd_scan_s390disks(hd_data_t *hd_data)
237 {
238   if (!hd_probe_feature(hd_data, pr_s390disks)) return;
239   hd_scan_s390_ex(hd_data, 1);
240 }
241
242 #endif
243