]>
Commit | Line | Data |
---|---|---|
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 | if(!rindex(cl->target,'.')) continue; | |
98 | int channel=strtol(rindex(cl->target,'.')+1,NULL,16); | |
99 | //printf("channel %x name %s target %s\n",channel,cl->name,cl->target); | |
100 | if(strncmp("cdev",cl->name,4)==0) | |
101 | { | |
102 | if(cl->name[4]=='0') /* first channel in group gets an entry */ | |
103 | { | |
104 | if(cutypes[channel]<0) cutypes[channel]*=-1; /* make sure its positive */ | |
105 | } | |
106 | else /* other channels in group are skipped */ | |
107 | if(cutypes[channel]>0) cutypes[channel]*=-1; /* make sure its negative */ | |
108 | } | |
109 | ||
110 | } | |
111 | } | |
112 | ||
113 | dlist_for_each_data(devlist, curdev, struct sysfs_device) | |
114 | { | |
115 | int readonly=0; | |
116 | res=new_mem(sizeof *res); | |
117 | ||
118 | attributes = sysfs_get_device_attributes(curdev); | |
119 | dlist_for_each_data(attributes,curattr, struct sysfs_attribute) | |
120 | { | |
121 | if (strcmp("online",curattr->name)==0) | |
122 | res->io.enabled=atoi(curattr->value); | |
123 | else if (strcmp("cutype",curattr->name)==0) | |
124 | { | |
125 | cutype=strtol(curattr->value,NULL,16); | |
126 | cumod=strtol(index(curattr->value,'/')+1,NULL,16); | |
127 | } else if (strcmp("devtype",curattr->name)==0) | |
128 | { | |
129 | devtype=strtol(curattr->value,NULL,16); | |
130 | devmod=strtol(index(curattr->value,'/')+1,NULL,16); | |
131 | } else if (strcmp("readonly",curattr->name)==0) | |
132 | { | |
133 | readonly=atoi(curattr->value); | |
134 | } | |
135 | } | |
136 | ||
137 | res->io.type=res_io; | |
138 | res->io.access=readonly?acc_ro:acc_rw; | |
139 | res->io.base=strtol(rindex(curdev->bus_id,'.')+1,NULL,16); | |
140 | ||
141 | /* Skip additional channels for multi-channel devices */ | |
142 | if(cutypes[res->io.base] < -3) | |
143 | continue; | |
144 | ||
145 | if(disks_only && cutype!=0x3990 && cutype!=0x2105 && cutype!=0x3880 && cutype!=0x9343 && cutype!=0x6310 && | |
146 | (cutype != 0x1731 || devtype != 0x1732 || cumod != 3)) | |
147 | continue; | |
148 | ||
149 | res->io.range=1; | |
150 | switch (cutype) | |
151 | { | |
152 | /* three channels */ | |
153 | case 0x1731: /* QDIO (QETH, HSI, zFCP) */ | |
154 | res->io.range++; | |
155 | /* two channels */ | |
156 | case 0x3088: /* CU3088 (CTC, LCS) */ | |
157 | res->io.range++; | |
158 | } | |
159 | ||
160 | hd=add_hd_entry(hd_data,__LINE__,0); | |
161 | add_res_entry(&hd->res,res); | |
162 | hd->vendor.id=MAKE_ID(TAG_SPECIAL,0x6001); /* IBM */ | |
163 | hd->device.id=MAKE_ID(TAG_SPECIAL,cutype); | |
164 | hd->sub_device.id=MAKE_ID(TAG_SPECIAL,devtype); | |
165 | hd->bus.id=bus_ccw; | |
166 | hd->sysfs_device_link = new_str(hd_sysfs_id(curdev->path)); | |
167 | hd->sysfs_bus_id = new_str(strrchr(curdev->path,'/')+1); | |
168 | ||
169 | if(cutypes[res->io.base]==-2) /* virtual reader */ | |
170 | { | |
171 | hd->base_class.id=bc_scanner; | |
172 | } | |
173 | if(cutypes[res->io.base]==-3) /* virtual punch */ | |
174 | { | |
175 | hd->base_class.id=bc_printer; | |
176 | } | |
177 | /* all other device data (names, classes etc.) comes from the s390 ID file */ | |
178 | ||
179 | hd->detail=free_hd_detail(hd->detail); | |
180 | hd->detail=new_mem(sizeof *hd->detail); | |
181 | hd->detail->ccw.type=hd_detail_ccw; | |
182 | hd->detail->ccw.data=new_mem(sizeof(ccw_t)); | |
183 | hd->detail->ccw.data->cu_model=cumod; | |
184 | hd->detail->ccw.data->dev_model=devmod; | |
185 | hd->detail->ccw.data->lcss=(strtol(curdev->bus_id,0,16) << 8) + strtol(curdev->bus_id+2,0,16); | |
186 | hddb_add_info(hd_data,hd); | |
187 | } | |
188 | ||
189 | if(virtual_machine) | |
190 | { | |
191 | /* add an unactivated IUCV device */ | |
192 | hd=add_hd_entry(hd_data,__LINE__,0); | |
193 | hd->vendor.id=MAKE_ID(TAG_SPECIAL,0x6001); /* IBM */ | |
194 | hd->device.id=MAKE_ID(TAG_SPECIAL,0x0005); /* IUCV */ | |
195 | hd->bus.id=bus_iucv; | |
196 | hd->base_class.id=bc_network; | |
197 | hd->status.active=status_no; | |
198 | hd->status.available=status_yes; | |
199 | hddb_add_info(hd_data,hd); | |
200 | ||
201 | /* add activated IUCV devices */ | |
202 | bus=sysfs_open_bus(BUSNAME_IUCV); | |
203 | if(bus) | |
204 | { | |
205 | devlist=sysfs_get_bus_devices(bus); | |
206 | if(devlist) | |
207 | { | |
208 | dlist_for_each_data(devlist, curdev, struct sysfs_device) | |
209 | { | |
210 | hd=add_hd_entry(hd_data,__LINE__,0); | |
211 | hd->vendor.id=MAKE_ID(TAG_SPECIAL,0x6001); /* IBM */ | |
212 | hd->device.id=MAKE_ID(TAG_SPECIAL,0x0005); /* IUCV */ | |
213 | hd->bus.id=bus_iucv; | |
214 | hd->base_class.id=bc_network; | |
215 | hd->status.active=status_yes; | |
216 | hd->status.available=status_yes; | |
217 | attributes = sysfs_get_device_attributes(curdev); | |
218 | dlist_for_each_data(attributes,curattr,struct sysfs_attribute) | |
219 | { | |
220 | if(strcmp("user",curattr->name)==0) | |
221 | hd->rom_id=new_str(curattr->value); | |
222 | } | |
223 | hd->sysfs_device_link = new_str(hd_sysfs_id(curdev->path)); | |
224 | hd->sysfs_bus_id = new_str(strrchr(curdev->path,'/')+1); | |
225 | hddb_add_info(hd_data,hd); | |
226 | } | |
227 | } | |
228 | } | |
229 | ||
230 | } | |
231 | } | |
232 | ||
233 | void hd_scan_s390(hd_data_t *hd_data) | |
234 | { | |
235 | if (!hd_probe_feature(hd_data, pr_s390)) return; | |
236 | hd_scan_s390_ex(hd_data, 0); | |
237 | } | |
238 | ||
239 | void hd_scan_s390disks(hd_data_t *hd_data) | |
240 | { | |
241 | if (!hd_probe_feature(hd_data, pr_s390disks)) return; | |
242 | hd_scan_s390_ex(hd_data, 1); | |
243 | } | |
244 | ||
245 | #endif | |
246 |