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
];
299 * backward interface compatibility
301 const struct imsm_orom
*find_imsm_orom(void)
303 return find_imsm_hba_orom(SYS_DEV_SATA
);
306 const struct imsm_orom
*find_imsm_capability(enum sys_dev_type hba_id
)
308 const struct imsm_orom
*cap
=NULL
;
310 if ((cap
= find_imsm_hba_orom(hba_id
)) != NULL
)
315 char *devt_to_devpath(dev_t dev
)
319 sprintf(device
, "/sys/dev/block/%d:%d/device", major(dev
), minor(dev
));
320 return canonicalize_file_name(device
);
323 char *diskfd_to_devpath(int fd
)
325 /* return the device path for a disk, return NULL on error or fd
326 * refers to a partition
330 if (fstat(fd
, &st
) != 0)
332 if (!S_ISBLK(st
.st_mode
))
335 return devt_to_devpath(st
.st_rdev
);
338 int path_attached_to_hba(const char *disk_path
, const char *hba_path
)
342 if (check_env("IMSM_TEST_AHCI_DEV") ||
343 check_env("IMSM_TEST_SCU_DEV")) {
347 if (!disk_path
|| !hba_path
)
349 dprintf("hba: %s - disk: %s\n", hba_path
, disk_path
);
350 if (strncmp(disk_path
, hba_path
, strlen(hba_path
)) == 0)
358 int devt_attached_to_hba(dev_t dev
, const char *hba_path
)
360 char *disk_path
= devt_to_devpath(dev
);
361 int rc
= path_attached_to_hba(disk_path
, hba_path
);
369 int disk_attached_to_hba(int fd
, const char *hba_path
)
371 char *disk_path
= diskfd_to_devpath(fd
);
372 int rc
= path_attached_to_hba(disk_path
, hba_path
);