Changeset View
Changeset View
Standalone View
Standalone View
stand/efi/libefi/efipart.c
Show All 37 Lines | |||||
#include <efi.h> | #include <efi.h> | ||||
#include <efilib.h> | #include <efilib.h> | ||||
#include <efiprot.h> | #include <efiprot.h> | ||||
#include <efichar.h> | #include <efichar.h> | ||||
#include <disk.h> | #include <disk.h> | ||||
static EFI_GUID blkio_guid = BLOCK_IO_PROTOCOL; | static EFI_GUID blkio_guid = BLOCK_IO_PROTOCOL; | ||||
static EFI_GUID FreeBSDGELIGUID = FREEBSD_GELI_GUID; | |||||
static int efipart_initfd(void); | static int efipart_initfd(void); | ||||
static int efipart_initcd(void); | static int efipart_initcd(void); | ||||
static int efipart_inithd(void); | static int efipart_inithd(void); | ||||
static int efipart_strategy(void *, int, daddr_t, size_t, char *, size_t *); | static int efipart_strategy(void *, int, daddr_t, size_t, char *, size_t *); | ||||
static int efipart_realstrategy(void *, int, daddr_t, size_t, char *, size_t *); | static int efipart_realstrategy(void *, int, daddr_t, size_t, char *, size_t *); | ||||
▲ Show 20 Lines • Show All 240 Lines • ▼ Show 20 Lines | for (i = 0; i < nin; i++) { | ||||
/* USB or SATA cd without the media. */ | /* USB or SATA cd without the media. */ | ||||
if (blkio->Media->RemovableMedia && | if (blkio->Media->RemovableMedia && | ||||
!blkio->Media->MediaPresent) { | !blkio->Media->MediaPresent) { | ||||
return (false); | return (false); | ||||
} | } | ||||
/* | /* | ||||
* We assume the block size 512 or greater power of 2. | * We assume the block size 512 or greater power of 2. | ||||
* iPXE is known to insert stub BLOCK IO device with | * iPXE is known to insert stub BLOCK IO device with | ||||
* BlockSize 1. | * BlockSize 1. | ||||
*/ | */ | ||||
if (blkio->Media->BlockSize < 512 || | if (blkio->Media->BlockSize < 512 || | ||||
!powerof2(blkio->Media->BlockSize)) { | !powerof2(blkio->Media->BlockSize)) { | ||||
return (false); | return (false); | ||||
} | } | ||||
} | } | ||||
▲ Show 20 Lines • Show All 174 Lines • ▼ Show 20 Lines | efipart_initcd(void) | ||||
bcache_add_dev(efiblk_pdinfo_count(&cdinfo)); | bcache_add_dev(efiblk_pdinfo_count(&cdinfo)); | ||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
efipart_hdinfo_add(EFI_HANDLE disk_handle, EFI_HANDLE part_handle) | efipart_hdinfo_add(EFI_HANDLE disk_handle, EFI_HANDLE part_handle) | ||||
{ | { | ||||
EFI_DEVICE_PATH *disk_devpath, *part_devpath; | EFI_DEVICE_PATH *disk_devpath, *part_devpath, *trimpath, *lastnode; | ||||
VENDOR_DEVICE_PATH *vendornode; | |||||
HARDDRIVE_DEVICE_PATH *node; | HARDDRIVE_DEVICE_PATH *node; | ||||
int unit; | int unit; | ||||
pdinfo_t *hd, *pd, *last; | pdinfo_t *hd, *pd, *pp, *last; | ||||
disk_devpath = efi_lookup_devpath(disk_handle); | disk_devpath = efi_lookup_devpath(disk_handle); | ||||
if (disk_devpath == NULL) | part_devpath = efi_lookup_devpath(part_handle); | ||||
if (disk_devpath == NULL || part_devpath == NULL) | |||||
return (ENOENT); | return (ENOENT); | ||||
if (part_handle != NULL) { | if (part_handle != NULL) { | ||||
part_devpath = efi_lookup_devpath(part_handle); | part_devpath = efi_lookup_devpath(part_handle); | ||||
if (part_devpath == NULL) | if (part_devpath == NULL) | ||||
return (ENOENT); | return (ENOENT); | ||||
node = (HARDDRIVE_DEVICE_PATH *) | node = (HARDDRIVE_DEVICE_PATH *) | ||||
efi_devpath_last_node(part_devpath); | efi_devpath_last_node(part_devpath); | ||||
if (node == NULL) | if (node == NULL) | ||||
return (ENOENT); /* This should not happen. */ | return (ENOENT); /* This should not happen. */ | ||||
} else { | } else { | ||||
part_devpath = NULL; | part_devpath = NULL; | ||||
node = NULL; | node = NULL; | ||||
} | } | ||||
/* Get the disk partition node */ | |||||
lastnode = efi_devpath_last_node(part_devpath); | |||||
if (lastnode == NULL) | |||||
return (ENOENT); /* This should not happen. */ | |||||
if (DevicePathType(lastnode) == MEDIA_DEVICE_PATH) { | |||||
if (DevicePathSubType(lastnode) == MEDIA_VENDOR_DP) { | |||||
vendornode = (VENDOR_DEVICE_PATH *)lastnode; | |||||
/* We only want GELI partitions */ | |||||
if (memcmp(&(vendornode->Guid), &FreeBSDGELIGUID, | |||||
sizeof(EFI_GUID))) { | |||||
return (EINVAL); | |||||
} | |||||
/* Trim off the vendor node */ | |||||
trimpath = efi_devpath_trim(part_devpath); | |||||
if (trimpath == NULL) | |||||
return (ENOENT); | |||||
lastnode = efi_devpath_last_node(trimpath); | |||||
if (lastnode == NULL) | |||||
return (ENOENT); | |||||
node = (HARDDRIVE_DEVICE_PATH *)lastnode; | |||||
} else if (DevicePathSubType(lastnode) == MEDIA_HARDDRIVE_DP) { | |||||
node = (HARDDRIVE_DEVICE_PATH *)lastnode; | |||||
} | |||||
else | |||||
return (EINVAL); | |||||
} else { | |||||
return (EINVAL); | |||||
} | |||||
pd = calloc(1, sizeof(pdinfo_t)); | pd = calloc(1, sizeof(pdinfo_t)); | ||||
if (pd == NULL) { | if (pd == NULL) { | ||||
printf("Failed to add disk, out of memory\n"); | printf("Failed to add disk, out of memory\n"); | ||||
return (ENOMEM); | return (ENOMEM); | ||||
} | } | ||||
STAILQ_INIT(&pd->pd_part); | STAILQ_INIT(&pd->pd_part); | ||||
STAILQ_FOREACH(hd, &hdinfo, pd_link) { | STAILQ_FOREACH(hd, &hdinfo, pd_link) { | ||||
if (efi_devpath_match(hd->pd_devpath, disk_devpath) == true) { | if (efi_devpath_match(hd->pd_devpath, disk_devpath) != 0) { | ||||
if (part_devpath == NULL) | /* Check if there's a related device entry | ||||
* already here. | |||||
*/ | |||||
STAILQ_FOREACH(pp, &hd->pd_part, pd_link) { | |||||
/* If the new device is a subpath of | |||||
* an existing device, then the | |||||
* existing entry subsumes the new | |||||
* one. | |||||
*/ | |||||
trimpath = efi_devpath_trim(pp->pd_devpath); | |||||
if (trimpath == NULL) | |||||
return (ENOMEM); | |||||
if (efi_devpath_match(trimpath, | |||||
part_devpath) != 0) { | |||||
free(trimpath); | |||||
free(pd); | |||||
return (EBUSY); | |||||
} | |||||
/* If the existing device path is a | |||||
* subpath of the new one, then the | |||||
* new entry subsumes the existing | |||||
* one. | |||||
*/ | |||||
free(trimpath); | |||||
trimpath = efi_devpath_trim(part_devpath); | |||||
if (trimpath == NULL) | |||||
return (ENOMEM); | |||||
if (efi_devpath_match(trimpath, | |||||
pp->pd_devpath) != 0) { | |||||
pp->pd_handle = part_handle; | |||||
pp->pd_basehandle = disk_handle; | |||||
pp->pd_devpath = part_devpath; | |||||
free(trimpath); | |||||
free(pd); | |||||
return (0); | return (0); | ||||
} | |||||
free(trimpath); | |||||
} | |||||
/* Add the partition. */ | /* Add the partition. */ | ||||
pd->pd_handle = part_handle; | pd->pd_handle = part_handle; | ||||
pd->pd_basehandle = disk_handle; | |||||
pd->pd_unit = node->PartitionNumber; | pd->pd_unit = node->PartitionNumber; | ||||
pd->pd_devpath = part_devpath; | pd->pd_devpath = part_devpath; | ||||
pd->pd_parent = hd; | pd->pd_parent = hd; | ||||
pd->pd_devsw = &efipart_hddev; | pd->pd_devsw = &efipart_hddev; | ||||
STAILQ_INSERT_TAIL(&hd->pd_part, pd, pd_link); | STAILQ_INSERT_TAIL(&hd->pd_part, pd, pd_link); | ||||
return (0); | return (0); | ||||
} | } | ||||
} | } | ||||
last = STAILQ_LAST(&hdinfo, pdinfo, pd_link); | last = STAILQ_LAST(&hdinfo, pdinfo, pd_link); | ||||
if (last != NULL) | if (last != NULL) | ||||
unit = last->pd_unit + 1; | unit = last->pd_unit + 1; | ||||
else | else | ||||
unit = 0; | unit = 0; | ||||
/* Add the disk. */ | /* Add the disk. */ | ||||
hd = pd; | hd = pd; | ||||
hd->pd_handle = disk_handle; | hd->pd_handle = disk_handle; | ||||
hd->pd_basehandle = disk_handle; | |||||
hd->pd_unit = unit; | hd->pd_unit = unit; | ||||
hd->pd_devpath = disk_devpath; | hd->pd_devpath = disk_devpath; | ||||
hd->pd_parent = NULL; | hd->pd_parent = NULL; | ||||
hd->pd_devsw = &efipart_hddev; | hd->pd_devsw = &efipart_hddev; | ||||
STAILQ_INSERT_TAIL(&hdinfo, hd, pd_link); | STAILQ_INSERT_TAIL(&hdinfo, hd, pd_link); | ||||
if (part_devpath == NULL) | if (part_devpath == NULL) | ||||
return (0); | return (0); | ||||
pd = calloc(1, sizeof(pdinfo_t)); | pd = calloc(1, sizeof(pdinfo_t)); | ||||
if (pd == NULL) { | if (pd == NULL) { | ||||
printf("Failed to add partition, out of memory\n"); | printf("Failed to add partition, out of memory\n"); | ||||
return (ENOMEM); | return (ENOMEM); | ||||
} | } | ||||
STAILQ_INIT(&pd->pd_part); | STAILQ_INIT(&pd->pd_part); | ||||
/* Add the partition. */ | /* Add the partition. */ | ||||
pd->pd_handle = part_handle; | pd->pd_handle = part_handle; | ||||
pd->pd_basehandle = disk_handle; | |||||
pd->pd_unit = node->PartitionNumber; | pd->pd_unit = node->PartitionNumber; | ||||
pd->pd_devpath = part_devpath; | pd->pd_devpath = part_devpath; | ||||
pd->pd_parent = hd; | pd->pd_parent = hd; | ||||
pd->pd_devsw = &efipart_hddev; | pd->pd_devsw = &efipart_hddev; | ||||
STAILQ_INSERT_TAIL(&hd->pd_part, pd, pd_link); | STAILQ_INSERT_TAIL(&hd->pd_part, pd, pd_link); | ||||
return (0); | return (0); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 44 Lines • ▼ Show 20 Lines | efipart_hdinfo_add_filepath(EFI_HANDLE disk_handle) | ||||
/* | /* | ||||
* Assume we are receiving handles in order, first disk handle, | * Assume we are receiving handles in order, first disk handle, | ||||
* then partitions for this disk. If this assumption proves | * then partitions for this disk. If this assumption proves | ||||
* false, this code would need update. | * false, this code would need update. | ||||
*/ | */ | ||||
if (p == NULL) { /* no colon, add the disk */ | if (p == NULL) { /* no colon, add the disk */ | ||||
pd->pd_handle = disk_handle; | pd->pd_handle = disk_handle; | ||||
pd->pd_basehandle = disk_handle; | |||||
pd->pd_unit = unit; | pd->pd_unit = unit; | ||||
pd->pd_devpath = devpath; | pd->pd_devpath = devpath; | ||||
pd->pd_parent = NULL; | pd->pd_parent = NULL; | ||||
pd->pd_devsw = &efipart_hddev; | pd->pd_devsw = &efipart_hddev; | ||||
STAILQ_INSERT_TAIL(&hdinfo, pd, pd_link); | STAILQ_INSERT_TAIL(&hdinfo, pd, pd_link); | ||||
free(pathname); | free(pathname); | ||||
return (0); | return (0); | ||||
} | } | ||||
Show All 15 Lines | efipart_hdinfo_add_filepath(EFI_HANDLE disk_handle) | ||||
*/ | */ | ||||
if (last == NULL) { | if (last == NULL) { | ||||
printf("BUG: No disk for partition \"%s\"\n", pathname); | printf("BUG: No disk for partition \"%s\"\n", pathname); | ||||
free(pathname); | free(pathname); | ||||
free(pd); | free(pd); | ||||
return (EINVAL); | return (EINVAL); | ||||
} | } | ||||
/* Add the partition. */ | /* Add the partition. */ | ||||
pd->pd_handle = disk_handle; | pd->pd_handle = disk_handle; | ||||
pd->pd_basehandle = disk_handle; | |||||
pd->pd_unit = unit; | pd->pd_unit = unit; | ||||
pd->pd_devpath = devpath; | pd->pd_devpath = devpath; | ||||
pd->pd_parent = last; | pd->pd_parent = last; | ||||
pd->pd_devsw = &efipart_hddev; | pd->pd_devsw = &efipart_hddev; | ||||
STAILQ_INSERT_TAIL(&last->pd_part, pd, pd_link); | STAILQ_INSERT_TAIL(&last->pd_part, pd, pd_link); | ||||
free(pathname); | free(pathname); | ||||
return (0); | return (0); | ||||
} | } | ||||
static void | static void | ||||
efipart_updatehd(void) | efipart_updatehd(void) | ||||
{ | { | ||||
int i, nin; | int i, nin; | ||||
EFI_DEVICE_PATH *devpath, *devpathcpy, *tmpdevpath, *node; | EFI_DEVICE_PATH *devpath, *devpathcpy, *tmpdevpath, *node; | ||||
EFI_HANDLE handle; | EFI_HANDLE handle; | ||||
EFI_BLOCK_IO *blkio; | EFI_BLOCK_IO *blkio; | ||||
EFI_STATUS status; | EFI_STATUS status; | ||||
nin = efipart_nhandles / sizeof (*efipart_handles); | nin = efipart_nhandles / sizeof (*efipart_handles); | ||||
for (i = 0; i < nin; i++) { | for (i = 0; i < nin; i++) { | ||||
devpath = efi_lookup_devpath(efipart_handles[i]); | devpath = efi_lookup_devpath(efipart_handles[i]); | ||||
if (devpath == NULL) | if (devpath == NULL) | ||||
continue; | continue; | ||||
if ((node = efi_devpath_last_node(devpath)) == NULL) | if ((node = efi_devpath_last_node(devpath)) == NULL) | ||||
continue; | continue; | ||||
if (!efipart_hdd(devpath)) | if (!efipart_hdd(devpath)) | ||||
continue; | continue; | ||||
status = BS->HandleProtocol(efipart_handles[i], | status = BS->HandleProtocol(efipart_handles[i], | ||||
&blkio_guid, (void **)&blkio); | &blkio_guid, (void **)&blkio); | ||||
if (EFI_ERROR(status)) | if (EFI_ERROR(status)) | ||||
continue; | continue; | ||||
/* Handle GELI volumes */ | |||||
if (DevicePathType(node) == MEDIA_DEVICE_PATH && | if (DevicePathType(node) == MEDIA_DEVICE_PATH && | ||||
DevicePathSubType(node) == MEDIA_VENDOR_DP) { | |||||
VENDOR_DEVICE_PATH *vendornode; | |||||
vendornode = (VENDOR_DEVICE_PATH *)node; | |||||
/* We only want GELI partitions */ | |||||
if (memcmp(&(vendornode->Guid), &FreeBSDGELIGUID, | |||||
sizeof(EFI_GUID))) { | |||||
continue; | |||||
} | |||||
/* Trim off the vendor node */ | |||||
devpathcpy = efi_devpath_trim(devpath); | |||||
if (devpathcpy == NULL) | |||||
continue; | |||||
if ((node = efi_devpath_last_node(devpathcpy)) == NULL) | |||||
continue; | |||||
devpath = devpathcpy; | |||||
} | |||||
if (DevicePathType(node) == MEDIA_DEVICE_PATH && | |||||
DevicePathSubType(node) == MEDIA_FILEPATH_DP) { | DevicePathSubType(node) == MEDIA_FILEPATH_DP) { | ||||
efipart_hdinfo_add_filepath(efipart_handles[i]); | efipart_hdinfo_add_filepath(efipart_handles[i]); | ||||
continue; | continue; | ||||
} | } | ||||
if (DevicePathType(node) == MEDIA_DEVICE_PATH && | if (DevicePathType(node) == MEDIA_DEVICE_PATH && | ||||
DevicePathSubType(node) == MEDIA_HARDDRIVE_DP) { | DevicePathSubType(node) == MEDIA_HARDDRIVE_DP) { | ||||
devpathcpy = efi_devpath_trim(devpath); | devpathcpy = efi_devpath_trim(devpath); | ||||
if (devpathcpy == NULL) | if (devpathcpy == NULL) | ||||
continue; | continue; | ||||
tmpdevpath = devpathcpy; | tmpdevpath = devpathcpy; | ||||
status = BS->LocateDevicePath(&blkio_guid, &tmpdevpath, | status = BS->LocateDevicePath(&blkio_guid, &tmpdevpath, | ||||
&handle); | &handle); | ||||
free(devpathcpy); | free(devpathcpy); | ||||
if (EFI_ERROR(status)) | if (EFI_ERROR(status)) | ||||
continue; | continue; | ||||
/* | /* | ||||
* We do not support nested partitions. | * We do not support nested partitions. | ||||
*/ | */ | ||||
devpathcpy = efi_lookup_devpath(handle); | devpathcpy = efi_lookup_devpath(handle); | ||||
if (devpathcpy == NULL) | if (devpathcpy == NULL) | ||||
continue; | continue; | ||||
if ((node = efi_devpath_last_node(devpathcpy)) == NULL) | if ((node = efi_devpath_last_node(devpathcpy)) == NULL) | ||||
continue; | continue; | ||||
if (DevicePathType(node) == MEDIA_DEVICE_PATH && | if (DevicePathType(node) == MEDIA_DEVICE_PATH && | ||||
DevicePathSubType(node) == MEDIA_HARDDRIVE_DP) | DevicePathSubType(node) == MEDIA_HARDDRIVE_DP) | ||||
continue; | continue; | ||||
Show All 19 Lines | |||||
} | } | ||||
static int | static int | ||||
efipart_print_common(struct devsw *dev, pdinfo_list_t *pdlist, int verbose) | efipart_print_common(struct devsw *dev, pdinfo_list_t *pdlist, int verbose) | ||||
{ | { | ||||
int ret = 0; | int ret = 0; | ||||
EFI_BLOCK_IO *blkio; | EFI_BLOCK_IO *blkio; | ||||
EFI_STATUS status; | EFI_STATUS status; | ||||
EFI_HANDLE h; | EFI_HANDLE handle; | ||||
EFI_HANDLE base_handle; | |||||
pdinfo_t *pd; | pdinfo_t *pd; | ||||
CHAR16 *text; | CHAR16 *text; | ||||
struct disk_devdesc pd_dev; | struct disk_devdesc pd_dev; | ||||
char line[80]; | char line[80]; | ||||
if (STAILQ_EMPTY(pdlist)) | if (STAILQ_EMPTY(pdlist)) | ||||
return (0); | return (0); | ||||
printf("%s devices:", dev->dv_name); | printf("%s devices:", dev->dv_name); | ||||
if ((ret = pager_output("\n")) != 0) | if ((ret = pager_output("\n")) != 0) | ||||
return (ret); | return (ret); | ||||
STAILQ_FOREACH(pd, pdlist, pd_link) { | STAILQ_FOREACH(pd, pdlist, pd_link) { | ||||
h = pd->pd_handle; | handle = pd->pd_handle; | ||||
base_handle = pd->pd_basehandle; | |||||
if (verbose) { /* Output the device path. */ | if (verbose) { /* Output the device path. */ | ||||
text = efi_devpath_name(efi_lookup_devpath(h)); | text = efi_devpath_name(efi_lookup_devpath(base_handle)); | ||||
if (text != NULL) { | if (text != NULL) { | ||||
printf(" %S", text); | printf(" %S", text); | ||||
efi_free_devpath_name(text); | efi_free_devpath_name(text); | ||||
if ((ret = pager_output("\n")) != 0) | if ((ret = pager_output("\n")) != 0) | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
snprintf(line, sizeof(line), | snprintf(line, sizeof(line), | ||||
" %s%d", dev->dv_name, pd->pd_unit); | " %s%d", dev->dv_name, pd->pd_unit); | ||||
printf("%s:", line); | printf("%s:", line); | ||||
status = BS->HandleProtocol(h, &blkio_guid, (void **)&blkio); | status = BS->HandleProtocol(base_handle, &blkio_guid, | ||||
(void **)&blkio); | |||||
if (!EFI_ERROR(status)) { | if (!EFI_ERROR(status)) { | ||||
printf(" %llu", | printf(" %llu", | ||||
blkio->Media->LastBlock == 0? 0: | blkio->Media->LastBlock == 0? 0: | ||||
(unsigned long long) (blkio->Media->LastBlock + 1)); | (unsigned long long) (blkio->Media->LastBlock + 1)); | ||||
if (blkio->Media->LastBlock != 0) { | if (blkio->Media->LastBlock != 0) { | ||||
printf(" X %u", blkio->Media->BlockSize); | printf(" X %u", blkio->Media->BlockSize); | ||||
} | } | ||||
printf(" blocks"); | printf(" blocks"); | ||||
if (blkio->Media->MediaPresent) { | if (blkio->Media->MediaPresent) { | ||||
if (blkio->Media->RemovableMedia) | if (blkio->Media->RemovableMedia) | ||||
printf(" (removable)"); | printf(" (removable)"); | ||||
} else { | } else { | ||||
printf(" (no media)"); | printf(" (no media)"); | ||||
} | } | ||||
if ((ret = pager_output("\n")) != 0) | if ((ret = pager_output("\n")) != 0) | ||||
break; | break; | ||||
if (!blkio->Media->MediaPresent) | if (!blkio->Media->MediaPresent) | ||||
continue; | continue; | ||||
pd->pd_blkio = blkio; | pd->pd_blkio = blkio; | ||||
pd_dev.dd.d_dev = dev; | pd_dev.dd.d_dev = dev; | ||||
pd_dev.dd.d_unit = pd->pd_unit; | pd_dev.dd.d_unit = pd->pd_unit; | ||||
pd_dev.d_slice = -1; | pd_dev.d_slice = -1; | ||||
pd_dev.d_partition = -1; | pd_dev.d_partition = -1; | ||||
pd_dev.dd.d_opendata = blkio; | |||||
ret = disk_open(&pd_dev, blkio->Media->BlockSize * | ret = disk_open(&pd_dev, blkio->Media->BlockSize * | ||||
(blkio->Media->LastBlock + 1), | (blkio->Media->LastBlock + 1), | ||||
blkio->Media->BlockSize); | blkio->Media->BlockSize); | ||||
if (ret == 0) { | if (ret == 0) { | ||||
ret = disk_print(&pd_dev, line, verbose); | ret = disk_print(&pd_dev, line, verbose); | ||||
disk_close(&pd_dev); | disk_close(&pd_dev); | ||||
if (ret != 0) | if (ret != 0) | ||||
return (ret); | return (ret); | ||||
} else { | } else { | ||||
/* Do not fail from disk_open() */ | /* Do not fail from disk_open() */ | ||||
printf("Open device failed %d\n", ret); | |||||
ret = 0; | ret = 0; | ||||
} | } | ||||
} else { | } else { | ||||
if ((ret = pager_output("\n")) != 0) | if ((ret = pager_output("\n")) != 0) | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
return (ret); | return (ret); | ||||
} | } | ||||
static int | static int | ||||
Show All 10 Lines | |||||
static int | static int | ||||
efipart_printhd(int verbose) | efipart_printhd(int verbose) | ||||
{ | { | ||||
return (efipart_print_common(&efipart_hddev, &hdinfo, verbose)); | return (efipart_print_common(&efipart_hddev, &hdinfo, verbose)); | ||||
} | } | ||||
static int | static int | ||||
efipart_lookupdev(struct disk_devdesc *dev, pdinfo_t **pp) | |||||
{ | |||||
pdinfo_list_t *pdi; | |||||
pdinfo_t *pd = NULL, *curr; | |||||
if (dev == NULL) { | |||||
return (EINVAL); | |||||
} | |||||
pdi = efiblk_get_pdinfo_list(dev->dd.d_dev); | |||||
if (pdi == NULL) { | |||||
return (EINVAL); | |||||
} | |||||
STAILQ_FOREACH(curr, pdi, pd_link) { | |||||
if (curr->pd_unit == dev->dd.d_unit) { | |||||
pd = curr; | |||||
break; | |||||
} | |||||
} | |||||
if (pd == NULL) | |||||
return (ENOENT); | |||||
*pp = NULL; | |||||
/* If we're looking up a specific partition, get the | |||||
* IO interface from that devide handle. | |||||
*/ | |||||
if (dev->d_slice != -1) { | |||||
STAILQ_FOREACH(curr, &pd->pd_part, pd_link) { | |||||
if (curr->pd_unit == dev->d_slice) { | |||||
*pp = curr; | |||||
break; | |||||
} | |||||
} | |||||
} else { | |||||
*pp = pd; | |||||
} | |||||
if (*pp == NULL) | |||||
return (ENOENT); | |||||
return (0); | |||||
} | |||||
static int | |||||
efipart_open(struct open_file *f, ...) | efipart_open(struct open_file *f, ...) | ||||
{ | { | ||||
va_list args; | va_list args; | ||||
struct disk_devdesc *dev; | struct disk_devdesc *dev; | ||||
pdinfo_t *pd; | pdinfo_t *pd; | ||||
EFI_BLOCK_IO *blkio; | EFI_BLOCK_IO *blkio; | ||||
EFI_STATUS status; | EFI_STATUS status; | ||||
int err; | |||||
va_start(args, f); | va_start(args, f); | ||||
dev = va_arg(args, struct disk_devdesc*); | dev = va_arg(args, struct disk_devdesc*); | ||||
va_end(args); | va_end(args); | ||||
if (dev == NULL) | |||||
return (EINVAL); | |||||
pd = efiblk_get_pdinfo((struct devdesc *)dev); | if ((err = efipart_lookupdev(dev, &pd)) != 0) { | ||||
if (pd == NULL) | return (err); | ||||
return (EIO); | } | ||||
if (pd->pd_blkio == NULL) { | if (pd->pd_blkio == NULL) { | ||||
status = BS->HandleProtocol(pd->pd_handle, &blkio_guid, | status = BS->HandleProtocol(pd->pd_handle, &blkio_guid, | ||||
(void **)&pd->pd_blkio); | (void **)&pd->pd_blkio); | ||||
if (EFI_ERROR(status)) | if (EFI_ERROR(status)) | ||||
return (efi_status_to_errno(status)); | return (efi_status_to_errno(status)); | ||||
} | } | ||||
blkio = pd->pd_blkio; | blkio = pd->pd_blkio; | ||||
if (!blkio->Media->MediaPresent) | if (!blkio->Media->MediaPresent) { | ||||
return (EAGAIN); | return (EAGAIN); | ||||
} | |||||
pd->pd_open++; | pd->pd_open++; | ||||
if (pd->pd_bcache == NULL) | if (pd->pd_bcache == NULL) | ||||
pd->pd_bcache = bcache_allocate(); | pd->pd_bcache = bcache_allocate(); | ||||
if (dev->dd.d_dev->dv_type == DEVT_DISK) { | dev->d_offset = 0; | ||||
int rc; | |||||
rc = disk_open(dev, | |||||
blkio->Media->BlockSize * (blkio->Media->LastBlock + 1), | |||||
blkio->Media->BlockSize); | |||||
if (rc != 0) { | |||||
pd->pd_open--; | |||||
if (pd->pd_open == 0) { | |||||
pd->pd_blkio = NULL; | |||||
bcache_free(pd->pd_bcache); | |||||
pd->pd_bcache = NULL; | |||||
} | |||||
} | |||||
return (rc); | |||||
} | |||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
efipart_close(struct open_file *f) | efipart_close(struct open_file *f) | ||||
{ | { | ||||
struct disk_devdesc *dev; | struct disk_devdesc *dev; | ||||
pdinfo_t *pd; | pdinfo_t *pd; | ||||
int err; | |||||
dev = (struct disk_devdesc *)(f->f_devdata); | dev = (struct disk_devdesc *)(f->f_devdata); | ||||
if (dev == NULL) | |||||
return (EINVAL); | |||||
pd = efiblk_get_pdinfo((struct devdesc *)dev); | if ((err = efipart_lookupdev(dev, &pd)) != 0) { | ||||
if (pd == NULL) | return (err); | ||||
return (EINVAL); | } | ||||
pd->pd_open--; | pd->pd_open--; | ||||
if (pd->pd_open == 0) { | if (pd->pd_open == 0) { | ||||
pd->pd_blkio = NULL; | pd->pd_blkio = NULL; | ||||
bcache_free(pd->pd_bcache); | bcache_free(pd->pd_bcache); | ||||
pd->pd_bcache = NULL; | pd->pd_bcache = NULL; | ||||
} | } | ||||
if (dev->dd.d_dev->dv_type == DEVT_DISK) | |||||
return (disk_close(dev)); | |||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
efipart_ioctl(struct open_file *f, u_long cmd, void *data) | efipart_ioctl(struct open_file *f, u_long cmd, void *data) | ||||
{ | { | ||||
struct disk_devdesc *dev; | struct disk_devdesc *dev; | ||||
pdinfo_t *pd; | pdinfo_t *pd; | ||||
int rc; | int err; | ||||
dev = (struct disk_devdesc *)(f->f_devdata); | dev = (struct disk_devdesc *)(f->f_devdata); | ||||
if (dev == NULL) | |||||
return (EINVAL); | |||||
pd = efiblk_get_pdinfo((struct devdesc *)dev); | if ((err = efipart_lookupdev(dev, &pd)) != 0) { | ||||
if (pd == NULL) | return (err); | ||||
return (EINVAL); | |||||
if (dev->dd.d_dev->dv_type == DEVT_DISK) { | |||||
rc = disk_ioctl(dev, cmd, data); | |||||
if (rc != ENOTTY) | |||||
return (rc); | |||||
} | } | ||||
switch (cmd) { | switch (cmd) { | ||||
case DIOCGSECTORSIZE: | case DIOCGSECTORSIZE: | ||||
*(u_int *)data = pd->pd_blkio->Media->BlockSize; | *(u_int *)data = pd->pd_blkio->Media->BlockSize; | ||||
break; | break; | ||||
case DIOCGMEDIASIZE: | case DIOCGMEDIASIZE: | ||||
*(uint64_t *)data = pd->pd_blkio->Media->BlockSize * | *(uint64_t *)data = pd->pd_blkio->Media->BlockSize * | ||||
(pd->pd_blkio->Media->LastBlock + 1); | (pd->pd_blkio->Media->LastBlock + 1); | ||||
▲ Show 20 Lines • Show All 49 Lines • ▼ Show 20 Lines | |||||
static int | static int | ||||
efipart_strategy(void *devdata, int rw, daddr_t blk, size_t size, | efipart_strategy(void *devdata, int rw, daddr_t blk, size_t size, | ||||
char *buf, size_t *rsize) | char *buf, size_t *rsize) | ||||
{ | { | ||||
struct bcache_devdata bcd; | struct bcache_devdata bcd; | ||||
struct disk_devdesc *dev; | struct disk_devdesc *dev; | ||||
pdinfo_t *pd; | pdinfo_t *pd; | ||||
int err; | |||||
dev = (struct disk_devdesc *)devdata; | dev = (struct disk_devdesc *)devdata; | ||||
if (dev == NULL) | |||||
return (EINVAL); | |||||
pd = efiblk_get_pdinfo((struct devdesc *)dev); | if ((err = efipart_lookupdev(dev, &pd)) != 0) { | ||||
if (pd == NULL) | return (err); | ||||
return (EINVAL); | } | ||||
if (pd->pd_blkio->Media->RemovableMedia && | if (pd->pd_blkio->Media->RemovableMedia && | ||||
!pd->pd_blkio->Media->MediaPresent) | !pd->pd_blkio->Media->MediaPresent) | ||||
return (ENXIO); | return (ENXIO); | ||||
bcd.dv_strategy = efipart_realstrategy; | bcd.dv_strategy = efipart_realstrategy; | ||||
bcd.dv_devdata = devdata; | bcd.dv_devdata = devdata; | ||||
bcd.dv_cache = pd->pd_bcache; | bcd.dv_cache = pd->pd_bcache; | ||||
Show All 17 Lines | efipart_realstrategy(void *devdata, int rw, daddr_t blk, size_t size, | ||||
pdinfo_t *pd; | pdinfo_t *pd; | ||||
EFI_BLOCK_IO *blkio; | EFI_BLOCK_IO *blkio; | ||||
uint64_t off, disk_blocks, d_offset = 0; | uint64_t off, disk_blocks, d_offset = 0; | ||||
char *blkbuf; | char *blkbuf; | ||||
size_t blkoff, blksz; | size_t blkoff, blksz; | ||||
int error; | int error; | ||||
size_t diskend, readstart; | size_t diskend, readstart; | ||||
if (dev == NULL || blk < 0) | if (blk < 0) | ||||
return (EINVAL); | return (EINVAL); | ||||
pd = efiblk_get_pdinfo((struct devdesc *)dev); | if ((error = efipart_lookupdev(dev, &pd)) != 0) { | ||||
if (pd == NULL) | return (error); | ||||
return (EINVAL); | } | ||||
blkio = pd->pd_blkio; | blkio = pd->pd_blkio; | ||||
if (blkio == NULL) | if (blkio == NULL) | ||||
return (ENXIO); | return (ENXIO); | ||||
if (size == 0 || (size % 512) != 0) | if (size == 0 || (size % 512) != 0) | ||||
return (EIO); | return (EIO); | ||||
off = blk * 512; | off = blk * 512; | ||||
/* | |||||
* Get disk blocks, this value is either for whole disk or for | |||||
* partition. | |||||
*/ | |||||
disk_blocks = 0; | |||||
if (dev->dd.d_dev->dv_type == DEVT_DISK) { | |||||
if (disk_ioctl(dev, DIOCGMEDIASIZE, &disk_blocks) == 0) { | |||||
/* DIOCGMEDIASIZE does return bytes. */ | |||||
disk_blocks /= blkio->Media->BlockSize; | |||||
} | |||||
d_offset = dev->d_offset; | |||||
} | |||||
if (disk_blocks == 0) | |||||
disk_blocks = blkio->Media->LastBlock + 1 - d_offset; | disk_blocks = blkio->Media->LastBlock + 1 - d_offset; | ||||
/* make sure we don't read past disk end */ | /* make sure we don't read past disk end */ | ||||
if ((off + size) / blkio->Media->BlockSize > d_offset + disk_blocks) { | if ((off + size) / blkio->Media->BlockSize > d_offset + disk_blocks) { | ||||
diskend = d_offset + disk_blocks; | diskend = d_offset + disk_blocks; | ||||
readstart = off / blkio->Media->BlockSize; | readstart = off / blkio->Media->BlockSize; | ||||
if (diskend <= readstart) { | if (diskend <= readstart) { | ||||
if (rsize != NULL) | if (rsize != NULL) | ||||
▲ Show 20 Lines • Show All 45 Lines • Show Last 20 Lines |