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>
34 static __u16
devpath_to_vendor(const char *dev_path
);
36 void free_sys_dev(struct sys_dev
**list
)
39 struct sys_dev
*next
= (*list
)->next
;
48 struct sys_dev
*find_driver_devices(const char *bus
, const char *driver
)
50 /* search sysfs for devices driven by 'driver' */
56 struct sys_dev
*head
= NULL
;
57 struct sys_dev
*list
= NULL
;
58 enum sys_dev_type type
;
60 if (strcmp(driver
, "isci") == 0)
62 else if (strcmp(driver
, "ahci") == 0)
65 type
= SYS_DEV_UNKNOWN
;
67 sprintf(path
, "/sys/bus/%s/drivers/%s", bus
, driver
);
68 driver_dir
= opendir(path
);
71 for (de
= readdir(driver_dir
); de
; de
= readdir(driver_dir
)) {
74 /* is 'de' a device? check that the 'subsystem' link exists and
75 * that its target matches 'bus'
77 sprintf(path
, "/sys/bus/%s/drivers/%s/%s/subsystem",
78 bus
, driver
, de
->d_name
);
79 n
= readlink(path
, link
, sizeof(link
));
80 if (n
< 0 || n
>= (int)sizeof(link
))
83 c
= strrchr(link
, '/');
86 if (strncmp(bus
, c
+1, strlen(bus
)) != 0)
89 sprintf(path
, "/sys/bus/%s/drivers/%s/%s",
90 bus
, driver
, de
->d_name
);
92 /* if it's not Intel device skip it. */
93 if (devpath_to_vendor(path
) != 0x8086)
96 /* start / add list entry */
98 head
= malloc(sizeof(*head
));
101 list
->next
= malloc(sizeof(*head
));
111 list
->path
= canonicalize_file_name(path
);
113 if ((list
->pci_id
= strrchr(list
->path
, '/')) != NULL
)
116 closedir(driver_dir
);
121 static __u16
devpath_to_vendor(const char *dev_path
)
123 char path
[strlen(dev_path
) + strlen("/vendor") + 1];
129 sprintf(path
, "%s/vendor", dev_path
);
131 fd
= open(path
, O_RDONLY
);
135 n
= read(fd
, vendor
, sizeof(vendor
));
136 if (n
== sizeof(vendor
)) {
137 vendor
[n
- 1] = '\0';
138 id
= strtoul(vendor
, NULL
, 16);
145 struct sys_dev
*find_intel_devices(void)
147 struct sys_dev
*ahci
, *isci
;
149 isci
= find_driver_devices("pci", "isci");
150 ahci
= find_driver_devices("pci", "ahci");
155 struct sys_dev
*elem
= ahci
;
163 static int platform_has_intel_devices(void)
165 struct sys_dev
*devices
;
166 devices
= find_intel_devices();
168 free_sys_dev(&devices
);
175 * PCI Expansion ROM Data Structure Format */
176 struct pciExpDataStructFormat
{
180 } __attribute__ ((packed
));
182 static struct imsm_orom imsm_orom
[SYS_DEV_MAX
];
183 static int populated_orom
[SYS_DEV_MAX
];
185 static int scan(const void *start
, const void *end
, const void *data
)
188 const struct imsm_orom
*imsm_mem
;
190 int len
= (end
- start
);
191 struct pciExpDataStructFormat
*ptr
= (struct pciExpDataStructFormat
*)data
;
193 dprintf("ptr->vendorID: %lx __le16_to_cpu(ptr->deviceID): %lx \n",
194 (ulong
) __le16_to_cpu(ptr
->vendorID
),
195 (ulong
) __le16_to_cpu(ptr
->deviceID
));
197 if ((__le16_to_cpu(ptr
->vendorID
) == 0x8086) &&
198 (__le16_to_cpu(ptr
->deviceID
) == 0x2822))
200 else if ((__le16_to_cpu(ptr
->vendorID
) == 0x8086) &&
201 (__le16_to_cpu(ptr
->deviceID
) == 0x1D60))
206 for (offset
= 0; offset
< len
; offset
+= 4) {
207 imsm_mem
= start
+ offset
;
208 if (memcmp(imsm_mem
->signature
, "$VER", 4) == 0) {
209 imsm_orom
[dev
] = *imsm_mem
;
210 populated_orom
[dev
] = 1;
211 return populated_orom
[SYS_DEV_SATA
] && populated_orom
[SYS_DEV_SAS
];
218 const struct imsm_orom
*imsm_platform_test(enum sys_dev_type hba_id
, int *populated
,
219 struct imsm_orom
*imsm_orom
)
221 memset(imsm_orom
, 0, sizeof(*imsm_orom
));
222 imsm_orom
->rlc
= IMSM_OROM_RLC_RAID0
| IMSM_OROM_RLC_RAID1
|
223 IMSM_OROM_RLC_RAID10
| IMSM_OROM_RLC_RAID5
;
224 imsm_orom
->sss
= IMSM_OROM_SSS_4kB
| IMSM_OROM_SSS_8kB
|
225 IMSM_OROM_SSS_16kB
| IMSM_OROM_SSS_32kB
|
226 IMSM_OROM_SSS_64kB
| IMSM_OROM_SSS_128kB
|
227 IMSM_OROM_SSS_256kB
| IMSM_OROM_SSS_512kB
|
228 IMSM_OROM_SSS_1MB
| IMSM_OROM_SSS_2MB
;
229 imsm_orom
->dpa
= IMSM_OROM_DISKS_PER_ARRAY
;
230 imsm_orom
->tds
= IMSM_OROM_TOTAL_DISKS
;
231 imsm_orom
->vpa
= IMSM_OROM_VOLUMES_PER_ARRAY
;
232 imsm_orom
->vphba
= IMSM_OROM_VOLUMES_PER_HBA
;
233 imsm_orom
->attr
= imsm_orom
->rlc
| IMSM_OROM_ATTR_ChecksumVerify
;
236 if (check_env("IMSM_TEST_OROM_NORAID5")) {
237 imsm_orom
->rlc
= IMSM_OROM_RLC_RAID0
| IMSM_OROM_RLC_RAID1
|
238 IMSM_OROM_RLC_RAID10
;
240 if (check_env("IMSM_TEST_AHCI_EFI_NORAID5") && (hba_id
== SYS_DEV_SAS
)) {
241 imsm_orom
->rlc
= IMSM_OROM_RLC_RAID0
| IMSM_OROM_RLC_RAID1
|
242 IMSM_OROM_RLC_RAID10
;
244 if (check_env("IMSM_TEST_SCU_EFI_NORAID5") && (hba_id
== SYS_DEV_SATA
)) {
245 imsm_orom
->rlc
= IMSM_OROM_RLC_RAID0
| IMSM_OROM_RLC_RAID1
|
246 IMSM_OROM_RLC_RAID10
;
254 static const struct imsm_orom
*find_imsm_hba_orom(enum sys_dev_type hba_id
)
258 if (hba_id
>= SYS_DEV_MAX
)
261 /* it's static data so we only need to read it once */
262 if (populated_orom
[hba_id
]) {
263 dprintf("OROM CAP: %p, pid: %d pop: %d\n",
264 &imsm_orom
[hba_id
], (int) getpid(), populated_orom
[hba_id
]);
265 return &imsm_orom
[hba_id
];
267 if (check_env("IMSM_TEST_OROM")) {
268 dprintf("OROM CAP: %p, pid: %d pop: %d\n",
269 &imsm_orom
[hba_id
], (int) getpid(), populated_orom
[hba_id
]);
270 return imsm_platform_test(hba_id
, &populated_orom
[hba_id
], &imsm_orom
[hba_id
]);
272 /* return empty OROM capabilities in EFI test mode */
273 if (check_env("IMSM_TEST_AHCI_EFI") ||
274 check_env("IMSM_TEST_SCU_EFI"))
277 if (!platform_has_intel_devices())
280 /* scan option-rom memory looking for an imsm signature */
281 if (check_env("IMSM_SAFE_OROM_SCAN"))
285 if (probe_roms_init(align
) != 0)
288 /* ignore result - True is returned if both are found */
289 scan_adapter_roms(scan
);
292 if (populated_orom
[hba_id
])
293 return &imsm_orom
[hba_id
];
297 #define GUID_STR_MAX 37 /* according to GUID format:
298 * xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" */
300 #define EFI_GUID(a, b, c, d0, d1, d2, d3, d4, d5, d6, d7) \
302 {{ (a) & 0xff, ((a) >> 8) & 0xff, ((a) >> 16) & 0xff, ((a) >> 24) & 0xff, \
303 (b) & 0xff, ((b) >> 8) & 0xff, \
304 (c) & 0xff, ((c) >> 8) & 0xff, \
305 (d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7) }})
308 #define SYS_EFI_VAR_PATH "/sys/firmware/efi/vars"
309 #define SCU_PROP "RstScuV"
310 #define AHCI_PROP "RstSataV"
312 #define VENDOR_GUID \
313 EFI_GUID(0x193dfefa, 0xa445, 0x4302, 0x99, 0xd8, 0xef, 0x3a, 0xad, 0x1a, 0x04, 0xc6)
315 int populated_efi
[SYS_DEV_MAX
] = { 0, 0 };
317 static struct imsm_orom imsm_efi
[SYS_DEV_MAX
];
319 const struct imsm_orom
*find_imsm_efi(enum sys_dev_type hba_id
)
323 char buf
[GUID_STR_MAX
];
326 if (hba_id
>= SYS_DEV_MAX
)
329 dprintf("EFI CAP: %p, pid: %d pop: %d\n",
330 &imsm_efi
[hba_id
], (int) getpid(), populated_efi
[hba_id
]);
332 /* it's static data so we only need to read it once */
333 if (populated_efi
[hba_id
]) {
334 dprintf("EFI CAP: %p, pid: %d pop: %d\n",
335 &imsm_efi
[hba_id
], (int) getpid(), populated_efi
[hba_id
]);
336 return &imsm_efi
[hba_id
];
338 if (check_env("IMSM_TEST_AHCI_EFI") ||
339 check_env("IMSM_TEST_SCU_EFI")) {
340 dprintf("OROM CAP: %p, pid: %d pop: %d\n",
341 &imsm_efi
[hba_id
], (int) getpid(), populated_efi
[hba_id
]);
342 return imsm_platform_test(hba_id
, &populated_efi
[hba_id
], &imsm_efi
[hba_id
]);
344 /* OROM test is set, return that there is no EFI capabilities */
345 if (check_env("IMSM_TEST_OROM")) {
348 if (hba_id
== SYS_DEV_SAS
)
349 snprintf(path
, PATH_MAX
, "%s/%s-%s", SYS_EFI_VAR_PATH
, SCU_PROP
, guid_str(buf
, VENDOR_GUID
));
351 snprintf(path
, PATH_MAX
, "%s/%s-%s", SYS_EFI_VAR_PATH
, AHCI_PROP
, guid_str(buf
, VENDOR_GUID
));
353 dprintf("EFI VAR: path=%s\n", path
);
355 if ((dfd
= open(path
, O_RDONLY
)) < 0) {
356 populated_efi
[hba_id
] = 0;
359 n
= read(dfd
, &imsm_efi
[hba_id
], sizeof(imsm_efi
[0]));
361 if (n
< (int) (sizeof(imsm_efi
[0]))) {
364 populated_efi
[hba_id
] = 1;
365 return &imsm_efi
[hba_id
];
369 * backward interface compatibility
371 const struct imsm_orom
*find_imsm_orom(void)
373 return find_imsm_hba_orom(SYS_DEV_SATA
);
376 const struct imsm_orom
*find_imsm_capability(enum sys_dev_type hba_id
)
378 const struct imsm_orom
*cap
=NULL
;
381 if ((cap
= find_imsm_efi(hba_id
)) != NULL
)
383 if ((cap
= find_imsm_hba_orom(hba_id
)) != NULL
)
388 char *devt_to_devpath(dev_t dev
)
392 sprintf(device
, "/sys/dev/block/%d:%d/device", major(dev
), minor(dev
));
393 return canonicalize_file_name(device
);
396 char *diskfd_to_devpath(int fd
)
398 /* return the device path for a disk, return NULL on error or fd
399 * refers to a partition
403 if (fstat(fd
, &st
) != 0)
405 if (!S_ISBLK(st
.st_mode
))
408 return devt_to_devpath(st
.st_rdev
);
411 int path_attached_to_hba(const char *disk_path
, const char *hba_path
)
415 if (check_env("IMSM_TEST_AHCI_DEV") ||
416 check_env("IMSM_TEST_SCU_DEV")) {
420 if (!disk_path
|| !hba_path
)
422 dprintf("hba: %s - disk: %s\n", hba_path
, disk_path
);
423 if (strncmp(disk_path
, hba_path
, strlen(hba_path
)) == 0)
431 int devt_attached_to_hba(dev_t dev
, const char *hba_path
)
433 char *disk_path
= devt_to_devpath(dev
);
434 int rc
= path_attached_to_hba(disk_path
, hba_path
);
442 int disk_attached_to_hba(int fd
, const char *hba_path
)
444 char *disk_path
= diskfd_to_devpath(fd
);
445 int rc
= path_attached_to_hba(disk_path
, hba_path
);