2 * Intel(R) Matrix Storage Manager hardware and firmware support routines
4 * Copyright (C) 2008 Intel Corporation
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * You should have received a copy of the GNU General Public License along with
16 * this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
20 #include "platform-intel.h"
21 #include "probe_roms.h"
29 #include <sys/types.h>
33 static int devpath_to_ll(const char *dev_path
, const char *entry
,
34 unsigned long long *val
);
36 static __u16
devpath_to_vendor(const char *dev_path
);
38 static void free_sys_dev(struct sys_dev
**list
)
41 struct sys_dev
*next
= (*list
)->next
;
50 struct sys_dev
*find_driver_devices(const char *bus
, const char *driver
)
52 /* search sysfs for devices driven by 'driver' */
58 struct sys_dev
*head
= NULL
;
59 struct sys_dev
*list
= NULL
;
60 enum sys_dev_type type
;
61 unsigned long long dev_id
;
63 if (strcmp(driver
, "isci") == 0)
65 else if (strcmp(driver
, "ahci") == 0)
68 type
= SYS_DEV_UNKNOWN
;
70 sprintf(path
, "/sys/bus/%s/drivers/%s", bus
, driver
);
71 driver_dir
= opendir(path
);
74 for (de
= readdir(driver_dir
); de
; de
= readdir(driver_dir
)) {
77 /* is 'de' a device? check that the 'subsystem' link exists and
78 * that its target matches 'bus'
80 sprintf(path
, "/sys/bus/%s/drivers/%s/%s/subsystem",
81 bus
, driver
, de
->d_name
);
82 n
= readlink(path
, link
, sizeof(link
));
83 if (n
< 0 || n
>= (int)sizeof(link
))
86 c
= strrchr(link
, '/');
89 if (strncmp(bus
, c
+1, strlen(bus
)) != 0)
92 sprintf(path
, "/sys/bus/%s/drivers/%s/%s",
93 bus
, driver
, de
->d_name
);
95 /* if it's not Intel device skip it. */
96 if (devpath_to_vendor(path
) != 0x8086)
99 if (devpath_to_ll(path
, "device", &dev_id
) != 0)
102 /* start / add list entry */
104 head
= xmalloc(sizeof(*head
));
107 list
->next
= xmalloc(sizeof(*head
));
116 list
->dev_id
= (__u16
) dev_id
;
118 list
->path
= realpath(path
, NULL
);
120 if ((list
->pci_id
= strrchr(list
->path
, '/')) != NULL
)
123 closedir(driver_dir
);
127 static struct sys_dev
*intel_devices
=NULL
;
128 static time_t valid_time
= 0;
130 static enum sys_dev_type
device_type_by_id(__u16 device_id
)
132 struct sys_dev
*iter
;
134 for(iter
= intel_devices
; iter
!= NULL
; iter
= iter
->next
)
135 if (iter
->dev_id
== device_id
)
137 return SYS_DEV_UNKNOWN
;
140 static int devpath_to_ll(const char *dev_path
, const char *entry
, unsigned long long *val
)
142 char path
[strlen(dev_path
) + strlen(entry
) + 2];
146 sprintf(path
, "%s/%s", dev_path
, entry
);
148 fd
= open(path
, O_RDONLY
);
151 n
= sysfs_fd_get_ll(fd
, val
);
156 static __u16
devpath_to_vendor(const char *dev_path
)
158 char path
[strlen(dev_path
) + strlen("/vendor") + 1];
164 sprintf(path
, "%s/vendor", dev_path
);
166 fd
= open(path
, O_RDONLY
);
170 n
= read(fd
, vendor
, sizeof(vendor
));
171 if (n
== sizeof(vendor
)) {
172 vendor
[n
- 1] = '\0';
173 id
= strtoul(vendor
, NULL
, 16);
180 struct sys_dev
*find_intel_devices(void)
182 struct sys_dev
*ahci
, *isci
;
184 if (valid_time
> time(0) - 10)
185 return intel_devices
;
188 free_sys_dev(&intel_devices
);
190 isci
= find_driver_devices("pci", "isci");
191 ahci
= find_driver_devices("pci", "ahci");
196 struct sys_dev
*elem
= ahci
;
201 intel_devices
= ahci
;
202 valid_time
= time(0);
203 return intel_devices
;
207 * PCI Expansion ROM Data Structure Format */
208 struct pciExpDataStructFormat
{
212 } __attribute__ ((packed
));
214 static struct imsm_orom imsm_orom
[SYS_DEV_MAX
];
215 static int populated_orom
[SYS_DEV_MAX
];
217 static int scan(const void *start
, const void *end
, const void *data
)
220 const struct imsm_orom
*imsm_mem
;
222 int len
= (end
- start
);
223 struct pciExpDataStructFormat
*ptr
= (struct pciExpDataStructFormat
*)data
;
225 if (data
+ 0x18 > end
) {
226 dprintf("cannot find pciExpDataStruct \n");
230 dprintf("ptr->vendorID: %lx __le16_to_cpu(ptr->deviceID): %lx \n",
231 (ulong
) __le16_to_cpu(ptr
->vendorID
),
232 (ulong
) __le16_to_cpu(ptr
->deviceID
));
234 if (__le16_to_cpu(ptr
->vendorID
) == 0x8086) {
235 /* serach attached intel devices by device id from OROM */
236 dev
= device_type_by_id(__le16_to_cpu(ptr
->deviceID
));
237 if (dev
== SYS_DEV_UNKNOWN
)
243 for (offset
= 0; offset
< len
; offset
+= 4) {
244 imsm_mem
= start
+ offset
;
245 if ((memcmp(imsm_mem
->signature
, "$VER", 4) == 0)) {
246 imsm_orom
[dev
] = *imsm_mem
;
247 populated_orom
[dev
] = 1;
248 return populated_orom
[SYS_DEV_SATA
] && populated_orom
[SYS_DEV_SAS
];
254 const struct imsm_orom
*imsm_platform_test(enum sys_dev_type hba_id
, int *populated
,
255 struct imsm_orom
*imsm_orom
)
257 memset(imsm_orom
, 0, sizeof(*imsm_orom
));
258 imsm_orom
->rlc
= IMSM_OROM_RLC_RAID0
| IMSM_OROM_RLC_RAID1
|
259 IMSM_OROM_RLC_RAID10
| IMSM_OROM_RLC_RAID5
;
260 imsm_orom
->sss
= IMSM_OROM_SSS_4kB
| IMSM_OROM_SSS_8kB
|
261 IMSM_OROM_SSS_16kB
| IMSM_OROM_SSS_32kB
|
262 IMSM_OROM_SSS_64kB
| IMSM_OROM_SSS_128kB
|
263 IMSM_OROM_SSS_256kB
| IMSM_OROM_SSS_512kB
|
264 IMSM_OROM_SSS_1MB
| IMSM_OROM_SSS_2MB
;
265 imsm_orom
->dpa
= IMSM_OROM_DISKS_PER_ARRAY
;
266 imsm_orom
->tds
= IMSM_OROM_TOTAL_DISKS
;
267 imsm_orom
->vpa
= IMSM_OROM_VOLUMES_PER_ARRAY
;
268 imsm_orom
->vphba
= IMSM_OROM_VOLUMES_PER_HBA
;
269 imsm_orom
->attr
= imsm_orom
->rlc
| IMSM_OROM_ATTR_ChecksumVerify
;
272 if (check_env("IMSM_TEST_OROM_NORAID5")) {
273 imsm_orom
->rlc
= IMSM_OROM_RLC_RAID0
| IMSM_OROM_RLC_RAID1
|
274 IMSM_OROM_RLC_RAID10
;
276 if (check_env("IMSM_TEST_AHCI_EFI_NORAID5") && (hba_id
== SYS_DEV_SAS
)) {
277 imsm_orom
->rlc
= IMSM_OROM_RLC_RAID0
| IMSM_OROM_RLC_RAID1
|
278 IMSM_OROM_RLC_RAID10
;
280 if (check_env("IMSM_TEST_SCU_EFI_NORAID5") && (hba_id
== SYS_DEV_SATA
)) {
281 imsm_orom
->rlc
= IMSM_OROM_RLC_RAID0
| IMSM_OROM_RLC_RAID1
|
282 IMSM_OROM_RLC_RAID10
;
288 static const struct imsm_orom
*find_imsm_hba_orom(enum sys_dev_type hba_id
)
292 if (hba_id
>= SYS_DEV_MAX
)
295 /* it's static data so we only need to read it once */
296 if (populated_orom
[hba_id
]) {
297 dprintf("OROM CAP: %p, pid: %d pop: %d\n",
298 &imsm_orom
[hba_id
], (int) getpid(), populated_orom
[hba_id
]);
299 return &imsm_orom
[hba_id
];
301 if (check_env("IMSM_TEST_OROM")) {
302 dprintf("OROM CAP: %p, pid: %d pop: %d\n",
303 &imsm_orom
[hba_id
], (int) getpid(), populated_orom
[hba_id
]);
304 return imsm_platform_test(hba_id
, &populated_orom
[hba_id
], &imsm_orom
[hba_id
]);
306 /* return empty OROM capabilities in EFI test mode */
307 if (check_env("IMSM_TEST_AHCI_EFI") ||
308 check_env("IMSM_TEST_SCU_EFI"))
311 find_intel_devices();
313 if (intel_devices
== NULL
)
316 /* scan option-rom memory looking for an imsm signature */
317 if (check_env("IMSM_SAFE_OROM_SCAN"))
321 if (probe_roms_init(align
) != 0)
324 /* ignore return value - True is returned if both adapater roms are found */
325 scan_adapter_roms(scan
);
328 if (populated_orom
[hba_id
])
329 return &imsm_orom
[hba_id
];
333 #define GUID_STR_MAX 37 /* according to GUID format:
334 * xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" */
336 #define EFI_GUID(a, b, c, d0, d1, d2, d3, d4, d5, d6, d7) \
338 {{ (a) & 0xff, ((a) >> 8) & 0xff, ((a) >> 16) & 0xff, ((a) >> 24) & 0xff, \
339 (b) & 0xff, ((b) >> 8) & 0xff, \
340 (c) & 0xff, ((c) >> 8) & 0xff, \
341 (d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7) }})
343 #define SYS_EFI_VAR_PATH "/sys/firmware/efi/vars"
344 #define SCU_PROP "RstScuV"
345 #define AHCI_PROP "RstSataV"
347 #define VENDOR_GUID \
348 EFI_GUID(0x193dfefa, 0xa445, 0x4302, 0x99, 0xd8, 0xef, 0x3a, 0xad, 0x1a, 0x04, 0xc6)
350 int populated_efi
[SYS_DEV_MAX
] = { 0, 0 };
352 static struct imsm_orom imsm_efi
[SYS_DEV_MAX
];
354 int read_efi_variable(void *buffer
, ssize_t buf_size
, char *variable_name
, struct efi_guid guid
)
357 char buf
[GUID_STR_MAX
];
359 ssize_t n
, var_data_len
;
361 snprintf(path
, PATH_MAX
, "%s/%s-%s/size", SYS_EFI_VAR_PATH
, variable_name
, guid_str(buf
, guid
));
363 dprintf("EFI VAR: path=%s\n", path
);
364 /* get size of variable data */
365 dfd
= open(path
, O_RDONLY
);
369 n
= read(dfd
, &buf
, sizeof(buf
));
376 var_data_len
= strtoul(buf
, NULL
, 16);
377 if ((errno
== ERANGE
&& (var_data_len
== LONG_MAX
))
378 || (errno
!= 0 && var_data_len
== 0))
382 snprintf(path
, PATH_MAX
, "%s/%s-%s/data", SYS_EFI_VAR_PATH
, variable_name
, guid_str(buf
, guid
));
384 dprintf("EFI VAR: path=%s\n", path
);
385 dfd
= open(path
, O_RDONLY
);
389 n
= read(dfd
, buffer
, buf_size
);
391 if (n
!= var_data_len
|| n
< buf_size
) {
398 const struct imsm_orom
*find_imsm_efi(enum sys_dev_type hba_id
)
400 if (hba_id
>= SYS_DEV_MAX
)
403 dprintf("EFI CAP: %p, pid: %d pop: %d\n",
404 &imsm_efi
[hba_id
], (int) getpid(), populated_efi
[hba_id
]);
406 /* it's static data so we only need to read it once */
407 if (populated_efi
[hba_id
]) {
408 dprintf("EFI CAP: %p, pid: %d pop: %d\n",
409 &imsm_efi
[hba_id
], (int) getpid(), populated_efi
[hba_id
]);
410 return &imsm_efi
[hba_id
];
412 if (check_env("IMSM_TEST_AHCI_EFI") ||
413 check_env("IMSM_TEST_SCU_EFI")) {
414 dprintf("OROM CAP: %p, pid: %d pop: %d\n",
415 &imsm_efi
[hba_id
], (int) getpid(), populated_efi
[hba_id
]);
416 return imsm_platform_test(hba_id
, &populated_efi
[hba_id
], &imsm_efi
[hba_id
]);
418 /* OROM test is set, return that there is no EFI capabilities */
419 if (check_env("IMSM_TEST_OROM"))
422 if (read_efi_variable(&imsm_efi
[hba_id
], sizeof(imsm_efi
[0]), hba_id
== SYS_DEV_SAS
? SCU_PROP
: AHCI_PROP
, VENDOR_GUID
)) {
423 populated_efi
[hba_id
] = 0;
427 populated_efi
[hba_id
] = 1;
428 return &imsm_efi
[hba_id
];
432 * backward interface compatibility
434 const struct imsm_orom
*find_imsm_orom(void)
436 return find_imsm_hba_orom(SYS_DEV_SATA
);
439 const struct imsm_orom
*find_imsm_capability(enum sys_dev_type hba_id
)
441 const struct imsm_orom
*cap
=NULL
;
443 if ((cap
= find_imsm_efi(hba_id
)) != NULL
)
445 if ((cap
= find_imsm_hba_orom(hba_id
)) != NULL
)
450 char *devt_to_devpath(dev_t dev
)
454 sprintf(device
, "/sys/dev/block/%d:%d/device", major(dev
), minor(dev
));
455 return realpath(device
, NULL
);
458 char *diskfd_to_devpath(int fd
)
460 /* return the device path for a disk, return NULL on error or fd
461 * refers to a partition
465 if (fstat(fd
, &st
) != 0)
467 if (!S_ISBLK(st
.st_mode
))
470 return devt_to_devpath(st
.st_rdev
);
473 int path_attached_to_hba(const char *disk_path
, const char *hba_path
)
477 if (check_env("IMSM_TEST_AHCI_DEV") ||
478 check_env("IMSM_TEST_SCU_DEV")) {
482 if (!disk_path
|| !hba_path
)
484 dprintf("hba: %s - disk: %s\n", hba_path
, disk_path
);
485 if (strncmp(disk_path
, hba_path
, strlen(hba_path
)) == 0)
493 int devt_attached_to_hba(dev_t dev
, const char *hba_path
)
495 char *disk_path
= devt_to_devpath(dev
);
496 int rc
= path_attached_to_hba(disk_path
, hba_path
);
504 int disk_attached_to_hba(int fd
, const char *hba_path
)
506 char *disk_path
= diskfd_to_devpath(fd
);
507 int rc
= path_attached_to_hba(disk_path
, hba_path
);