]> git.ipfire.org Git - ipfire-2.x.git/blob - src/hwinfo/src/hd/block.c
Signierten GPG-Schluessel importiert.
[ipfire-2.x.git] / src / hwinfo / src / hd / block.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <unistd.h>
5 #include <errno.h>
6 #include <fcntl.h>
7 #include <ctype.h>
8 #include <sys/stat.h>
9 #include <sys/types.h>
10 #include <sys/ioctl.h>
11 #include <linux/iso_fs.h>
12 #include <scsi/sg.h>
13
14 #include "hd.h"
15 #include "hd_int.h"
16 #include "hddb.h"
17 #include "block.h"
18
19 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
20 * block device stuff
21 *
22 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
23 */
24
25 static void get_block_devs(hd_data_t *hd_data);
26 static void add_partitions(hd_data_t *hd_data, hd_t *hd, char *path);
27 static void add_cdrom_info(hd_data_t *hd_data, hd_t *hd);
28 static void add_other_sysfs_info(hd_data_t *hd_data, hd_t *hd, struct sysfs_device *sf_dev);
29 static void add_ide_sysfs_info(hd_data_t *hd_data, hd_t *hd, struct sysfs_device *sf_dev);
30 static void add_scsi_sysfs_info(hd_data_t *hd_data, hd_t *hd, struct sysfs_device *sf_dev);
31 static void read_partitions(hd_data_t *hd_data);
32 static void read_cdroms(hd_data_t *hd_data);
33 static cdrom_info_t *new_cdrom_entry(cdrom_info_t **ci);
34 static cdrom_info_t *get_cdrom_entry(cdrom_info_t *ci, int n);
35 static void get_scsi_tape(hd_data_t *hd_data);
36 static void get_generic_scsi_devs(hd_data_t *hd_data);
37 static void add_disk_size(hd_data_t *hd_data, hd_t *hd);
38
39
40 void hd_scan_sysfs_block(hd_data_t *hd_data)
41 {
42 if(!hd_probe_feature(hd_data, pr_block)) return;
43
44 hd_data->module = mod_block;
45
46 /* some clean-up */
47 remove_hd_entries(hd_data);
48
49 hd_data->disks = free_str_list(hd_data->disks);
50 hd_data->partitions = free_str_list(hd_data->partitions);
51 hd_data->cdroms = free_str_list(hd_data->cdroms);
52
53 if(hd_probe_feature(hd_data, pr_block_mods)) {
54 PROGRESS(1, 0, "block modules");
55 load_module(hd_data, "ide_cd");
56 load_module(hd_data, "sr_mod");
57 load_module(hd_data, "sd_mod");
58 load_module(hd_data, "st");
59 }
60
61 PROGRESS(2, 0, "sysfs drivers");
62
63 hd_sysfs_driver_list(hd_data);
64
65 PROGRESS(3, 0, "cdrom");
66
67 read_cdroms(hd_data);
68
69 PROGRESS(4, 0, "partition");
70
71 read_partitions(hd_data);
72
73 PROGRESS(5, 0, "get sysfs block dev data");
74
75 get_block_devs(hd_data);
76
77 if(hd_data->cdrom) {
78 ADD2LOG("oops: cdrom list not empty\n");
79 }
80 }
81
82
83 void get_block_devs(hd_data_t *hd_data)
84 {
85 str_list_t *sl;
86 char *s, *t;
87 unsigned u1, u2, u3;
88 uint64_t ul0;
89 hd_t *hd, *hd1;
90 hd_dev_num_t dev_num;
91
92 struct sysfs_bus *sf_bus;
93 struct sysfs_class *sf_class;
94 struct sysfs_class_device *sf_cdev;
95 struct sysfs_device *sf_dev;
96 struct dlist *sf_cdev_list;
97 struct dlist *sf_ide_list = NULL;
98 struct sysfs_device *sf_ide;
99
100 sf_bus = sysfs_open_bus("ide");
101 if(sf_bus) {
102 sf_ide_list = sysfs_get_bus_devices(sf_bus);
103 if(sf_ide_list) dlist_for_each_data(sf_ide_list, sf_ide, struct sysfs_device) {
104 ADD2LOG(
105 " ide: bus_id = %s path = %s\n",
106 sf_ide->bus_id,
107 hd_sysfs_id(sf_ide->path)
108 );
109 }
110 }
111
112 sf_class = sysfs_open_class("block");
113
114 if(!sf_class) {
115 ADD2LOG("sysfs: no such class: block\n");
116 return;
117 }
118
119 sf_cdev_list = sysfs_get_class_devices(sf_class);
120 if(sf_cdev_list) dlist_for_each_data(sf_cdev_list, sf_cdev, struct sysfs_class_device) {
121 ADD2LOG(
122 " block: name = %s, path = %s\n",
123 sf_cdev->name,
124 hd_sysfs_id(sf_cdev->path)
125 );
126
127 memset(&dev_num, 0, sizeof dev_num);
128
129 if((s = hd_attr_str(sysfs_get_classdev_attr(sf_cdev, "dev")))) {
130 if(sscanf(s, "%u:%u", &u1, &u2) == 2) {
131 dev_num.type = 'b';
132 dev_num.major = u1;
133 dev_num.minor = u2;
134 dev_num.range = 1;
135 }
136 ADD2LOG(" dev = %u:%u\n", u1, u2);
137 }
138
139 if(hd_attr_uint(sysfs_get_classdev_attr(sf_cdev, "range"), &ul0, 0)) {
140 dev_num.range = ul0;
141 ADD2LOG(" range = %u\n", dev_num.range);
142 }
143
144 sf_dev = sysfs_get_classdev_device(sf_cdev);
145 if(sf_dev) {
146 ADD2LOG(
147 " block device: bus = %s, bus_id = %s driver = %s\n path = %s\n",
148 sf_dev->bus,
149 sf_dev->bus_id,
150 sf_dev->driver_name,
151 hd_sysfs_id(sf_dev->path)
152 );
153 }
154
155 hd = NULL;
156
157 /* check if disk is DASD and has already been found by s390.c */
158 if(sf_dev && sf_dev->driver_name && strstr(sf_dev->driver_name,"dasd"))
159 {
160 char bid[9];
161 hd_res_t* res;
162 //fprintf(stderr,"dn %s bi %s\n",sf_dev->driver_name,sf_dev->bus_id);
163 for(hd=hd_data->hd;hd;hd=hd->next)
164 {
165 //fprintf(stderr,"bcid %d\n",hd->base_class.id);
166 if(hd->base_class.id == bc_storage_device
167 && hd->detail
168 && hd->detail->ccw.type == hd_detail_ccw)
169 {
170 for(res=hd->res;res;res=res->next)
171 {
172 if(res->io.type==res_io)
173 {
174 sprintf(bid,"%01x.%01x.%04x",
175 hd->detail->ccw.data->lcss >> 8,
176 hd->detail->ccw.data->lcss & 0xff,
177 (unsigned short)res->io.base);
178 //fprintf(stderr,"bid %s\n",bid);
179 if (strcmp(bid,sf_dev->bus_id)==0) goto out;
180 }
181 }
182 }
183 }
184 hd=NULL;
185 out:;
186 }
187 else if((sl = search_str_list(hd_data->disks, hd_sysfs_name2_dev(sf_cdev->name)))) {
188 hd = add_hd_entry(hd_data, __LINE__, 0);
189 hd->sub_class.id = sc_sdev_disk;
190 }
191 else if((sl = search_str_list(hd_data->cdroms, hd_sysfs_name2_dev(sf_cdev->name)))) {
192 hd = add_hd_entry(hd_data, __LINE__, 0);
193 hd->sub_class.id = sc_sdev_cdrom;
194 }
195 else if(
196 sf_dev &&
197 sf_dev->bus &&
198 (!strcmp(sf_dev->bus, "scsi") || !strcmp(sf_dev->bus, "ide"))
199 ) {
200 hd = add_hd_entry(hd_data, __LINE__, 0);
201 hd->sub_class.id = sc_sdev_other;
202 }
203
204 if(hd) {
205 str_printf(&hd->unix_dev_name, 0, "/dev/%s", hd_sysfs_name2_dev(sf_cdev->name));
206
207 hd->base_class.id = bc_storage_device;
208
209 hd->sysfs_id = new_str(hd_sysfs_id(sf_cdev->path));
210
211 if(sf_dev) hd->sysfs_device_link = new_str(hd_sysfs_id(sf_dev->path));
212
213 hd->unix_dev_num = dev_num;
214
215 hd->bus.id = bus_none;
216
217 if(sf_dev) {
218 if(sf_dev->bus) {
219 if(!strcmp(sf_dev->bus, "ide")) hd->bus.id = bus_ide;
220 else if(!strcmp(sf_dev->bus, "scsi")) hd->bus.id = bus_scsi;
221 }
222 hd->sysfs_bus_id = new_str(sf_dev->bus_id);
223 }
224
225 if(sf_dev && (s = hd_sysfs_id(sf_dev->path))) {
226
227 /* parent has longest matching sysfs id */
228 u2 = strlen(s);
229 for(u3 = 0, hd1 = hd_data->hd; hd1; hd1 = hd1->next) {
230 if(hd1->sysfs_id) {
231 u1 = strlen(hd1->sysfs_id);
232 if(u1 > u3 && u1 <= u2 && !strncmp(s, hd1->sysfs_id, u1)) {
233 u3 = u1;
234 hd->attached_to = hd1->idx;
235 }
236 }
237 }
238
239 /* find longest matching sysfs id we have a driver for */
240 s = new_str(s);
241 t = strrchr(s, '/');
242 if(t) *t = 0;
243 t = hd_sysfs_find_driver(hd_data, s, 0);
244 if(t) {
245 add_str_list(&hd->drivers, t);
246 }
247 s = free_mem(s);
248
249 /* look for ide-scsi handled devices */
250 if(hd->bus.id == bus_scsi) {
251 if(sf_ide_list) dlist_for_each_data(sf_ide_list, sf_ide, struct sysfs_device) {
252 if(
253 strcmp(sf_dev->path, sf_ide->path) &&
254 !strncmp(sf_dev->path, sf_ide->path, strlen(sf_ide->path)) &&
255 sscanf(sf_ide->bus_id, "%u.%u", &u1, &u2) == 2
256 ) {
257 str_printf(&hd->unix_dev_name2, 0, "/dev/hd%c", 'a' + (u1 << 1) + u2);
258 }
259 }
260 }
261 }
262
263 /*
264 * set hd->drivers before calling any of add_xxx_sysfs_info()
265 */
266 if(
267 sf_dev &&
268 sf_dev->driver_name &&
269 *sf_dev->driver_name &&
270 strcmp(sf_dev->driver_name, "unknown")
271 ) {
272 add_str_list(&hd->drivers, sf_dev->driver_name);
273 }
274
275 if(hd->bus.id == bus_ide) {
276 add_ide_sysfs_info(hd_data, hd, sf_dev);
277 }
278 else if(hd->bus.id == bus_scsi) {
279 add_scsi_sysfs_info(hd_data, hd, sf_dev);
280 }
281 else {
282 add_other_sysfs_info(hd_data, hd, sf_dev);
283 }
284
285
286 if(hd->sub_class.id == sc_sdev_cdrom) {
287 add_cdrom_info(hd_data, hd);
288 }
289
290 if(
291 hd->sub_class.id == sc_sdev_disk &&
292 hd_probe_feature(hd_data, pr_block_part)
293 ) {
294 add_partitions(hd_data, hd, sf_cdev->path);
295 }
296
297 }
298
299 }
300
301 sysfs_close_class(sf_class);
302
303 sysfs_close_bus(sf_bus);
304 }
305
306
307 /*
308 * Find driver for sysfs_id.
309 *
310 * Return driver for id (exact = 1) or longest matching id (exact = 0).
311 */
312 char *hd_sysfs_find_driver(hd_data_t *hd_data, char *sysfs_id, int exact)
313 {
314 hd_sysfsdrv_t *sf;
315 char *t;
316 unsigned u1, u2, u3;
317
318 if(!sysfs_id || !*sysfs_id) return NULL;
319
320 t = NULL;
321
322 if(exact) {
323 for(sf = hd_data->sysfsdrv; sf; sf = sf->next) {
324 if(!strcmp(sysfs_id, sf->device)) {
325 t = sf->driver;
326 break;
327 }
328 }
329 }
330 else {
331 u2 = strlen(sysfs_id);
332 u3 = 0;
333 for(sf = hd_data->sysfsdrv; sf; sf = sf->next) {
334 u1 = strlen(sf->device);
335 if(u1 > u3 && u1 <= u2 && !strncmp(sysfs_id, sf->device, u1)) {
336 u3 = u1;
337 t = sf->driver;
338 }
339 }
340 }
341
342 return t;
343 }
344
345
346 void add_partitions(hd_data_t *hd_data, hd_t *hd, char *path)
347 {
348 hd_t *hd1;
349 str_list_t *sl;
350 char *s;
351 size_t len;
352
353 s = hd->unix_dev_name + sizeof "/dev/" - 1;
354 len = strlen(s);
355 for(sl = hd_data->partitions; sl; sl = sl->next) {
356 if(!strncmp(sl->str, s, len)) {
357 hd1 = add_hd_entry(hd_data, __LINE__, 0);
358 hd1->base_class.id = bc_partition;
359 str_printf(&hd1->unix_dev_name, 0, "/dev/%s", sl->str);
360 hd1->attached_to = hd->idx;
361
362 str_printf(&hd1->sysfs_id, 0, "%s/%s", hd->sysfs_id, hd_sysfs_dev2_name(sl->str));
363 }
364 }
365 }
366
367
368 void add_cdrom_info(hd_data_t *hd_data, hd_t *hd)
369 {
370 cdrom_info_t *ci, **prev;
371
372 hd->detail = free_hd_detail(hd->detail);
373 hd->detail = new_mem(sizeof *hd->detail);
374 hd->detail->type = hd_detail_cdrom;
375
376 for(ci = *(prev = &hd_data->cdrom); ci; ci = *(prev = &ci->next)) {
377 if(!strcmp(hd->unix_dev_name + sizeof "/dev/" - 1, ci->name)) {
378 hd->detail->cdrom.data = ci;
379 *prev = ci->next;
380 hd->detail->cdrom.data->next = NULL;
381 break;
382 }
383 }
384
385 if((ci = hd->detail->cdrom.data)) {
386 /* update prog_if: cdr, cdrw, ... */
387 if(
388 /* ###### FIXME: dosn't work anyway: ide-scsi doesn't support sysfs */
389 hd->bus.id == bus_scsi &&
390 !search_str_list(hd->drivers, "ide-scsi") /* could be ide, though */
391 ) {
392 /* scsi devs lie */
393 if(ci->dvd && (ci->cdrw || ci->dvdr || ci->dvdram)) {
394 ci->dvd = ci->dvdr = ci->dvdram = 0;
395 }
396 ci->dvdr = ci->dvdram = 0;
397 ci->cdr = ci->cdrw = 0;
398 if(hd->prog_if.id == pif_cdr) ci->cdr = 1;
399 }
400
401 /* trust ide info */
402 if(ci->dvd) {
403 hd->is.dvd = 1;
404 hd->prog_if.id = pif_dvd;
405 }
406 if(ci->cdr) {
407 hd->is.cdr = 1;
408 hd->prog_if.id = pif_cdr;
409 }
410 if(ci->cdrw) {
411 hd->is.cdrw = 1;
412 hd->prog_if.id = pif_cdrw;
413 }
414 if(ci->dvdr) {
415 hd->is.dvdr = 1;
416 hd->prog_if.id = pif_dvdr;
417 }
418 if(ci->dvdram) {
419 hd->is.dvdram = 1;
420 hd->prog_if.id = pif_dvdram;
421 }
422 }
423
424 if(
425 hd_probe_feature(hd_data, pr_block_cdrom) &&
426 hd_report_this(hd_data, hd)
427 ) {
428 hd_read_cdrom_info(hd_data, hd);
429 }
430 }
431
432
433 void add_other_sysfs_info(hd_data_t *hd_data, hd_t *hd, struct sysfs_device *sf_dev)
434 {
435 unsigned u0, u1;
436 char c;
437
438 if(hd->sysfs_id) {
439 if(
440 sscanf(hd->sysfs_id, "/block/cciss!c%ud%u", &u0, &u1) == 2
441 ) {
442 hd->slot = (u0 << 8) + u1;
443 str_printf(&hd->device.name, 0, "CCISS disk %u/%u", u0, u1);
444 }
445 else if(
446 sscanf(hd->sysfs_id, "/block/ida!c%ud%u", &u0, &u1) == 2
447 ) {
448 hd->slot = (u0 << 8) + u1;
449 str_printf(&hd->device.name, 0, "SMART Array %u/%u", u0, u1);
450 }
451 else if(
452 sscanf(hd->sysfs_id, "/block/rd!c%ud%u", &u0, &u1) == 2
453 ) {
454 hd->slot = (u0 << 8) + u1;
455 str_printf(&hd->device.name, 0, "DAC960 RAID Array %u/%u", u0, u1);
456 }
457 else if(
458 sscanf(hd->sysfs_id, "/block/i2o!hd%c", &c) == 1 &&
459 c >= 'a'
460 ) {
461 hd->slot = c - 'a';
462 str_printf(&hd->device.name, 0, "I2O disk %u", hd->slot);
463 }
464 else if(
465 sscanf(hd->sysfs_id, "/block/dasd%c", &c) == 1 &&
466 c >= 'a'
467 ) {
468 hd->slot = c - 'a';
469 hd->device.name = new_str("S390 Disk");
470 }
471 }
472
473 add_disk_size(hd_data, hd);
474 }
475
476
477 void add_ide_sysfs_info(hd_data_t *hd_data, hd_t *hd, struct sysfs_device *sf_dev)
478 {
479 char *fname = NULL, buf[256], *dev_name, *s;
480 unsigned u0, u1, u2, size = 0;
481 str_list_t *sl, *sl0;
482 hd_res_t *res;
483 FILE *f;
484
485 if(!hd_report_this(hd_data, hd)) return;
486
487 if(hd->sysfs_bus_id && sscanf(hd->sysfs_bus_id, "%u.%u", &u0, &u1) == 2) {
488 /* host.master/slave */
489 hd->slot = (u0 << 1) + u1;
490 }
491
492 if(
493 hd->unix_dev_name &&
494 strlen(hd->unix_dev_name) > 5
495 ) {
496 dev_name = hd->unix_dev_name + 5;
497
498 str_printf(&fname, 0, PROC_IDE "/%s/media", dev_name);
499 if((sl = read_file(fname, 0, 1))) {
500
501 if(strstr(sl->str, "floppy"))
502 hd->sub_class.id = sc_sdev_floppy;
503 else if(strstr(sl->str, "cdrom"))
504 hd->sub_class.id = sc_sdev_cdrom;
505 else if(strstr(sl->str, "tape"))
506 hd->sub_class.id = sc_sdev_tape;
507
508 free_str_list(sl);
509 }
510
511 str_printf(&fname, 0, PROC_IDE "/%s/model", dev_name);
512 if((sl = read_file(fname, 0, 1))) {
513 hd->vendor.name = canon_str(sl->str, strlen(sl->str));
514 if((s = strchr(hd->vendor.name, ' '))) {
515 hd->device.name = canon_str(s, strlen(s));
516 if(*hd->device.name) {
517 *s = 0;
518 }
519 else {
520 hd->device.name = free_mem(hd->device.name);
521 }
522 }
523 if(!hd->device.name) {
524 hd->device.name = hd->vendor.name;
525 hd->vendor.name = NULL;
526 }
527
528 free_str_list(sl);
529 }
530
531 str_printf(&fname, 0, PROC_IDE "/%s/driver", dev_name);
532 if((sl = read_file(fname, 0, 1))) {
533 if((s = strchr(sl->str, ' '))) *s = 0;
534 s = canon_str(sl->str, strlen(sl->str));
535 add_str_list(&hd->drivers, s);
536 s = free_mem(s);
537 free_str_list(sl);
538 }
539
540 str_printf(&fname, 0, PROC_IDE "/%s/capacity", dev_name);
541 if((sl = read_file(fname, 0, 1))) {
542 if(sscanf(sl->str, "%u", &u0) == 1 && u0 != 0x7fffffff) {
543 res = add_res_entry(&hd->res, new_mem(sizeof *res));
544 res->size.type = res_size;
545 res->size.unit = size_unit_sectors;
546 res->size.val1 = size = u0;
547 res->size.val2 = 512; // ####### FIXME: sector size?
548 }
549 free_str_list(sl);
550 }
551
552 str_printf(&fname, 0, PROC_IDE "/%s/geometry", dev_name);
553 if((sl0 = read_file(fname, 0, 2))) {
554 for(sl = sl0; sl; sl = sl->next) {
555 if(sscanf(sl->str, " physical %u / %u / %u", &u0, &u1, &u2) == 3) {
556 if(u0 || u1 || u2) {
557 if(size && u1 && u2) {
558 u0 = size / (u1 * u2);
559 }
560 res = add_res_entry(&hd->res, new_mem(sizeof *res));
561 res->disk_geo.type = res_disk_geo;
562 res->disk_geo.cyls = u0;
563 res->disk_geo.heads = u1;
564 res->disk_geo.sectors = u2;
565 res->disk_geo.geotype = geo_physical;
566 }
567 continue;
568 }
569
570 if(sscanf(sl->str, " logical %u / %u / %u", &u0, &u1, &u2) == 3) {
571 if(size && u1 && u2) {
572 u0 = size / (u1 * u2);
573 }
574 res = add_res_entry(&hd->res, new_mem(sizeof *res));
575 res->disk_geo.type = res_disk_geo;
576 res->disk_geo.cyls = u0;
577 res->disk_geo.heads = u1;
578 res->disk_geo.sectors = u2;
579 res->disk_geo.geotype = geo_logical;
580 }
581 }
582 free_str_list(sl0);
583 }
584
585 str_printf(&fname, 0, PROC_IDE "/%s/cache", dev_name);
586 if((sl = read_file(fname, 0, 1))) {
587 if(sscanf(sl->str, "%u", &u0) == 1 && u0) {
588 res = add_res_entry(&hd->res, new_mem(sizeof *res));
589 res->cache.type = res_cache;
590 res->cache.size = u0;
591 }
592 free_str_list(sl);
593 }
594
595 str_printf(&fname, 0, PROC_IDE "/%s/identify", dev_name);
596 if((f = fopen(fname, "r"))) {
597 u1 = 0;
598 memset(buf, sizeof buf, 0);
599 while(u1 < sizeof buf - 1 && fscanf(f, "%x", &u0) == 1) {
600 buf[u1++] = u0 >> 8; buf[u1++] = u0;
601 }
602 fclose(f);
603
604 /* ok, we now have the ATA/ATAPI ident block */
605
606 if(buf[0x14] || buf[0x15]) { /* has serial id */
607 hd->serial = canon_str(buf + 0x14, 20);
608 }
609 if(buf[0x2e] || buf[0x2f]) { /* has revision id */
610 hd->revision.name = canon_str(buf + 0x2e, 8);
611 }
612 }
613
614 free_mem(fname);
615 }
616
617 if(!size) add_disk_size(hd_data, hd);
618 }
619
620
621 /*
622 * assumes hd->drivers aleady includes scsi device drivers (like 'sd')
623 */
624 void add_scsi_sysfs_info(hd_data_t *hd_data, hd_t *hd, struct sysfs_device *sf_dev)
625 {
626 hd_t *hd1;
627 char *s, *t, *cs, *pr_str;
628 unsigned u0, u1, u2, u3;
629 int fd, k;
630 unsigned char scsi_cmd_buf[0x300];
631 struct sg_io_hdr hdr;
632 unsigned char *uc;
633 scsi_t *scsi;
634 hd_res_t *geo, *size;
635 uint64_t ul0;
636
637 if(!hd_report_this(hd_data, hd)) return;
638
639 hd->detail = new_mem(sizeof *hd->detail);
640 hd->detail->type = hd_detail_scsi;
641 hd->detail->scsi.data = scsi = new_mem(sizeof *scsi);
642
643 if(hd->sysfs_bus_id && sscanf(hd->sysfs_bus_id, "%u:%u:%u:%u", &u0, &u1, &u2, &u3) == 4) {
644 /* host:channel:id:lun */
645 hd->slot = (u0 << 8) + (u1 << 4) + u2;
646 hd->func = u3;
647 }
648
649 if((s = hd_attr_str(sysfs_get_device_attr(sf_dev, "vendor")))) {
650 cs = canon_str(s, strlen(s));
651 ADD2LOG(" vendor = %s\n", cs);
652 if(*cs) {
653 hd->vendor.name = cs;
654 }
655 else {
656 free_mem(cs);
657 }
658 }
659
660 if((s = hd_attr_str(sysfs_get_device_attr(sf_dev, "model")))) {
661 cs = canon_str(s, strlen(s));
662 ADD2LOG(" model = %s\n", cs);
663 if(*cs) {
664 hd->device.name = cs;
665 }
666 else {
667 free_mem(cs);
668 }
669
670 /* sata entries are somewhat strange... */
671 if(
672 hd->vendor.name &&
673 !strcmp(hd->vendor.name, "ATA") &&
674 hd->device.name
675 ) {
676 hd->bus.id = bus_ide;
677
678 if((cs = strchr(hd->device.name, ' '))) {
679 t = canon_str(cs, strlen(cs));
680 if(*t) {
681 *cs = 0;
682 free_mem(hd->vendor.name);
683 hd->vendor.name = hd->device.name;
684 hd->device.name = t;
685 }
686 else {
687 t = free_mem(t);
688 }
689 }
690
691 if(!strcmp(hd->vendor.name, "ATA")) {
692 hd->vendor.name = free_mem(hd->vendor.name);
693 }
694 }
695 }
696
697 if((s = hd_attr_str(sysfs_get_device_attr(sf_dev, "rev")))) {
698 cs = canon_str(s, strlen(s));
699 ADD2LOG(" rev = %s\n", cs);
700 if(*cs) {
701 hd->revision.name = cs;
702 }
703 else {
704 free_mem(cs);
705 }
706 }
707
708 if(hd_attr_uint(sysfs_get_device_attr(sf_dev, "type"), &ul0, 0)) {
709 ADD2LOG(" type = %u\n", (unsigned) ul0);
710 if(ul0 == 6 /* scanner */) {
711 hd->sub_class.id = sc_sdev_scanner;
712 }
713 else if(ul0 == 3 /* processor */ && hd->vendor.name) {
714 if(
715 !strncmp(hd->vendor.name, "HP", sizeof "HP" - 1) ||
716 !strncmp(hd->vendor.name, "EPSON", sizeof "EPSON" - 1)
717 ) {
718 hd->sub_class.id = sc_sdev_scanner;
719 }
720 }
721
722 /*
723 * typically needed for usb card readers (unused slots)
724 */
725 if(
726 hd->base_class.id == bc_storage_device &&
727 hd->sub_class.id == sc_sdev_other
728 ) {
729 switch(ul0) {
730 case 0:
731 if(search_str_list(hd->drivers, "sd")) {
732 hd->sub_class.id = sc_sdev_disk;
733 }
734 break;
735
736 case 5:
737 if(search_str_list(hd->drivers, "sr")) {
738 hd->sub_class.id = sc_sdev_cdrom;
739 }
740 break;
741 }
742 }
743
744 }
745
746 /* s390: wwpn & fcp lun */
747 if(hd_attr_uint(sysfs_get_device_attr(sf_dev, "wwpn"), &ul0, 0)) {
748 ADD2LOG(" wwpn = 0x%016"PRIx64"\n", ul0);
749 scsi->wwpn = ul0;
750
751 /* it's a bit of a hack, actually */
752 t = new_str(hd_sysfs_id(sf_dev->path));
753 if(t) {
754 if((s = strrchr(t, '/'))) *s = 0;
755 if((s = strrchr(t, '/'))) *s = 0;
756 if((s = strrchr(t, '/'))) {
757 scsi->controller_id = new_str(s + 1);
758 }
759 }
760 t = free_mem(t);
761 }
762
763 if(hd_attr_uint(sysfs_get_device_attr(sf_dev, "fcp_lun"), &ul0, 0)) {
764 ADD2LOG(" fcp_lun = 0x%016"PRIx64"\n", ul0);
765 scsi->fcp_lun = ul0;
766 }
767
768 /* ppc: get rom id */
769 if((hd1 = hd_get_device_by_idx(hd_data, hd->attached_to)) && hd1->rom_id) {
770 str_printf(&hd->rom_id, 0, "%s/@%u", hd1->rom_id, (hd->slot & 0xf));
771 }
772
773 pr_str = NULL;
774
775 if(
776 hd_report_this(hd_data, hd) &&
777 hd->unix_dev_name &&
778 hd->sub_class.id == sc_sdev_cdrom &&
779 hd_data->in_vmware != 1 /* VMWare doesn't like it */
780 ) {
781 PROGRESS(5, 0, hd->unix_dev_name);
782 fd = open(hd->unix_dev_name, O_RDONLY | O_NONBLOCK);
783 if(fd >= 0) {
784
785 str_printf(&pr_str, 0, "%s cache", hd->unix_dev_name);
786 PROGRESS(5, 1, pr_str);
787
788 memset(scsi_cmd_buf, 0, sizeof scsi_cmd_buf);
789 memset(&hdr, 0, sizeof(hdr));
790
791 hdr.interface_id = 'S';
792 hdr.cmd_len = 6;
793 hdr.dxfer_direction = SG_DXFER_FROM_DEV;
794 hdr.dxferp = scsi_cmd_buf + 8 + 6;
795 hdr.dxfer_len = 0xff;
796 hdr.cmdp = scsi_cmd_buf + 8;
797 hdr.cmdp[0] = 0x1a;
798 hdr.cmdp[2] = 0x08;
799 hdr.cmdp[4] = 0xff;
800
801 k = ioctl(fd, SG_IO, &hdr);
802
803 if(k) {
804 ADD2LOG("%s status(0x1a:8) 0x%x\n", hd->unix_dev_name, k);
805 }
806 else {
807 unsigned char *ptr = hdr.dxferp;
808
809 uc = ptr + 4 + ptr[3] + 2;
810 scsi->cache = uc[0];
811 ADD2LOG(" scsi cache: 0x%02x\n", uc[0]);
812
813 if((scsi->cache & 4)) {
814 hd->prog_if.id = pif_cdr;
815 }
816 }
817
818 close(fd);
819 }
820 }
821
822
823 if(
824 hd_report_this(hd_data, hd) &&
825 hd->unix_dev_name &&
826 hd->sub_class.id == sc_sdev_disk &&
827 !hd_probe_feature(hd_data, pr_scsi_noserial)
828 ) {
829 PROGRESS(5, 0, hd->unix_dev_name);
830 fd = open(hd->unix_dev_name, O_RDONLY | O_NONBLOCK);
831 if(fd >= 0) {
832
833 str_printf(&pr_str, 0, "%s geo", hd->unix_dev_name);
834 PROGRESS(5, 1, pr_str);
835
836 if(hd_getdisksize(hd_data, hd->unix_dev_name, fd, &geo, &size) == 1) {
837 /* (low-level) unformatted disk */
838 hd->is.notready = 1;
839 }
840
841 if(geo) add_res_entry(&hd->res, geo);
842 if(size) add_res_entry(&hd->res, size);
843
844 str_printf(&pr_str, 0, "%s serial", hd->unix_dev_name);
845 PROGRESS(5, 2, pr_str);
846
847 memset(scsi_cmd_buf, 0, sizeof scsi_cmd_buf);
848 memset(&hdr, 0, sizeof(hdr));
849
850 hdr.interface_id = 'S';
851 hdr.cmd_len = 6;
852 hdr.dxfer_direction = SG_DXFER_FROM_DEV;
853 hdr.dxferp = scsi_cmd_buf + 8 + 6;
854 hdr.dxfer_len = 0x24;
855 hdr.cmdp = scsi_cmd_buf + 8;
856 hdr.cmdp[0] = 0x12;
857 hdr.cmdp[1] = 0x01;
858 hdr.cmdp[2] = 0x80;
859 hdr.cmdp[4] = 0x24;
860
861 k = ioctl(fd, SG_IO, &hdr);
862
863 if(k) {
864 ADD2LOG("%s status(0x12) 0x%x\n", scsi->dev_name, k);
865 }
866 else {
867 unsigned char *ptr = hdr.dxferp;
868
869 ADD2LOG(" serial id len: %u\n", ptr[3]);
870
871 if((hd->serial = canon_str(ptr + 4, ptr[3]))) {
872 if(!*hd->serial) hd->serial = free_mem(hd->serial);
873 }
874 }
875
876 close(fd);
877 }
878 }
879
880 pr_str = free_mem(pr_str);
881
882
883 if(
884 hd->base_class.id == bc_storage_device &&
885 hd->sub_class.id == sc_sdev_scanner
886 ) {
887 hd->base_class.id = bc_scanner;
888 }
889
890 // ###### FIXME: usb-storage: disk vs. floppy?
891
892 }
893
894
895 void read_partitions(hd_data_t *hd_data)
896 {
897 str_list_t *sl, *sl0, *pl0 = NULL;
898 char buf[256], *s1, *name, *base;
899 char *last_base = new_str(" ");
900 char *last_name = new_str(" ");
901 int l, is_disk;
902
903 if(!(sl0 = read_file(PROC_PARTITIONS, 2, 0))) return;
904
905 if(hd_data->debug) {
906 ADD2LOG("----- "PROC_PARTITIONS" -----\n");
907 for(sl = sl0; sl; sl = sl->next) {
908 ADD2LOG(" %s", sl->str);
909 }
910 ADD2LOG("----- "PROC_PARTITIONS" end -----\n");
911 }
912
913 for(sl = sl0; sl; sl = sl->next) {
914 *buf = 0;
915 if(sscanf(sl->str, "%*s %*s %*s %255s", buf) > 0) {
916 if(*buf) add_str_list(&pl0, buf);
917 }
918 }
919
920 free_str_list(sl0);
921
922 for(is_disk = 1, sl = pl0; sl; sl = sl->next) {
923 base = sl->str;
924 l = strlen(base);
925 if(!l) continue;
926
927 s1 = base + l - 1;
928 while(isdigit(*s1) && s1 > base) s1--;
929 if(s1 == base) continue;
930
931 name = new_str(base);
932 s1[1] = 0;
933
934 if(!strcmp(last_base, base)) {
935 if(!strcmp(last_name, base)) is_disk = 0;
936 }
937 else {
938 is_disk = strncmp(last_name, base, strlen(last_name)) ? 1 : 0;
939 }
940
941 if(!search_str_list(hd_data->cdroms, name)) {
942 if(
943 strncmp(name, "loop", sizeof "loop" - 1) &&
944 (
945 hd_data->flags.list_md ||
946 (
947 strncmp(name, "md", sizeof "md" - 1) &&
948 strncmp(name, "dm-", sizeof "dm-" - 1)
949 )
950 )
951 ) {
952 add_str_list(is_disk ? &hd_data->disks : &hd_data->partitions, name);
953 }
954 }
955 free_mem(last_base);
956 free_mem(last_name);
957
958 last_base = new_str(base);
959 last_name = name; name = NULL;
960 }
961
962 free_mem(last_base);
963 free_mem(last_name);
964
965 free_str_list(pl0);
966
967 if(hd_data->debug) {
968 ADD2LOG("disks:\n");
969 for(sl = hd_data->disks; sl; sl = sl->next) ADD2LOG(" %s\n", sl->str);
970 ADD2LOG("partitions:\n");
971 for(sl = hd_data->partitions; sl; sl = sl->next) ADD2LOG(" %s\n", sl->str);
972 }
973 }
974
975
976 /*
977 * Read iso9660/el torito info, if there is a CD inserted.
978 * Returns NULL if nothing was found
979 */
980 cdrom_info_t *hd_read_cdrom_info(hd_data_t *hd_data, hd_t *hd)
981 {
982 int fd;
983 char *s;
984 cdrom_info_t *ci;
985 struct iso_primary_descriptor iso_desc;
986 unsigned char sector[0x800];
987 unsigned et;
988 unsigned u0, u1, u2;
989
990 #ifdef LIBHD_MEMCHECK
991 {
992 if(libhd_log)
993 fprintf(libhd_log, "; %s\t%p\t%p\n", __FUNCTION__, CALLED_FROM(hd_read_cdrom_info, hd_data), hd_data);
994 }
995 #endif
996
997 /* free existing entry */
998 if(hd->detail && hd->detail->type != hd_detail_cdrom) {
999 hd->detail = free_hd_detail(hd->detail);
1000 }
1001
1002 if(!hd->detail) {
1003 hd->detail = new_mem(sizeof *hd->detail);
1004 hd->detail->type = hd_detail_cdrom;
1005 hd->detail->cdrom.data = new_mem(sizeof *hd->detail->cdrom.data);
1006 }
1007
1008 ci = hd->detail->cdrom.data;
1009
1010 hd->is.notready = 0;
1011
1012 if((fd = open(hd->unix_dev_name, O_RDONLY)) < 0) {
1013 /* we are here if there is no CD in the drive */
1014 hd->is.notready = 1;
1015 return NULL;
1016 }
1017
1018 ci->iso9660.ok = 0;
1019 if(
1020 lseek(fd, 0x8000, SEEK_SET) >= 0 &&
1021 read(fd, &iso_desc, sizeof iso_desc) == sizeof iso_desc
1022 ) {
1023 ci->cdrom = 1;
1024 if(!memcmp(iso_desc.id, "CD001", 5)) {
1025 ci->iso9660.ok = 1;
1026 /* now, fill in the fields */
1027 s = canon_str(iso_desc.volume_id, sizeof iso_desc.volume_id);
1028 if(!*s) s = free_mem(s);
1029 ci->iso9660.volume = s;
1030
1031 s = canon_str(iso_desc.publisher_id, sizeof iso_desc.publisher_id);
1032 if(!*s) s = free_mem(s);
1033 ci->iso9660.publisher = s;
1034
1035 s = canon_str(iso_desc.preparer_id, sizeof iso_desc.preparer_id);
1036 if(!*s) s = free_mem(s);
1037 ci->iso9660.preparer = s;
1038
1039 s = canon_str(iso_desc.application_id, sizeof iso_desc.application_id);
1040 if(!*s) s = free_mem(s);
1041 ci->iso9660.application = s;
1042
1043 s = canon_str(iso_desc.creation_date, sizeof iso_desc.creation_date);
1044 if(!*s) s = free_mem(s);
1045 ci->iso9660.creation_date = s;
1046 }
1047 }
1048
1049 if(
1050 ci->iso9660.ok &&
1051 lseek(fd, 0x8800, SEEK_SET) >= 0 &&
1052 read(fd, &sector, sizeof sector) == sizeof sector
1053 ) {
1054 if(
1055 sector[0] == 0 && sector[6] == 1 &&
1056 !memcmp(sector + 1, "CD001", 5) &&
1057 !memcmp(sector + 7, "EL TORITO SPECIFICATION", 23)
1058 ) {
1059 et = sector[0x47] + (sector[0x48] << 8) + (sector[0x49] << 16) + (sector[0x4a] << 24);
1060 ADD2LOG(" %s: el torito boot catalog at 0x%04x\n", ci->name, et);
1061 if(
1062 lseek(fd, et * 0x800, SEEK_SET) >= 0 &&
1063 read(fd, &sector, sizeof sector) == sizeof sector &&
1064 sector[0] == 1
1065 ) {
1066 ci->el_torito.ok = 1;
1067 ci->el_torito.catalog = et;
1068 ci->el_torito.platform = sector[1];
1069 s = canon_str(sector + 4, 24);
1070 if(!*s) s = free_mem(s);
1071 ci->el_torito.id_string = s;
1072 ci->el_torito.bootable = sector[0x20] == 0x88 ? 1 : 0;
1073 ci->el_torito.media_type = sector[0x21];
1074 ADD2LOG(" media type: %u\n", ci->el_torito.media_type);
1075 ci->el_torito.load_address = (sector[0x22] + (sector[0x23] << 8)) << 4;
1076 ADD2LOG(" load address: 0x%04x\n", ci->el_torito.load_address);
1077 #if 0
1078 if(ci->el_torito.platform == 0 && ci->el_torito.load_address == 0)
1079 ci->el_torito.load_address = 0x7c00;
1080 #endif
1081 ci->el_torito.load_count = sector[0x26] + (sector[0x27] << 8);
1082 ci->el_torito.start = sector[0x28] + (sector[0x29] << 8) + (sector[0x2a] << 16) + (sector[0x2b] << 24);
1083 if(ci->el_torito.media_type >= 1 && ci->el_torito.media_type <= 3) {
1084 ci->el_torito.geo.c = 80;
1085 ci->el_torito.geo.h = 2;
1086 }
1087 switch(ci->el_torito.media_type) {
1088 case 1:
1089 ci->el_torito.geo.s = 15;
1090 break;
1091 case 2:
1092 ci->el_torito.geo.s = 18;
1093 break;
1094 case 3:
1095 ci->el_torito.geo.s = 36;
1096 break;
1097 }
1098 if(
1099 lseek(fd, ci->el_torito.start * 0x800, SEEK_SET) >= 0 &&
1100 read(fd, &sector, sizeof sector) == sizeof sector
1101 ) {
1102 if(ci->el_torito.media_type == 4) {
1103 /* ##### we should go on and read the 1st partition sector in this case... */
1104 ci->el_torito.geo.h = (unsigned) sector[0x1be + 5] + 1;
1105 ci->el_torito.geo.s = sector[0x1be + 6] & 0x3f;
1106 ci->el_torito.geo.c = sector[0x1be + 7] + (((unsigned) sector[0x1be + 6] >> 6) << 8);
1107 }
1108 if(
1109 sector[0x1fe] == 0x55 && sector[0x1ff] == 0xaa &&
1110 sector[0x0b] == 0 && sector[0x0c] == 2 &&
1111 sector[0x0e] == 1 && sector[0x0f] == 0
1112 ) {
1113 u0 = sector[0x13] + (sector[0x14] << 8); /* partition size */
1114 u1 = sector[0x18] + (sector[0x19] << 8); /* sectors per track */
1115 u2 = sector[0x1a] + (sector[0x1b] << 8); /* heads */
1116 u0 = u0 ? u0 : sector[0x20] + (sector[0x21] << 8) + (sector[0x22] << 16) + ((unsigned) sector[0x23] << 24);
1117 if(sector[0x26] == 0x29) {
1118 s = canon_str(sector + 0x2b, 11);
1119 if(!*s) s = free_mem(s);
1120 ci->el_torito.label = s;
1121 }
1122 if(!ci->el_torito.label) {
1123 s = canon_str(sector + 3, 8);
1124 if(!*s) s = free_mem(s);
1125 ci->el_torito.label = s;
1126 }
1127 if(
1128 (ci->el_torito.media_type == 0 || ci->el_torito.media_type > 3) &&
1129 u0 && u1 && u2
1130 ) {
1131 ci->el_torito.geo.h = u2;
1132 ci->el_torito.geo.s = u1;
1133 ci->el_torito.geo.size = u0;
1134 ci->el_torito.geo.c = ci->el_torito.geo.size / (u1 * u2);
1135 }
1136 }
1137 }
1138
1139 ci->el_torito.geo.size = ci->el_torito.geo.s * ci->el_torito.geo.c * ci->el_torito.geo.h;
1140 }
1141 }
1142 }
1143
1144 close(fd);
1145
1146 return ci;
1147 }
1148
1149
1150 /*
1151 * Read the list of CDROM devices known to the kernel. The info is taken
1152 * from /proc/sys/dev/cdrom/info.
1153 */
1154 void read_cdroms(hd_data_t *hd_data)
1155 {
1156 char *s, *t, *v;
1157 str_list_t *sl, *sl0;
1158 cdrom_info_t *ci;
1159 int i, line, entries = 0;
1160 unsigned val;
1161
1162 if(!(sl0 = read_file(PROC_CDROM_INFO, 2, 0))) return;
1163
1164 if((hd_data->debug & HD_DEB_CDROM)) {
1165 ADD2LOG("----- "PROC_CDROM_INFO" -----\n");
1166 for(sl = sl0; sl; sl = sl->next) {
1167 if(*sl->str != '\n') ADD2LOG("%s", sl->str);
1168 }
1169 ADD2LOG("----- "PROC_CDROM_INFO" end -----\n");
1170 }
1171
1172 for(sl = sl0; sl; sl = sl->next) {
1173 if(
1174 (line = 0, strstr(sl->str, "drive name:") == sl->str) ||
1175 (line++, strstr(sl->str, "drive speed:") == sl->str) ||
1176 (line++, strstr(sl->str, "Can write CD-R:") == sl->str) ||
1177 (line++, strstr(sl->str, "Can write CD-RW:") == sl->str) ||
1178 (line++, strstr(sl->str, "Can read DVD:") == sl->str) ||
1179 (line++, strstr(sl->str, "Can write DVD-R:") == sl->str) ||
1180 (line++, strstr(sl->str, "Can write DVD-RAM:") == sl->str)
1181 ) {
1182 s = strchr(sl->str, ':') + 1;
1183 i = 0;
1184 while((t = strsep(&s, " \t\n"))) {
1185 if(!*t) continue;
1186 i++;
1187 switch(line) {
1188 case 0: /* drive name */
1189 ci = new_cdrom_entry(&hd_data->cdrom);
1190 entries++;
1191 add_str_list(&hd_data->cdroms, t);
1192 ci->name = new_str(t);
1193 break;
1194
1195 case 1: /* drive speed */
1196 case 2: /* Can write CD-R */
1197 case 3: /* Can write CD-RW */
1198 case 4: /* Can read DVD */
1199 case 5: /* Can write DVD-R */
1200 case 6: /* Can write DVD-RAM */
1201 ci = get_cdrom_entry(hd_data->cdrom, entries - i);
1202 if(ci) {
1203 val = strtoul(t, &v, 10);
1204 if(!*v) {
1205 switch(line) {
1206 case 1:
1207 ci->speed = val;
1208 break;
1209 case 2:
1210 ci->cdr = val;
1211 break;
1212 case 3:
1213 ci->cdrw = val;
1214 break;
1215 case 4:
1216 ci->dvd = val;
1217 break;
1218 case 5:
1219 ci->dvdr = val;
1220 break;
1221 case 6:
1222 ci->dvdram = val;
1223 break;
1224 }
1225 }
1226 }
1227 break;
1228 }
1229 }
1230 }
1231 }
1232
1233 free_str_list(sl0);
1234 }
1235
1236
1237 /* add new entries at the _start_ of the list */
1238 cdrom_info_t *new_cdrom_entry(cdrom_info_t **ci)
1239 {
1240 cdrom_info_t *new_ci = new_mem(sizeof *new_ci);
1241
1242 new_ci->next = *ci;
1243 return *ci = new_ci;
1244 }
1245
1246
1247 /* return nth entry */
1248 cdrom_info_t *get_cdrom_entry(cdrom_info_t *ci, int n)
1249 {
1250 if(n < 0) return NULL;
1251
1252 while(n--) {
1253 if(!ci) return NULL;
1254 ci = ci->next;
1255 }
1256
1257 return ci;
1258 }
1259
1260
1261 /*
1262 * Add generic scsi devs.
1263 */
1264 void hd_scan_sysfs_scsi(hd_data_t *hd_data)
1265 {
1266 if(!hd_probe_feature(hd_data, pr_scsi)) return;
1267
1268 hd_data->module = mod_scsi;
1269
1270 /* some clean-up */
1271 remove_hd_entries(hd_data);
1272
1273 PROGRESS(1, 0, "scsi modules");
1274
1275 load_module(hd_data, "sg");
1276
1277 PROGRESS(2, 0, "scsi tape");
1278
1279 get_scsi_tape(hd_data);
1280
1281 PROGRESS(3, 0, "scsi generic");
1282
1283 get_generic_scsi_devs(hd_data);
1284 }
1285
1286
1287 void get_scsi_tape(hd_data_t *hd_data)
1288 {
1289 char *s, *t;
1290 unsigned u1, u2, u3;
1291 uint64_t ul0;
1292 hd_t *hd, *hd1;
1293 hd_dev_num_t dev_num;
1294
1295 struct sysfs_class *sf_class;
1296 struct sysfs_class_device *sf_cdev;
1297 struct sysfs_device *sf_dev;
1298 struct dlist *sf_cdev_list;
1299
1300 sf_class = sysfs_open_class("scsi_tape");
1301
1302 if(!sf_class) {
1303 ADD2LOG("sysfs: no such class: scsi_tape\n");
1304 return;
1305 }
1306
1307 sf_cdev_list = sysfs_get_class_devices(sf_class);
1308 if(sf_cdev_list) dlist_for_each_data(sf_cdev_list, sf_cdev, struct sysfs_class_device) {
1309 ADD2LOG(
1310 " scsi tape: name = %s, path = %s\n",
1311 sf_cdev->name,
1312 hd_sysfs_id(sf_cdev->path)
1313 );
1314
1315 memset(&dev_num, 0, sizeof dev_num);
1316
1317 if((s = hd_attr_str(sysfs_get_classdev_attr(sf_cdev, "dev")))) {
1318 if(sscanf(s, "%u:%u", &u1, &u2) == 2) {
1319 dev_num.type = 'c';
1320 dev_num.major = u1;
1321 dev_num.minor = u2;
1322 dev_num.range = 1;
1323 }
1324 ADD2LOG(" dev = %u:%u\n", u1, u2);
1325 }
1326
1327 if(hd_attr_uint(sysfs_get_classdev_attr(sf_cdev, "range"), &ul0, 0)) {
1328 dev_num.range = ul0;
1329 ADD2LOG(" range = %u\n", dev_num.range);
1330 }
1331
1332 sf_dev = sysfs_get_classdev_device(sf_cdev);
1333 if(sf_dev) {
1334 s = hd_sysfs_id(sf_dev->path);
1335 ADD2LOG(
1336 " scsi device: bus = %s, bus_id = %s driver = %s\n path = %s\n",
1337 sf_dev->bus,
1338 sf_dev->bus_id,
1339 sf_dev->driver_name,
1340 s
1341 );
1342
1343 for(hd = hd_data->hd; hd; hd = hd->next) {
1344 if(
1345 hd->module == hd_data->module &&
1346 hd->sysfs_device_link &&
1347 hd->base_class.id == bc_storage_device &&
1348 hd->sub_class.id == sc_sdev_tape &&
1349 s &&
1350 !strcmp(hd->sysfs_device_link, s)
1351 ) break;
1352 }
1353
1354 if(!hd) {
1355 hd = add_hd_entry(hd_data, __LINE__, 0);
1356 hd->base_class.id = bc_storage_device;
1357 hd->sub_class.id = sc_sdev_tape;
1358
1359 hd->bus.id = bus_scsi;
1360
1361 hd->sysfs_device_link = new_str(s);
1362
1363 hd->sysfs_bus_id = new_str(sf_dev->bus_id);
1364
1365 /* parent has longest matching sysfs id */
1366 u2 = strlen(s);
1367 for(u3 = 0, hd1 = hd_data->hd; hd1; hd1 = hd1->next) {
1368 if(hd1->sysfs_id) {
1369 u1 = strlen(hd1->sysfs_id);
1370 if(u1 > u3 && u1 <= u2 && !strncmp(s, hd1->sysfs_id, u1)) {
1371 u3 = u1;
1372 hd->attached_to = hd1->idx;
1373 }
1374 }
1375 }
1376
1377 /* find longest matching sysfs id we have a driver for */
1378 s = new_str(s);
1379 t = strrchr(s, '/');
1380 if(t) *t = 0;
1381 t = hd_sysfs_find_driver(hd_data, s, 0);
1382 if(t) {
1383 add_str_list(&hd->drivers, t);
1384 }
1385 s = free_mem(s);
1386
1387 if(
1388 sf_dev->driver_name &&
1389 *sf_dev->driver_name &&
1390 strcmp(sf_dev->driver_name, "unknown")
1391 ) {
1392 add_str_list(&hd->drivers, sf_dev->driver_name);
1393 }
1394
1395 add_scsi_sysfs_info(hd_data, hd, sf_dev);
1396 }
1397
1398 s = hd_sysfs_name2_dev(sf_cdev->name);
1399
1400 if(!hd->unix_dev_name || strlen(s) + sizeof "/dev/" - 1 < strlen(hd->unix_dev_name)) {
1401 str_printf(&hd->unix_dev_name, 0, "/dev/%s", s);
1402 hd->unix_dev_num = dev_num;
1403 free_mem(hd->sysfs_id);
1404 hd->sysfs_id = new_str(hd_sysfs_id(sf_cdev->path));
1405 }
1406 }
1407 }
1408
1409 sysfs_close_class(sf_class);
1410 }
1411
1412
1413 void get_generic_scsi_devs(hd_data_t *hd_data)
1414 {
1415 char *s, *t;
1416 unsigned u1, u2, u3;
1417 uint64_t ul0;
1418 hd_t *hd, *hd1;
1419 hd_dev_num_t dev_num;
1420
1421 struct sysfs_class *sf_class;
1422 struct sysfs_class_device *sf_cdev;
1423 struct sysfs_device *sf_dev;
1424 struct dlist *sf_cdev_list;
1425
1426 sf_class = sysfs_open_class("scsi_generic");
1427
1428 if(!sf_class) {
1429 ADD2LOG("sysfs: no such class: scsi_generic\n");
1430 return;
1431 }
1432
1433 sf_cdev_list = sysfs_get_class_devices(sf_class);
1434 if(sf_cdev_list) dlist_for_each_data(sf_cdev_list, sf_cdev, struct sysfs_class_device) {
1435 ADD2LOG(
1436 " scsi: name = %s, path = %s\n",
1437 sf_cdev->name,
1438 hd_sysfs_id(sf_cdev->path)
1439 );
1440
1441 memset(&dev_num, 0, sizeof dev_num);
1442
1443 if((s = hd_attr_str(sysfs_get_classdev_attr(sf_cdev, "dev")))) {
1444 if(sscanf(s, "%u:%u", &u1, &u2) == 2) {
1445 dev_num.type = 'c';
1446 dev_num.major = u1;
1447 dev_num.minor = u2;
1448 dev_num.range = 1;
1449 }
1450 ADD2LOG(" dev = %u:%u\n", u1, u2);
1451 }
1452
1453 if(hd_attr_uint(sysfs_get_classdev_attr(sf_cdev, "range"), &ul0, 0)) {
1454 dev_num.range = ul0;
1455 ADD2LOG(" range = %u\n", dev_num.range);
1456 }
1457
1458 sf_dev = sysfs_get_classdev_device(sf_cdev);
1459 if(sf_dev) {
1460 s = hd_sysfs_id(sf_dev->path);
1461
1462 ADD2LOG(
1463 " scsi device: bus = %s, bus_id = %s driver = %s\n path = %s\n",
1464 sf_dev->bus,
1465 sf_dev->bus_id,
1466 sf_dev->driver_name,
1467 s
1468 );
1469 }
1470
1471 for(hd = hd_data->hd; hd; hd = hd->next) {
1472 if(
1473 hd->sysfs_device_link &&
1474 hd->bus.id == bus_scsi &&
1475 s &&
1476 !strcmp(hd->sysfs_device_link, s)
1477 ) break;
1478 }
1479
1480 if(hd) {
1481 if(!hd->unix_dev_name2) {
1482 str_printf(&hd->unix_dev_name2, 0, "/dev/%s", hd_sysfs_name2_dev(sf_cdev->name));
1483 hd->unix_dev_num2 = dev_num;
1484 }
1485 }
1486
1487 hd = NULL;
1488
1489 if(
1490 sf_dev &&
1491 sf_dev->driver_name &&
1492 !strcmp(sf_dev->driver_name, "unknown")
1493 ) {
1494 hd = add_hd_entry(hd_data, __LINE__, 0);
1495 hd->base_class.id = bc_storage_device;
1496 hd->sub_class.id = sc_sdev_other;
1497
1498 str_printf(&hd->unix_dev_name, 0, "/dev/%s", hd_sysfs_name2_dev(sf_cdev->name));
1499
1500 hd->bus.id = bus_scsi;
1501
1502 hd->sysfs_id = new_str(hd_sysfs_id(sf_cdev->path));
1503
1504 hd->unix_dev_num = dev_num;
1505
1506 if(sf_dev) hd->sysfs_bus_id = new_str(sf_dev->bus_id);
1507
1508 if(sf_dev && (s = hd_sysfs_id(sf_dev->path))) {
1509
1510 /* parent has longest matching sysfs id */
1511 u2 = strlen(s);
1512 for(u3 = 0, hd1 = hd_data->hd; hd1; hd1 = hd1->next) {
1513 if(hd1->sysfs_id) {
1514 u1 = strlen(hd1->sysfs_id);
1515 if(u1 > u3 && u1 <= u2 && !strncmp(s, hd1->sysfs_id, u1)) {
1516 u3 = u1;
1517 hd->attached_to = hd1->idx;
1518 }
1519 }
1520 }
1521
1522 /* find longest matching sysfs id we have a driver for */
1523 s = new_str(s);
1524 t = strrchr(s, '/');
1525 if(t) *t = 0;
1526 t = hd_sysfs_find_driver(hd_data, s, 0);
1527 if(t) {
1528 add_str_list(&hd->drivers, t);
1529 }
1530 s = free_mem(s);
1531
1532 }
1533
1534 add_scsi_sysfs_info(hd_data, hd, sf_dev);
1535
1536 }
1537
1538 }
1539
1540 sysfs_close_class(sf_class);
1541 }
1542
1543
1544 void add_disk_size(hd_data_t *hd_data, hd_t *hd)
1545 {
1546 hd_res_t *geo, *size;
1547 int fd;
1548 char *pr_str;
1549
1550 pr_str = NULL;
1551
1552 if(
1553 hd->unix_dev_name &&
1554 hd->sub_class.id == sc_sdev_disk
1555 ) {
1556 PROGRESS(5, 0, hd->unix_dev_name);
1557 fd = open(hd->unix_dev_name, O_RDONLY | O_NONBLOCK);
1558 if(fd >= 0) {
1559
1560 str_printf(&pr_str, 0, "%s geo", hd->unix_dev_name);
1561 PROGRESS(5, 1, pr_str);
1562
1563 if(hd_getdisksize(hd_data, hd->unix_dev_name, fd, &geo, &size) == 1) {
1564 /* (low-level) unformatted disk */
1565 hd->is.notready = 1;
1566 }
1567
1568 if(geo) add_res_entry(&hd->res, geo);
1569 if(size) add_res_entry(&hd->res, size);
1570
1571 close(fd);
1572 }
1573 }
1574
1575 pr_str = free_mem(pr_str);
1576 }
1577
1578