[U-Boot] [PATCH 00/11] Add DM blockdev subsystem

This series adds the new unified blockdev subsystem based on DM, converts all filesystems and associated commands to the new API and adds a compatibility wrapper for current SATA drivers.
Note: this is based on current DM branch with some FS cleanup patches sent out recently.
Pavel Herrmann (11): DM: add block device core DM: add support for scanning DOS partitions to blockdev core DM: add block controller core DM: add sata_legacy driver for blockctrl DM: add ata and partition blockdev drivers DM: add cmd_block command DM: use new blockdev API in FAT DM: use new blockdev API in ext2 DM: use new blockdev API in reiserfs DM: use new blockdev API in ZFS DM: switch sandbox to DM blockdev
Makefile | 2 + arch/sandbox/lib/board.c | 8 + common/Makefile | 14 + common/cmd_block.c | 139 ++++++ common/cmd_ext2dm.c | 211 +++++++++ common/cmd_fatdm.c | 192 ++++++++ common/cmd_reiserdm.c | 193 ++++++++ common/cmd_zfsdm.c | 199 ++++++++ drivers/blockctrl/Makefile | 43 ++ drivers/blockctrl/core.c | 349 ++++++++++++++ drivers/blockctrl/sata_legacy.c | 166 +++++++ drivers/blockdev/Makefile | 43 ++ drivers/blockdev/ata.c | 234 ++++++++++ drivers/blockdev/ata.h | 37 ++ drivers/blockdev/core.c | 752 +++++++++++++++++++++++++++++++ drivers/blockdev/part_types/part_dos.c | 148 ++++++ drivers/blockdev/part_types/part_dos.h | 49 ++ drivers/blockdev/part_types/part_types.h | 34 ++ drivers/blockdev/partition.c | 179 ++++++++ fs/ext2/Makefile | 7 +- fs/ext2/dev_dm.c | 107 +++++ fs/fat/Makefile | 7 +- fs/fat/dev_dm.c | 141 ++++++ fs/reiserfs/Makefile | 8 +- fs/reiserfs/dev_dm.c | 104 +++++ fs/zfs/Makefile | 7 +- fs/zfs/dev_dm.c | 117 +++++ include/configs/sandbox.h | 4 + include/dm/blockctrl.h | 75 +++ include/dm/blockdev.h | 121 +++++ include/ext2fs.h | 9 +- include/fat.h | 8 + include/reiserfs.h | 8 +- include/zfs_common.h | 8 + 34 files changed, 3717 insertions(+), 6 deletions(-) create mode 100644 common/cmd_block.c create mode 100644 common/cmd_ext2dm.c create mode 100644 common/cmd_fatdm.c create mode 100644 common/cmd_reiserdm.c create mode 100644 common/cmd_zfsdm.c create mode 100644 drivers/blockctrl/Makefile create mode 100644 drivers/blockctrl/core.c create mode 100644 drivers/blockctrl/sata_legacy.c create mode 100644 drivers/blockdev/Makefile create mode 100644 drivers/blockdev/ata.c create mode 100644 drivers/blockdev/ata.h create mode 100644 drivers/blockdev/core.c create mode 100644 drivers/blockdev/part_types/part_dos.c create mode 100644 drivers/blockdev/part_types/part_dos.h create mode 100644 drivers/blockdev/part_types/part_types.h create mode 100644 drivers/blockdev/partition.c create mode 100644 fs/ext2/dev_dm.c create mode 100644 fs/fat/dev_dm.c create mode 100644 fs/reiserfs/dev_dm.c create mode 100644 fs/zfs/dev_dm.c create mode 100644 include/dm/blockctrl.h create mode 100644 include/dm/blockdev.h

This core will register all block devices (disk, cards, partitons) and provide unfied access to them, instead of current method with device + partition offset
Signed-off-by: Pavel Herrmann morpheus.ibis@gmail.com --- Makefile | 1 + drivers/blockdev/Makefile | 42 ++++++++++++++++ include/dm/blockdev.h | 121 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 164 insertions(+) create mode 100644 drivers/blockdev/Makefile create mode 100644 include/dm/blockdev.h
diff --git a/Makefile b/Makefile index ba74696..e43fd9d 100644 --- a/Makefile +++ b/Makefile @@ -303,6 +303,7 @@ LIBS-y += test/libtest.o
LIBS-$(CONFIG_DM) += common/dm/libdm.o LIBS-$(CONFIG_DM) += drivers/demo/libdemo.o +LIBS-${CONFIG_DM_BLOCK} += drivers/blockdev/libblockdev.o
ifneq ($(CONFIG_AM33XX)$(CONFIG_OMAP34XX)$(CONFIG_OMAP44XX)$(CONFIG_OMAP54XX),) LIBS-y += $(CPUDIR)/omap-common/libomap-common.o diff --git a/drivers/blockdev/Makefile b/drivers/blockdev/Makefile new file mode 100644 index 0000000..693e236 --- /dev/null +++ b/drivers/blockdev/Makefile @@ -0,0 +1,42 @@ +# See file CREDITS for list of people who contributed to this +# project. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# + +include $(TOPDIR)/config.mk + +LIB := $(obj)libblockdev.o + +COBJS-${CONFIG_DM_BLOCK} := core.o + +COBJS := $(COBJS-y) +SRCS := $(COBJS:.o=.c) +OBJS := $(addprefix $(obj),$(COBJS)) + +all: $(LIB) + +$(LIB): $(obj).depend $(OBJS) + $(call cmd_link_o_target, $(OBJS)) + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/include/dm/blockdev.h b/include/dm/blockdev.h new file mode 100644 index 0000000..828eb2b --- /dev/null +++ b/include/dm/blockdev.h @@ -0,0 +1,121 @@ +/* + * (C) Copyright 2012 + * Pavel Herrmann morpheus.ibis@gmail.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef _DM_BLOCKDEV_H_ +#define _DM_BLOCKDEV_H_ 1 + +#include <dm/options.h> +#include <dm/structures.h> + +#define BLOCKDEV_IFTYPE_BITS 4 +#define BLOCKDEV_IFTYPE_COUNT (1<<BLOCKDEV_IFTYPE_BITS) +#define BLOCKDEV_IFTYPE_MAX BLOCKDEV_IFTYPE_COUNT-1 + +/* core interface structures */ + +enum blockdev_iftype { + BLOCKDEV_IFTYPE_UNKNOWN = 0, + BLOCKDEV_IFTYPE_PARTITION, + BLOCKDEV_IFTYPE_ATA, + BLOCKDEV_IFTYPE_SD, + BLOCKDEV_IFTYPE_USB, +}; + +/* values from ATA specification */ +#define BLOCKDEV_TYPE_UNKNOWN 0xff +#define BLOCKDEV_TYPE_HARDDISK 0x00 +#define BLOCKDEV_TYPE_TAPE 0x01 +#define BLOCKDEV_TYPE_CDROM 0x05 +#define BLOCKDEV_TYPE_OPDISK 0x07 +/* this one does not exist in ATA */ +#define BLOCKDEV_TYPE_PARTITION 0xfe + +enum blockdev_option_code { + BLKD_OPT_IFTYPE = 0, + BLKD_OPT_TYPE, + BLKD_OPT_BLOCKSIZE, + BLKD_OPT_BLOCKCOUNT, + BLKD_OPT_REMOVABLE, + BLKD_OPT_LBA48, + BLKD_OPT_VENDOR, + BLKD_OPT_PRODUCT, + BLKD_OPT_REVISION, + BLKD_OPT_SCSILUN, + BLKD_OPT_SCSITARGET, + BLKD_OPT_OFFSET +}; + +struct blockdev_ops { + lbaint_t (*read)(struct instance *inst, lbaint_t start, + lbaint_t blkcnt, void *buffer); + lbaint_t (*write)(struct instance *inst, lbaint_t start, + lbaint_t blkcnt, void *buffer); + lbaint_t (*erase)(struct instance *inst, lbaint_t start, + lbaint_t blkcnt); + int (*get_option)(struct instance *inst, + enum blockdev_option_code option, + struct option *result); + int (*set_option)(struct instance *inst, + enum blockdev_option_code option, + struct option *value); +}; + +struct blockdev_core_hint { + enum blockdev_iftype iftype; + unsigned int part_number; +}; + +/* platform data for devices */ + +struct blockdev_ata_platform_data { + int port_number; +}; + +struct blockdev_partition_platform_data { + lbaint_t offset; + lbaint_t block_count; + unsigned int part_number; +}; + +/* core command API */ + +struct instance *get_blockdev_by_name(char *name); +int scan_partitions(struct instance *i); +int add_partition(struct instance *parent, lbaint_t start, lbaint_t length, + unsigned int number); +int print_blockdev_info(struct instance *i); +int print_blockdev_info_all(void); + +/* core driver API */ + +lbaint_t blockdev_read(struct instance *i, lbaint_t start, lbaint_t blkcnt, + void *buffer); +lbaint_t blockdev_write(struct instance *i, lbaint_t start, lbaint_t blkcnt, + void *buffer); +lbaint_t blockdev_erase(struct instance *i, lbaint_t start, lbaint_t blkcnt); +int blockdev_get_option(struct instance *i, enum blockdev_option_code op, + struct option *result); +int blockdev_set_option(struct instance *i, enum blockdev_option_code op, + struct option *value); + +#endif

Dear Pavel Herrmann,
This core will register all block devices (disk, cards, partitons) and provide unfied access to them, instead of current method with device + partition offset
Signed-off-by: Pavel Herrmann morpheus.ibis@gmail.com
Makefile | 1 + drivers/blockdev/Makefile | 42 ++++++++++++++++ include/dm/blockdev.h | 121 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 164 insertions(+) create mode 100644 drivers/blockdev/Makefile create mode 100644 include/dm/blockdev.h
Why not use drivers/block/ ?
[...]
Best regards, Marek Vasut

On Thursday 20 of September 2012 21:58:17 Marek Vasut wrote:
Dear Pavel Herrmann,
This core will register all block devices (disk, cards, partitons) and provide unfied access to them, instead of current method with device + partition offset
Signed-off-by: Pavel Herrmann morpheus.ibis@gmail.com
Makefile | 1 + drivers/blockdev/Makefile | 42 ++++++++++++++++ include/dm/blockdev.h | 121
++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 164 insertions(+)
create mode 100644 drivers/blockdev/Makefile create mode 100644 include/dm/blockdev.h
Why not use drivers/block/ ?
Because the drivers in drivers/block have a different purpose than blockdev. I would expect this question for blockctrl, there i just try to avoid confusion about being completely compatible
Pavel Herrmann

Dear Pavel Herrmann,
On Thursday 20 of September 2012 21:58:17 Marek Vasut wrote:
Dear Pavel Herrmann,
This core will register all block devices (disk, cards, partitons) and provide unfied access to them, instead of current method with device + partition offset
Signed-off-by: Pavel Herrmann morpheus.ibis@gmail.com
Makefile | 1 + drivers/blockdev/Makefile | 42 ++++++++++++++++ include/dm/blockdev.h | 121
++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 164 insertions(+)
create mode 100644 drivers/blockdev/Makefile create mode 100644 include/dm/blockdev.h
Why not use drivers/block/ ?
Because the drivers in drivers/block have a different purpose than blockdev.
Different, ok. Can you elaborate how is it different?
I would expect this question for blockctrl, there i just try to avoid confusion about being completely compatible
Pavel Herrmann
Best regards, Marek Vasut

On Friday 21 of September 2012 14:39:14 Marek Vasut wrote:
Dear Pavel Herrmann,
On Thursday 20 of September 2012 21:58:17 Marek Vasut wrote:
Dear Pavel Herrmann,
This core will register all block devices (disk, cards, partitons) and provide unfied access to them, instead of current method with device + partition offset
Signed-off-by: Pavel Herrmann morpheus.ibis@gmail.com
Makefile | 1 + drivers/blockdev/Makefile | 42 ++++++++++++++++ include/dm/blockdev.h | 121
++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 164 insertions(+)
create mode 100644 drivers/blockdev/Makefile create mode 100644 include/dm/blockdev.h
Why not use drivers/block/ ?
Because the drivers in drivers/block have a different purpose than blockdev.
Different, ok. Can you elaborate how is it different?
blockctrl is equivalent in purpose to drivers/block, just a new approach
blockctrl = AHCI, PIIX... whichever chip you have between SATA and PCI (or generally disk-bus and board-bus)
blockdev = disk, partition, SD card - something that does basic checks (range, possibility of operation) and submits operations to correct parent (blockctrl, MMC controller, whatnot). Also this gets rid of all partition-related code in filesystems, because the access to a partition and to the whole disk is the same, no need to manually compute offsets every time (and you can support discontinuous partitions, if you chose to do so)
Pavel Herrmann

Dear Pavel Herrmann,
On Friday 21 of September 2012 14:39:14 Marek Vasut wrote:
Dear Pavel Herrmann,
On Thursday 20 of September 2012 21:58:17 Marek Vasut wrote:
Dear Pavel Herrmann,
This core will register all block devices (disk, cards, partitons) and provide unfied access to them, instead of current method with device + partition offset
Signed-off-by: Pavel Herrmann morpheus.ibis@gmail.com
Makefile | 1 + drivers/blockdev/Makefile | 42 ++++++++++++++++ include/dm/blockdev.h | 121
++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 164 insertions(+)
create mode 100644 drivers/blockdev/Makefile create mode 100644 include/dm/blockdev.h
Why not use drivers/block/ ?
Because the drivers in drivers/block have a different purpose than blockdev.
Different, ok. Can you elaborate how is it different?
blockctrl is equivalent in purpose to drivers/block, just a new approach
blockctrl = AHCI, PIIX... whichever chip you have between SATA and PCI (or generally disk-bus and board-bus)
So this is for sata ? Or will it also by used for SD/USB flash discs?
blockdev = disk, partition, SD card
Uh, let's say I understand (even if I don't see the correlation between partition and SD card)
- something that does basic checks
(range, possibility of operation) and submits operations to correct parent (blockctrl, MMC controller, whatnot).
Ascii art might help here greatly (how these pieces fall together). I think I do understand it though.
Also this gets rid of all partition-related code in filesystems, because the access to a partition and to the whole disk is the same, no need to manually compute offsets every time (and you can support discontinuous partitions, if you chose to do so)
Pavel Herrmann
Best regards, Marek Vasut

On Friday 21 of September 2012 15:53:26 Marek Vasut wrote:
Dear Pavel Herrmann,
On Friday 21 of September 2012 14:39:14 Marek Vasut wrote:
Dear Pavel Herrmann,
On Thursday 20 of September 2012 21:58:17 Marek Vasut wrote:
Dear Pavel Herrmann,
This core will register all block devices (disk, cards, partitons) and provide unfied access to them, instead of current method with device + partition offset
Signed-off-by: Pavel Herrmann morpheus.ibis@gmail.com
Makefile | 1 + drivers/blockdev/Makefile | 42 ++++++++++++++++ include/dm/blockdev.h | 121
++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 164 insertions(+)
create mode 100644 drivers/blockdev/Makefile create mode 100644 include/dm/blockdev.h
Why not use drivers/block/ ?
Because the drivers in drivers/block have a different purpose than blockdev.
Different, ok. Can you elaborate how is it different?
blockctrl is equivalent in purpose to drivers/block, just a new approach
blockctrl = AHCI, PIIX... whichever chip you have between SATA and PCI (or generally disk-bus and board-bus)
So this is for sata ? Or will it also by used for SD/USB flash discs?
no, blockctrl will be used for SATA, PATA, SCSI, and anything of the sort (device with several ports, block devices on said ports, ability to send read/write/query commands to devices on ports - definitely not USB, possibly also SD, but you probably want more operations from SD)
blockdev = disk, partition, SD card
Uh, let's say I understand (even if I don't see the correlation between partition and SD card)
they are an ordered bunch of blocks with a "conventional" filesystem on them
- something that does basic checks
(range, possibility of operation) and submits operations to correct parent (blockctrl, MMC controller, whatnot).
Ascii art might help here greatly (how these pieces fall together). I think I do understand it though.
current code user -> FS -> offset calculation from partition info -> drivers/disk
new code user -> FS -> blockdev -> blockctrl (or USB or SD controller)
partition blockdev does all the offset calculation and range check that FSs do now, and then submits the operation to the parent blockdev, which in turn submits it to blockctrl (or an SD controller in case of a SD card, or USB controller in case of a USB flash)
Pavel Herrmann

Dear Pavel Herrmann,
[...]
blockctrl = AHCI, PIIX... whichever chip you have between SATA and PCI (or generally disk-bus and board-bus)
So this is for sata ? Or will it also by used for SD/USB flash discs?
no, blockctrl will be used for SATA, PATA, SCSI, and anything of the sort (device with several ports, block devices on said ports, ability to send read/write/query commands to devices on ports - definitely not USB, possibly also SD, but you probably want more operations from SD)
Why not USB flash ? Why not SD, what other stuff do you need for that? Is the API not misdesigned then?
blockdev = disk, partition, SD card
Uh, let's say I understand (even if I don't see the correlation between partition and SD card)
they are an ordered bunch of blocks with a "conventional" filesystem on them
You might want to do RAW reads, so why do you put filesystem into this context?
- something that does basic checks
(range, possibility of operation) and submits operations to correct parent (blockctrl, MMC controller, whatnot).
Ascii art might help here greatly (how these pieces fall together). I think I do understand it though.
current code user -> FS -> offset calculation from partition info -> drivers/disk
new code user -> FS -> blockdev -> blockctrl (or USB or SD controller)
So your "blockctrl" should do the USB/SD/whatever muxing.
partition blockdev does all the offset calculation and range check that FSs do now, and then submits the operation to the parent blockdev, which in turn submits it to blockctrl (or an SD controller in case of a SD card, or USB controller in case of a USB flash)
Make sure you document this in the next series.
Pavel Herrmann
Best regards, Marek Vasut

On Friday 21 of September 2012 17:34:27 Marek Vasut wrote:
Dear Pavel Herrmann,
[...]
blockctrl = AHCI, PIIX... whichever chip you have between SATA and PCI (or generally disk-bus and board-bus)
So this is for sata ? Or will it also by used for SD/USB flash discs?
no, blockctrl will be used for SATA, PATA, SCSI, and anything of the sort (device with several ports, block devices on said ports, ability to send read/write/query commands to devices on ports - definitely not USB, possibly also SD, but you probably want more operations from SD)
Why not USB flash ? Why not SD, what other stuff do you need for that? Is the API not misdesigned then?
you should have a blockdev driver for USB flash and SD, but not blockctrl
blockdev = disk, partition, SD card
Uh, let's say I understand (even if I don't see the correlation between partition and SD card)
they are an ordered bunch of blocks with a "conventional" filesystem on them
You might want to do RAW reads, so why do you put filesystem into this context?
yes, you can do raw reads, but in most cases you are using a filesystem. i put filesystem there to differentiate from nand devices (which have a special flash- based filesystems in most cases).
- something that does basic checks
(range, possibility of operation) and submits operations to correct parent (blockctrl, MMC controller, whatnot).
Ascii art might help here greatly (how these pieces fall together). I think I do understand it though.
current code user -> FS -> offset calculation from partition info -> drivers/disk
new code user -> FS -> blockdev -> blockctrl (or USB or SD controller)
So your "blockctrl" should do the USB/SD/whatever muxing.
no, blockdev shoud be the last common part, for SD/USB, you should have a different blockdev driver, that uses USB/SD API for the actual works
blockctrl is just an unified look at whatever now resides in drivers/block
partition blockdev does all the offset calculation and range check that FSs do now, and then submits the operation to the parent blockdev, which in turn submits it to blockctrl (or an SD controller in case of a SD card, or USB controller in case of a USB flash)
Make sure you document this in the next series.
Pavel Herrmann
Best regards, Marek Vasut

Dear Pavel Herrmann,
On Friday 21 of September 2012 17:34:27 Marek Vasut wrote:
Dear Pavel Herrmann,
[...]
blockctrl = AHCI, PIIX... whichever chip you have between SATA and PCI (or generally disk-bus and board-bus)
So this is for sata ? Or will it also by used for SD/USB flash discs?
no, blockctrl will be used for SATA, PATA, SCSI, and anything of the sort (device with several ports, block devices on said ports, ability to send read/write/query commands to devices on ports - definitely not USB, possibly also SD, but you probably want more operations from SD)
Why not USB flash ? Why not SD, what other stuff do you need for that? Is the API not misdesigned then?
you should have a blockdev driver for USB flash and SD, but not blockctrl
I'm lost again. Do I also need a blockdev driver for SATA controller now that I need a blockdev driver for SD card controller ?
blockdev = disk, partition, SD card
Uh, let's say I understand (even if I don't see the correlation between partition and SD card)
they are an ordered bunch of blocks with a "conventional" filesystem on them
You might want to do RAW reads, so why do you put filesystem into this context?
yes, you can do raw reads, but in most cases you are using a filesystem.
Not true, see how env is stored to these media.
i put filesystem there to differentiate from nand devices (which have a special flash- based filesystems in most cases).
Not true, raw IO on flash media is often used too.
- something that does basic checks
(range, possibility of operation) and submits operations to correct parent (blockctrl, MMC controller, whatnot).
Ascii art might help here greatly (how these pieces fall together). I think I do understand it though.
current code user -> FS -> offset calculation from partition info -> drivers/disk
new code user -> FS -> blockdev -> blockctrl (or USB or SD controller)
So your "blockctrl" should do the USB/SD/whatever muxing.
no, blockdev shoud be the last common part, for SD/USB, you should have a different blockdev driver, that uses USB/SD API for the actual works
blockctrl is just an unified look at whatever now resides in drivers/block
Answer my question, you are contradicting yourself in your answer. So again, does "blockctrl" do the muxing between the downstream drivers (SD blockdev, USB blockdev, SATA blockdev, IDE blockdev ... ) ?
partition blockdev does all the offset calculation and range check that FSs do now, and then submits the operation to the parent blockdev, which in turn submits it to blockctrl (or an SD controller in case of a SD card, or USB controller in case of a USB flash)
Make sure you document this in the next series.
Pavel Herrmann
Best regards, Marek Vasut
Best regards, Marek Vasut

On Friday 21 of September 2012 17:55:10 Marek Vasut wrote:
Dear Pavel Herrmann,
On Friday 21 of September 2012 17:34:27 Marek Vasut wrote:
Dear Pavel Herrmann,
[...]
blockctrl = AHCI, PIIX... whichever chip you have between SATA and PCI (or generally disk-bus and board-bus)
So this is for sata ? Or will it also by used for SD/USB flash discs?
no, blockctrl will be used for SATA, PATA, SCSI, and anything of the sort (device with several ports, block devices on said ports, ability to send read/write/query commands to devices on ports - definitely not USB, possibly also SD, but you probably want more operations from SD)
Why not USB flash ? Why not SD, what other stuff do you need for that? Is the API not misdesigned then?
you should have a blockdev driver for USB flash and SD, but not blockctrl
I'm lost again. Do I also need a blockdev driver for SATA controller now that I need a blockdev driver for SD card controller ?
you need a blockdev for a blockctrl (see [5/11]), and you need a blockctrl driver for your SATA controller
you can either implement your SD as a blockctrl and use that blockdev, or implement a separate blockdev for your SD card (this is the original intention)
I have not looked at current SD API, but i do recall seeing some non-memory SDIO cards (wifi for example, not sure u-boot supports this though), so i dont think SD should be implemented as a blockctrl
blockdev = disk, partition, SD card
Uh, let's say I understand (even if I don't see the correlation between partition and SD card)
they are an ordered bunch of blocks with a "conventional" filesystem on them
You might want to do RAW reads, so why do you put filesystem into this context?
yes, you can do raw reads, but in most cases you are using a filesystem.
Not true, see how env is stored to these media.
i put filesystem there to differentiate from nand devices (which have a special flash- based filesystems in most cases).
Not true, raw IO on flash media is often used too.
- something that does basic checks
(range, possibility of operation) and submits operations to correct parent (blockctrl, MMC controller, whatnot).
Ascii art might help here greatly (how these pieces fall together). I think I do understand it though.
current code user -> FS -> offset calculation from partition info -> drivers/disk
new code user -> FS -> blockdev -> blockctrl (or USB or SD controller)
So your "blockctrl" should do the USB/SD/whatever muxing.
no, blockdev shoud be the last common part, for SD/USB, you should have a different blockdev driver, that uses USB/SD API for the actual works
blockctrl is just an unified look at whatever now resides in drivers/block
Answer my question, you are contradicting yourself in your answer. So again, does "blockctrl" do the muxing between the downstream drivers (SD blockdev, USB blockdev, SATA blockdev, IDE blockdev ... ) ?
again, no
blockctrl is a common API primarily for SATA/PATA/SCSI controllers, blockdev is an abstraction of any block device, therefore you should have a AHCI blockctrl, piix blockctrl, bfin blockctrl, sil3114 blockctrl (add anything from drivers/block) but a USB blockdev and SD blockdev.
see the difference?
the idea is that there would be no difference when working with SATA/PATA/SCSI (as the commands are almost the same currently), but working with USB drives and SD cards would be a little different (that is from their own separate commands, but not through the blockdev layer)
Pavel Herrmann

Dear Pavel Herrmann,
[...]
you should have a blockdev driver for USB flash and SD, but not blockctrl
I'm lost again. Do I also need a blockdev driver for SATA controller now that I need a blockdev driver for SD card controller ?
you need a blockdev for a blockctrl (see [5/11]), and you need a blockctrl driver for your SATA controller
So "blockctrl" == The controller driver? Viva abbrevs. Rename it to block_controller_driver .
you can either implement your SD as a blockctrl and use that blockdev
SD as in ... SD card or SD host controller ? Use what blockdev ?
, or implement a separate blockdev for your SD card (this is the original intention)
Ok, so the general abstration is to have a block_controller_driver (blockctrl in your parlance) for each and every driver in drivers/block _and_ which provides only basic read/write block for the downstream drivers (block_device) attached to it _and_ proxifies them for particular device type handlers?
Now block_device (blockdev) is either a whole disc, partition, or subpartition. It exports read/write block operations, but to complete them, it uses upcalls into it's parent, yes? These upcalls stop at first block_controller_driver, correct?
The user only ever uses the read/write block operations of the block_device, yes?
I have not looked at current SD API, but i do recall seeing some non-memory SDIO cards (wifi for example, not sure u-boot supports this though), so i dont think SD should be implemented as a blockctrl
They are not. But you should have looked at them since if you don't, that means you ignored fundamental part of the block interface.
But anyway, in case of SD card, the upcalls stop at block_controller_driver, which handles the block IO the specific SD controller way?
> blockdev = disk, partition, SD card
Uh, let's say I understand (even if I don't see the correlation between partition and SD card)
they are an ordered bunch of blocks with a "conventional" filesystem on them
You might want to do RAW reads, so why do you put filesystem into this context?
yes, you can do raw reads, but in most cases you are using a filesystem.
Not true, see how env is stored to these media.
i put filesystem there to differentiate from nand devices (which have a special flash- based filesystems in most cases).
Not true, raw IO on flash media is often used too.
> - something that does basic checks > (range, possibility of operation) and submits operations to > correct > parent (blockctrl, MMC controller, whatnot).
Ascii art might help here greatly (how these pieces fall together). I think I do understand it though.
current code user -> FS -> offset calculation from partition info -> drivers/disk
new code user -> FS -> blockdev -> blockctrl (or USB or SD controller)
So your "blockctrl" should do the USB/SD/whatever muxing.
no, blockdev shoud be the last common part, for SD/USB, you should have a different blockdev driver, that uses USB/SD API for the actual works
blockctrl is just an unified look at whatever now resides in drivers/block
Answer my question, you are contradicting yourself in your answer. So again, does "blockctrl" do the muxing between the downstream drivers (SD blockdev, USB blockdev, SATA blockdev, IDE blockdev ... ) ?
again, no
blockctrl is a common API primarily for SATA/PATA/SCSI controllers, blockdev is an abstraction of any block device, therefore you should have a AHCI blockctrl, piix blockctrl, bfin blockctrl, sil3114 blockctrl (add anything from drivers/block) but a USB blockdev and SD blockdev.
see the difference?
I assume I do, confirm above.
the idea is that there would be no difference when working with SATA/PATA/SCSI (as the commands are almost the same currently), but working with USB drives and SD cards would be a little different (that is from their own separate commands, but not through the blockdev layer)
I see
Pavel Herrmann
Best regards, Marek Vasut

On Friday 21 of September 2012 20:00:10 Marek Vasut wrote:
Dear Pavel Herrmann,
[...]
you should have a blockdev driver for USB flash and SD, but not blockctrl
I'm lost again. Do I also need a blockdev driver for SATA controller now that I need a blockdev driver for SD card controller ?
you need a blockdev for a blockctrl (see [5/11]), and you need a blockctrl driver for your SATA controller
So "blockctrl" == The controller driver? Viva abbrevs. Rename it to block_controller_driver .
thats far too long, dont you think? we only have 80 cols in code...
you can either implement your SD as a blockctrl and use that blockdev
SD as in ... SD card or SD host controller ? Use what blockdev ?
either we say we only have SD memory (and will never ever have other SDIO cards), implement SD controller with blockctrl API (and change it slightly, because SD is inherently flash and therefore has an erase operation)
on the other hand, we could have a separate API for SD controllers (richer than the blockctrl, to eventually suport non-memory SD cards), and then have a device that provides blockdev API on one end, and uses this SD API on the other (much like blockdev_ata in [5/11] does for blockctrl API). this is the original idea; for this reason, blockdev API already has an erase operation, even though blockctrl does not support it.
, or implement a separate blockdev for your SD card (this is the original intention)
Ok, so the general abstration is to have a block_controller_driver (blockctrl in your parlance) for each and every driver in drivers/block
yes
_and_ which provides only basic read/write block for the downstream drivers (block_device) attached to it
yes
_and_ proxifies them for particular device type handlers?
not sure what you mean there. what device type handlers? is that SATA/SCSI/PATA? that should disappear, only reason i have it in code is because i am wrapping old APIs into the new one.
Now block_device (blockdev) is either a whole disc, partition, or subpartition. It exports read/write block operations, but to complete them, it uses upcalls into it's parent, yes?
yes
These upcalls stop at first block_controller_driver, correct?
in case of a hard disk, yes. in case of a USB flash, it uses USB calls to its parent (USB hub or whatever) to complete the task at hand
The user only ever uses the read/write block operations of the block_device, yes?
yes
I have not looked at current SD API, but i do recall seeing some non-memory SDIO cards (wifi for example, not sure u-boot supports this though), so i dont think SD should be implemented as a blockctrl
They are not. But you should have looked at them since if you don't, that means you ignored fundamental part of the block interface.
But anyway, in case of SD card, the upcalls stop at block_controller_driver, which handles the block IO the specific SD controller way?
see above for the options. original idea is no, but it should be possible to implement it that way
> > blockdev = disk, partition, SD card > > Uh, let's say I understand (even if I don't see the correlation > between partition and SD card)
they are an ordered bunch of blocks with a "conventional" filesystem on them
You might want to do RAW reads, so why do you put filesystem into this context?
yes, you can do raw reads, but in most cases you are using a filesystem.
Not true, see how env is stored to these media.
i put filesystem there to differentiate from nand devices (which have a special flash- based filesystems in most cases).
Not true, raw IO on flash media is often used too.
> > - something that does basic checks > > (range, possibility of operation) and submits operations to > > correct > > parent (blockctrl, MMC controller, whatnot). > > Ascii art might help here greatly (how these pieces fall > together). I > think I do understand it though.
current code user -> FS -> offset calculation from partition info -> drivers/disk
new code user -> FS -> blockdev -> blockctrl (or USB or SD controller)
So your "blockctrl" should do the USB/SD/whatever muxing.
no, blockdev shoud be the last common part, for SD/USB, you should have a different blockdev driver, that uses USB/SD API for the actual works
blockctrl is just an unified look at whatever now resides in drivers/block
Answer my question, you are contradicting yourself in your answer. So again, does "blockctrl" do the muxing between the downstream drivers (SD blockdev, USB blockdev, SATA blockdev, IDE blockdev ... ) ?
again, no
blockctrl is a common API primarily for SATA/PATA/SCSI controllers, blockdev is an abstraction of any block device, therefore you should have a AHCI blockctrl, piix blockctrl, bfin blockctrl, sil3114 blockctrl (add anything from drivers/block) but a USB blockdev and SD blockdev.
see the difference?
I assume I do, confirm above.
the idea is that there would be no difference when working with SATA/PATA/SCSI (as the commands are almost the same currently), but working with USB drives and SD cards would be a little different (that is from their own separate commands, but not through the blockdev layer)
I see
Pavel Herrmann

Dear Pavel Herrmann,
On Friday 21 of September 2012 20:00:10 Marek Vasut wrote:
Dear Pavel Herrmann,
[...]
you should have a blockdev driver for USB flash and SD, but not blockctrl
I'm lost again. Do I also need a blockdev driver for SATA controller now that I need a blockdev driver for SD card controller ?
you need a blockdev for a blockctrl (see [5/11]), and you need a blockctrl driver for your SATA controller
So "blockctrl" == The controller driver? Viva abbrevs. Rename it to block_controller_driver .
thats far too long, dont you think? we only have 80 cols in code...
So what? You can abbrev. the variable name, so it won't get in the way. As you can see, I was confused by the name, do you expect others not to be?
you can either implement your SD as a blockctrl and use that blockdev
SD as in ... SD card or SD host controller ? Use what blockdev ?
either we say we only have SD memory (and will never ever have other SDIO cards), implement SD controller with blockctrl API (and change it slightly, because SD is inherently flash and therefore has an erase operation)
on the other hand, we could have a separate API for SD controllers (richer than the blockctrl, to eventually suport non-memory SD cards), and then have a device that provides blockdev API on one end, and uses this SD API on the other (much like blockdev_ata in [5/11] does for blockctrl API). this is the original idea; for this reason, blockdev API already has an erase operation, even though blockctrl does not support it.
, or implement a separate blockdev for your SD card (this is the original intention)
Ok, so the general abstration is to have a block_controller_driver (blockctrl in your parlance) for each and every driver in drivers/block
yes
_and_ which provides only basic read/write block for the downstream drivers (block_device) attached to it
yes
_and_ proxifies them for particular device type handlers?
not sure what you mean there. what device type handlers? is that SATA/SCSI/PATA? that should disappear, only reason i have it in code is because i am wrapping old APIs into the new one.
I mean the particular block_controller_driver instance routes the "read/write block" request from downstream block_device through SATA/SD/SCSI/whatever "library" or "layer" back into itself. But the later "itself" is the implementation of the "library" or "layer" API. Once the library call returns, the "read/write block" operation is complete and the result can be passed back to the downstream "block_device". Yes?
Now block_device (blockdev) is either a whole disc, partition, or subpartition. It exports read/write block operations, but to complete them, it uses upcalls into it's parent, yes?
yes
These upcalls stop at first block_controller_driver, correct?
in case of a hard disk, yes. in case of a USB flash, it uses USB calls to its parent (USB hub or whatever) to complete the task at hand
Let me reformulate -- there is only single block_controller_driver instance the request crosses on it's way up the driver tree. Yes?
[...]
Best regards, Marek Vasut

On Friday 21 of September 2012 21:17:43 Marek Vasut wrote:
Dear Pavel Herrmann,
On Friday 21 of September 2012 20:00:10 Marek Vasut wrote:
Dear Pavel Herrmann,
[...]
you should have a blockdev driver for USB flash and SD, but not blockctrl
I'm lost again. Do I also need a blockdev driver for SATA controller now that I need a blockdev driver for SD card controller ?
you need a blockdev for a blockctrl (see [5/11]), and you need a blockctrl driver for your SATA controller
So "blockctrl" == The controller driver? Viva abbrevs. Rename it to block_controller_driver .
thats far too long, dont you think? we only have 80 cols in code...
So what? You can abbrev. the variable name, so it won't get in the way. As you can see, I was confused by the name, do you expect others not to be?
you can either implement your SD as a blockctrl and use that blockdev
SD as in ... SD card or SD host controller ? Use what blockdev ?
either we say we only have SD memory (and will never ever have other SDIO cards), implement SD controller with blockctrl API (and change it slightly, because SD is inherently flash and therefore has an erase operation)
on the other hand, we could have a separate API for SD controllers (richer than the blockctrl, to eventually suport non-memory SD cards), and then have a device that provides blockdev API on one end, and uses this SD API on the other (much like blockdev_ata in [5/11] does for blockctrl API). this is the original idea; for this reason, blockdev API already has an erase operation, even though blockctrl does not support it.
, or implement a separate blockdev for your SD card (this is the original intention)
Ok, so the general abstration is to have a block_controller_driver (blockctrl in your parlance) for each and every driver in drivers/block
yes
_and_ which provides only basic read/write block for the downstream drivers (block_device) attached to it
yes
_and_ proxifies them for particular device type handlers?
not sure what you mean there. what device type handlers? is that SATA/SCSI/PATA? that should disappear, only reason i have it in code is because i am wrapping old APIs into the new one.
I mean the particular block_controller_driver instance routes the "read/write block" request from downstream block_device through SATA/SD/SCSI/whatever "library" or "layer" back into itself. But the later "itself" is the implementation of the "library" or "layer" API. Once the library call returns, the "read/write block" operation is complete and the result can be passed back to the downstream "block_device". Yes?
in that case no, the block controller should directly take care of the call, without it being translated into some form it likes better for its particular interface.
the translation is udes as a mechanism to support old code, but eventually there should be none, and the drivers should take a request from block_device and take care of it (probably by using memory-mapped access, or however you communicate with that chip).
there might be a shared library for old IDE drivers though, as they are more like a shared code with driver (and board)-specific hooks.
Now block_device (blockdev) is either a whole disc, partition, or subpartition. It exports read/write block operations, but to complete them, it uses upcalls into it's parent, yes?
yes
These upcalls stop at first block_controller_driver, correct?
in case of a hard disk, yes. in case of a USB flash, it uses USB calls to its parent (USB hub or whatever) to complete the task at hand
Let me reformulate -- there is only single block_controller_driver instance the request crosses on it's way up the driver tree. Yes?
one or none - requests on USB flashes should not pass through block_controller_driver.
every child of block_controller should be a block_device (not necessarily the other way around), so there is no way you pass more instances block_controller on your way up.

Dear Pavel Herrmann,
[...]
I mean the particular block_controller_driver instance routes the "read/write block" request from downstream block_device through SATA/SD/SCSI/whatever "library" or "layer" back into itself. But the later "itself" is the implementation of the "library" or "layer" API. Once the library call returns, the "read/write block" operation is complete and the result can be passed back to the downstream "block_device". Yes?
in that case no, the block controller should directly take care of the call, without it being translated into some form it likes better for its particular interface.
This is entirely wrong. This would mean for example for SD drivers, to implement whole SD stack.
the translation is udes as a mechanism to support old code, but eventually there should be none, and the drivers should take a request from block_device and take care of it (probably by using memory-mapped access, or however you communicate with that chip).
there might be a shared library for old IDE drivers though, as they are more like a shared code with driver (and board)-specific hooks.
Now block_device (blockdev) is either a whole disc, partition, or subpartition. It exports read/write block operations, but to complete them, it uses upcalls into it's parent, yes?
yes
These upcalls stop at first block_controller_driver, correct?
in case of a hard disk, yes. in case of a USB flash, it uses USB calls to its parent (USB hub or whatever) to complete the task at hand
Let me reformulate -- there is only single block_controller_driver instance the request crosses on it's way up the driver tree. Yes?
one or none - requests on USB flashes should not pass through block_controller_driver.
Uh, what do they pass into then ?
every child of block_controller should be a block_device (not necessarily the other way around
I doubt it's even possible to be the other way around.
), so there is no way you pass more instances block_controller on your way up.
Ok, let me explain again. Let's look at the USB case to make it more real-world- ish. Imagine you have a thumb drive with 2 partitions. Thus you have two instances of struct block_device [denote BDp] for the partitions and one more for the whole disc [denote BDd]. When you read from partition, you end up poking BDp, which pushes the request up into BDd. This in turn calls USB-flashdisc- block_controller_driver [call it UFc]. For flash disc to read data, it needs to do some USB transfers. These are provided by USB host controller [UHC]. Thus you need some glue between UHC and UFc ... this is what I'm talking about.
Ok, I see the issue at hand. In case of a "regular drive", this implements the IO directly. In case of SD, this is a proxy object which interfaces with some SD-library and prepares the SD commands and then pushes that up into the controller to do the job? Same thing for USB flashes ?
Best regards, Marek Vasut

On Friday 21 of September 2012 23:11:57 Marek Vasut wrote:
Dear Pavel Herrmann,
[...]
I mean the particular block_controller_driver instance routes the "read/write block" request from downstream block_device through SATA/SD/SCSI/whatever "library" or "layer" back into itself. But the later "itself" is the implementation of the "library" or "layer" API. Once the library call returns, the "read/write block" operation is complete and the result can be passed back to the downstream "block_device". Yes?
in that case no, the block controller should directly take care of the call, without it being translated into some form it likes better for its particular interface.
This is entirely wrong. This would mean for example for SD drivers, to implement whole SD stack.
no one is forbiding you from having a shared library of common routines, but you should not force anyone to use it.
the translation is udes as a mechanism to support old code, but eventually there should be none, and the drivers should take a request from block_device and take care of it (probably by using memory-mapped access, or however you communicate with that chip).
there might be a shared library for old IDE drivers though, as they are more like a shared code with driver (and board)-specific hooks.
Now block_device (blockdev) is either a whole disc, partition, or subpartition. It exports read/write block operations, but to complete them, it uses upcalls into it's parent, yes?
yes
These upcalls stop at first block_controller_driver, correct?
in case of a hard disk, yes. in case of a USB flash, it uses USB calls to its parent (USB hub or whatever) to complete the task at hand
Let me reformulate -- there is only single block_controller_driver instance the request crosses on it's way up the driver tree. Yes?
one or none - requests on USB flashes should not pass through block_controller_driver.
Uh, what do they pass into then ?
their parent (an USB hub)
every child of block_controller should be a block_device (not necessarily the other way around
I doubt it's even possible to be the other way around.
), so there is no way you pass more instances block_controller on your way up.
Ok, let me explain again. Let's look at the USB case to make it more real-world- ish. Imagine you have a thumb drive with 2 partitions. Thus you have two instances of struct block_device [denote BDp] for the partitions and one more for the whole disc [denote BDd]. When you read from partition, you end up poking BDp, which pushes the request up into BDd. This in turn calls USB-flashdisc- block_controller_driver [call it UFc]. For flash disc to read data, it needs to do some USB transfers. These are provided by USB host controller [UHC]. Thus you need some glue between UHC and UFc ... this is what I'm talking about.
there should be no "UFc", your "BDd" driver should talk directly to your "UHC" (a driver that has blockdev API on one end, USB on the other)
Ok, I see the issue at hand. In case of a "regular drive", this implements the IO directly. In case of SD, this is a proxy object which interfaces with some SD-library and prepares the SD commands and then pushes that up into the controller to do the job? Same thing for USB flashes ?
not every block device will have a block controller as a parent (or parent-of- parent in case of a partition). there would be a blockdev-usb that has a USB hub as a parent, and a blockdev-mmc, that has a mmc/sdio controller as a parent.
so basically what you mean, without the block_controller in the middle - please note that the block_device API is actually richer than the block_controller API (has erase) for exactly this reason.
Pavel Herrmann

Dear Pavel Herrmann,
[...]
one or none - requests on USB flashes should not pass through block_controller_driver.
Uh, what do they pass into then ?
their parent (an USB hub)
block_device instance (aka. partition/disk) directly connected to USB hub instance does not seem right.
every child of block_controller should be a block_device (not necessarily the other way around
I doubt it's even possible to be the other way around.
), so there is no way you pass more instances block_controller on your way up.
Ok, let me explain again. Let's look at the USB case to make it more real-world- ish. Imagine you have a thumb drive with 2 partitions. Thus you have two instances of struct block_device [denote BDp] for the partitions and one more for the whole disc [denote BDd]. When you read from partition, you end up poking BDp, which pushes the request up into BDd. This in turn calls USB-flashdisc- block_controller_driver [call it UFc]. For flash disc to read data, it needs to do some USB transfers. These are provided by USB host controller [UHC]. Thus you need some glue between UHC and UFc ... this is what I'm talking about.
there should be no "UFc", your "BDd" driver should talk directly to your "UHC"
So my generic partition implementation (BDd) would have to implement USB flashdisc stuff, correct? This makes no sense.
(a driver that has blockdev API on one end, USB on the other)
Ok, so how would this work, every partition implementation implements upcalls for all USB, SCSI, SATA, IDE, SD, ... and gazilion other types of drive it can sit on?
Ok, I see the issue at hand. In case of a "regular drive", this implements the IO directly. In case of SD, this is a proxy object which interfaces with some SD-library and prepares the SD commands and then pushes that up into the controller to do the job? Same thing for USB flashes ?
not every block device will have a block controller as a parent (or parent-of- parent in case of a partition). there would be a blockdev-usb that has a USB hub as a parent, and a blockdev-mmc, that has a mmc/sdio controller as a parent.
So you would have a specific partition implementation for SD, SATA, IDE, SCSI, USB ... ? This is flawed.
The partition should be a generic "thing" which knows nothing about where it's sitting at. So is the whole drive, same thing, it just has partitions hooked under it.
I'd expect a "block_controller" to be the proxy object under which the block_device representing the disc is connected. And this "block_controller" to be proxifying the requests to the respective drivers (be it SD, SATA, whatever).
so basically what you mean, without the block_controller in the middle - please note that the block_device API is actually richer than the block_controller API (has erase) for exactly this reason.
Pavel Herrmann
Best regards, Marek Vasut

On Saturday 22 of September 2012 02:09:15 Marek Vasut wrote:
Dear Pavel Herrmann,
[...]
one or none - requests on USB flashes should not pass through block_controller_driver.
Uh, what do they pass into then ?
their parent (an USB hub)
block_device instance (aka. partition/disk) directly connected to USB hub instance does not seem right.
why?
every child of block_controller should be a block_device (not necessarily the other way around
I doubt it's even possible to be the other way around.
), so there is no way you pass more instances block_controller on your way up.
Ok, let me explain again. Let's look at the USB case to make it more real-world- ish. Imagine you have a thumb drive with 2 partitions. Thus you have two instances of struct block_device [denote BDp] for the partitions and one more for the whole disc [denote BDd]. When you read from partition, you end up poking BDp, which pushes the request up into BDd. This in turn calls USB-flashdisc- block_controller_driver [call it UFc]. For flash disc to read data, it needs to do some USB transfers. These are provided by USB host controller [UHC]. Thus you need some glue between UHC and UFc ... this is what I'm talking about.
there should be no "UFc", your "BDd" driver should talk directly to your "UHC"
So my generic partition implementation (BDd) would have to implement USB flashdisc stuff, correct? This makes no sense.
no. your generic USB flash would have to implement USB flashdisc stuff, your generic partition implements block_device operations on top of other block_device (aka diosk, memory card, USB flash)
please read the letters you came up with right. (maybe after getting some sleep by the looks of it)
the point you are not getting is that there should be more block_device drivers than there is now - one for partitions, one for disk, one for USB flash, one for SD and so on, each one using a different parent API
(a driver that has blockdev API on one end, USB on the other)
Ok, so how would this work, every partition implementation implements upcalls for all USB, SCSI, SATA, IDE, SD, ... and gazilion other types of drive it can sit on?
no, partition only implements call onto another block device
Ok, I see the issue at hand. In case of a "regular drive", this implements the IO directly. In case of SD, this is a proxy object which interfaces with some SD-library and prepares the SD commands and then pushes that up into the controller to do the job? Same thing for USB flashes ?
not every block device will have a block controller as a parent (or parent-of- parent in case of a partition). there would be a blockdev-usb that has a USB hub as a parent, and a blockdev-mmc, that has a mmc/sdio controller as a parent.
So you would have a specific partition implementation for SD, SATA, IDE, SCSI, USB ... ? This is flawed.
no, read above
The partition should be a generic "thing" which knows nothing about where it's sitting at. So is the whole drive, same thing, it just has partitions hooked under it.
I'd expect a "block_controller" to be the proxy object under which the block_device representing the disc is connected. And this "block_controller" to be proxifying the requests to the respective drivers (be it SD, SATA, whatever).
your idea is wrong - you expect there will always be only one block_device representig a "disk", and all the proxy would be done by the block_controller above it. this is not true
Pavel Herrmann

Dear Pavel Herrmann,
On Saturday 22 of September 2012 02:09:15 Marek Vasut wrote:
Dear Pavel Herrmann,
[...]
one or none - requests on USB flashes should not pass through block_controller_driver.
Uh, what do they pass into then ?
their parent (an USB hub)
block_device instance (aka. partition/disk) directly connected to USB hub instance does not seem right.
why?
It doesn't make sense ... you need some kind of interim controller (like the chip between the USB and NAND in the thumbdrive.
every child of block_controller should be a block_device (not necessarily the other way around
I doubt it's even possible to be the other way around.
), so there is no way you pass more instances block_controller on your way up.
Ok, let me explain again. Let's look at the USB case to make it more real-world- ish. Imagine you have a thumb drive with 2 partitions. Thus you have two instances of struct block_device [denote BDp] for the partitions and one more for the whole disc [denote BDd]. When you read from partition, you end up poking BDp, which pushes the request up into BDd. This in turn calls USB-flashdisc- block_controller_driver [call it UFc]. For flash disc to read data, it needs to do some USB transfers. These are provided by USB host controller [UHC]. Thus you need some glue between UHC and UFc ... this is what I'm talking about.
there should be no "UFc", your "BDd" driver should talk directly to your "UHC"
So my generic partition implementation (BDd) would have to implement USB flashdisc stuff, correct? This makes no sense.
no. your generic USB flash would have to implement USB flashdisc stuff, your generic partition implements block_device operations on top of other block_device (aka diosk, memory card, USB flash)
Ok, so in your parlance, the block_device is either "partition/disc" or a "SD card controller driver" or "USB flashdisc driver" ? You are mixing these two things together?
please read the letters you came up with right. (maybe after getting some sleep by the looks of it)
I'd prefer to read some documented code.
the point you are not getting is that there should be more block_device drivers than there is now - one for partitions, one for disk, one for USB flash, one for SD and so on, each one using a different parent API
Ok, now I understand your intention. Split it -- make partitions separate, since this is flat out confusing!
Make partitions / whole disc a separate thing ... Make USB flash driver / SD card driver / etc. another thing ...
You can not mix these two together, it makes no sense.
(a driver that has blockdev API on one end, USB on the other)
Ok, so how would this work, every partition implementation implements upcalls for all USB, SCSI, SATA, IDE, SD, ... and gazilion other types of drive it can sit on?
no, partition only implements call onto another block device
Ok, I see the issue at hand. In case of a "regular drive", this implements the IO directly. In case of SD, this is a proxy object which interfaces with some SD-library and prepares the SD commands and then pushes that up into the controller to do the job? Same thing for USB flashes ?
not every block device will have a block controller as a parent (or parent-of- parent in case of a partition). there would be a blockdev-usb that has a USB hub as a parent, and a blockdev-mmc, that has a mmc/sdio controller as a parent.
So you would have a specific partition implementation for SD, SATA, IDE, SCSI, USB ... ? This is flawed.
no, read above
The partition should be a generic "thing" which knows nothing about where it's sitting at. So is the whole drive, same thing, it just has partitions hooked under it.
I'd expect a "block_controller" to be the proxy object under which the block_device representing the disc is connected. And this "block_controller" to be proxifying the requests to the respective drivers (be it SD, SATA, whatever).
your idea is wrong - you expect there will always be only one block_device representig a "disk", and all the proxy would be done by the block_controller above it. this is not true
Any amount of "block_device" can be connected under the "block_controller". Given that "block_device" is a partition/disc _only_ and "block_controller" is the interface driver ... which is probably not true, so you lost me again.
I stop here, this discussion leads nowhere. Can you please write proper documentation from which I can get an idea how this exactly works? Ideally with diagrams ... doc/driver-model/UDM-block.txt would be a good place.
Pavel Herrmann
Best regards, Marek Vasut

On Saturday 22 of September 2012 15:33:10 Marek Vasut wrote:
Dear Pavel Herrmann,
On Saturday 22 of September 2012 02:09:15 Marek Vasut wrote:
Dear Pavel Herrmann,
[...]
one or none - requests on USB flashes should not pass through block_controller_driver.
Uh, what do they pass into then ?
their parent (an USB hub)
block_device instance (aka. partition/disk) directly connected to USB hub instance does not seem right.
why?
It doesn't make sense ... you need some kind of interim controller (like the chip between the USB and NAND in the thumbdrive.
yes, but you dont make drivers for every chip there is, instead the chips understand a common language, where you describe block operations by USB transfers, and that is exactly what saib block_device_usb_flash would do.
every child of block_controller should be a block_device (not necessarily the other way around
I doubt it's even possible to be the other way around.
), so there is no way you pass more instances block_controller on your way up.
Ok, let me explain again. Let's look at the USB case to make it more real-world- ish. Imagine you have a thumb drive with 2 partitions. Thus you have two instances of struct block_device [denote BDp] for the partitions and one more for the whole disc [denote BDd]. When you read from partition, you end up poking BDp, which pushes the request up into BDd. This in turn calls USB-flashdisc- block_controller_driver [call it UFc]. For flash disc to read data, it needs to do some USB transfers. These are provided by USB host controller [UHC]. Thus you need some glue between UHC and UFc ... this is what I'm talking about.
there should be no "UFc", your "BDd" driver should talk directly to your "UHC"
So my generic partition implementation (BDd) would have to implement USB flashdisc stuff, correct? This makes no sense.
no. your generic USB flash would have to implement USB flashdisc stuff, your generic partition implements block_device operations on top of other block_device (aka diosk, memory card, USB flash)
Ok, so in your parlance, the block_device is either "partition/disc" or a "SD card controller driver" or "USB flashdisc driver" ? You are mixing these two things together?
please read the letters you came up with right. (maybe after getting some sleep by the looks of it)
I'd prefer to read some documented code.
im missing the point of this. you stateted that you have a partition "BDp" and a disk "BDd". i said your "BDd" will sit above USB API, and you stared ranting about partitions implementing USB stuff, which was totaly off.
the point you are not getting is that there should be more block_device drivers than there is now - one for partitions, one for disk, one for USB flash, one for SD and so on, each one using a different parent API
Ok, now I understand your intention. Split it -- make partitions separate, since this is flat out confusing!
Make partitions / whole disc a separate thing ... Make USB flash driver / SD card driver / etc. another thing ...
You can not mix these two together, it makes no sense.
well, disks, SD cards and USB flashes are one thing at the moment (see struct block_dev_desc). i am only adding partitions to the mix.
(a driver that has blockdev API on one end, USB on the other)
Ok, so how would this work, every partition implementation implements upcalls for all USB, SCSI, SATA, IDE, SD, ... and gazilion other types of drive it can sit on?
no, partition only implements call onto another block device
Ok, I see the issue at hand. In case of a "regular drive", this implements the IO directly. In case of SD, this is a proxy object which interfaces with some SD-library and prepares the SD commands and then pushes that up into the controller to do the job? Same thing for USB flashes ?
not every block device will have a block controller as a parent (or parent-of- parent in case of a partition). there would be a blockdev-usb that has a USB hub as a parent, and a blockdev-mmc, that has a mmc/sdio controller as a parent.
So you would have a specific partition implementation for SD, SATA, IDE, SCSI, USB ... ? This is flawed.
no, read above
The partition should be a generic "thing" which knows nothing about where it's sitting at. So is the whole drive, same thing, it just has partitions hooked under it.
I'd expect a "block_controller" to be the proxy object under which the block_device representing the disc is connected. And this "block_controller" to be proxifying the requests to the respective drivers (be it SD, SATA, whatever).
your idea is wrong - you expect there will always be only one block_device representig a "disk", and all the proxy would be done by the block_controller above it. this is not true
Any amount of "block_device" can be connected under the "block_controller". Given that "block_device" is a partition/disc _only_ and "block_controller" is the interface driver ... which is probably not true, so you lost me again.
block controller muxes several disks onto one device (like a SATA controller does). you dont need this on USB drives and MMC cards, because you have a controller that can access multiple devices already (like the USB root hub)
if you took a look at the code you might see the point - the only thing you add by haveing a block_controller is a "port" parameter to every function, which you dont need in SD cards or USB flashes
I stop here, this discussion leads nowhere. Can you please write proper documentation from which I can get an idea how this exactly works? Ideally with diagrams ... doc/driver-model/UDM-block.txt would be a good place.
Pavel Herrmann
Best regards, Marek Vasut

On Saturday 22 September 2012 15:59:46 Pavel Herrmann wrote:
On Saturday 22 of September 2012 15:33:10 Marek Vasut wrote:
Dear Pavel Herrmann,
On Saturday 22 of September 2012 02:09:15 Marek Vasut wrote:
Dear Pavel Herrmann,
[...]
> one or none - requests on USB flashes should not pass through > block_controller_driver.
Uh, what do they pass into then ?
their parent (an USB hub)
block_device instance (aka. partition/disk) directly connected to USB hub instance does not seem right.
why?
It doesn't make sense ... you need some kind of interim controller (like the chip between the USB and NAND in the thumbdrive.
yes, but you dont make drivers for every chip there is, instead the chips understand a common language, where you describe block operations by USB transfers, and that is exactly what saib block_device_usb_flash would do.
> every child of block_controller should be a block_device (not > necessarily the other way around
I doubt it's even possible to be the other way around.
> ), so there is no way you pass more instances > block_controller on your way up.
Ok, let me explain again. Let's look at the USB case to make it more real-world- ish. Imagine you have a thumb drive with 2 partitions. Thus you have two instances of struct block_device [denote BDp] for the partitions and one more for the whole disc [denote BDd]. When you read from partition, you end up poking BDp, which pushes the request up into BDd. This in turn calls USB-flashdisc- block_controller_driver [call it UFc]. For flash disc to read data, it needs to do some USB transfers. These are provided by USB host controller [UHC]. Thus you need some glue between UHC and UFc ... this is what I'm talking about.
there should be no "UFc", your "BDd" driver should talk directly to your "UHC"
So my generic partition implementation (BDd) would have to implement USB flashdisc stuff, correct? This makes no sense.
no. your generic USB flash would have to implement USB flashdisc stuff, your generic partition implements block_device operations on top of other block_device (aka diosk, memory card, USB flash)
Ok, so in your parlance, the block_device is either "partition/disc" or a "SD card controller driver" or "USB flashdisc driver" ? You are mixing these two things together?
please read the letters you came up with right. (maybe after getting some sleep by the looks of it)
I'd prefer to read some documented code.
im missing the point of this. you stateted that you have a partition "BDp" and a disk "BDd". i said your "BDd" will sit above USB API, and you stared ranting about partitions implementing USB stuff, which was totaly off.
the point you are not getting is that there should be more block_device drivers than there is now - one for partitions, one for disk, one for USB flash, one for SD and so on, each one using a different parent API
Ok, now I understand your intention. Split it -- make partitions separate, since this is flat out confusing!
Make partitions / whole disc a separate thing ... Make USB flash driver / SD card driver / etc. another thing ...
You can not mix these two together, it makes no sense.
well, disks, SD cards and USB flashes are one thing at the moment (see struct block_dev_desc). i am only adding partitions to the mix.
(a driver that has blockdev API on one end, USB on the other)
Ok, so how would this work, every partition implementation implements upcalls for all USB, SCSI, SATA, IDE, SD, ... and gazilion other types of drive it can sit on?
no, partition only implements call onto another block device
Ok, I see the issue at hand. In case of a "regular drive", this implements the IO directly. In case of SD, this is a proxy object which interfaces with some SD-library and prepares the SD commands and then pushes that up into the controller to do the job? Same thing for USB flashes ?
not every block device will have a block controller as a parent (or parent-of- parent in case of a partition). there would be a blockdev-usb that has a USB hub as a parent, and a blockdev-mmc, that has a mmc/sdio controller as a parent.
So you would have a specific partition implementation for SD, SATA, IDE, SCSI, USB ... ? This is flawed.
no, read above
The partition should be a generic "thing" which knows nothing about where it's sitting at. So is the whole drive, same thing, it just has partitions hooked under it.
I'd expect a "block_controller" to be the proxy object under which the block_device representing the disc is connected. And this "block_controller" to be proxifying the requests to the respective drivers (be it SD, SATA, whatever).
your idea is wrong - you expect there will always be only one block_device representig a "disk", and all the proxy would be done by the block_controller above it. this is not true
Any amount of "block_device" can be connected under the "block_controller". Given that "block_device" is a partition/disc _only_ and "block_controller" is the interface driver ... which is probably not true, so you lost me again.
block controller muxes several disks onto one device (like a SATA controller does). you dont need this on USB drives and MMC cards, because you have a controller that can access multiple devices already (like the USB root hub)
if you took a look at the code you might see the point - the only thing you add by haveing a block_controller is a "port" parameter to every function, which you dont need in SD cards or USB flashes
For all who are reading this, I have been enlightened with the knowledge that there can be multiple MMC/SD cards on one MMC controller, as there can be multiple hard drives behind one USB device. This is something this code was indeed not designed for, and i apologize for the misunderstanding.
Pavel Herrmann

On Fri, Sep 21, 2012 at 1:07 AM, Pavel Herrmann morpheus.ibis@gmail.com wrote:
This core will register all block devices (disk, cards, partitons) and provide unfied access to them, instead of current method with device + partition offset
Signed-off-by: Pavel Herrmann morpheus.ibis@gmail.com
Makefile | 1 + drivers/blockdev/Makefile | 42 ++++++++++++++++ include/dm/blockdev.h | 121 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 164 insertions(+) create mode 100644 drivers/blockdev/Makefile create mode 100644 include/dm/blockdev.h
<snip>
+struct blockdev_ops {
lbaint_t (*read)(struct instance *inst, lbaint_t start,
lbaint_t blkcnt, void *buffer);
lbaint_t (*write)(struct instance *inst, lbaint_t start,
lbaint_t blkcnt, void *buffer);
lbaint_t (*erase)(struct instance *inst, lbaint_t start,
lbaint_t blkcnt);
lbaint_t is little "cryptic". Any better name suggestions?
Regards, Vikram

Hi
On Friday 21 of September 2012 02:19:00 Vikram Narayanan wrote:
On Fri, Sep 21, 2012 at 1:07 AM, Pavel Herrmann morpheus.ibis@gmail.com
wrote:
This core will register all block devices (disk, cards, partitons) and provide unfied access to them, instead of current method with device + partition offset
Signed-off-by: Pavel Herrmann morpheus.ibis@gmail.com
Makefile | 1 + drivers/blockdev/Makefile | 42 ++++++++++++++++ include/dm/blockdev.h | 121 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 164 insertions(+) create mode 100644 drivers/blockdev/Makefile create mode 100644 include/dm/blockdev.h
<snip>
+struct blockdev_ops {
lbaint_t (*read)(struct instance *inst, lbaint_t start,
lbaint_t blkcnt, void *buffer);
lbaint_t (*write)(struct instance *inst, lbaint_t start,
lbaint_t blkcnt, void *buffer);
lbaint_t (*erase)(struct instance *inst, lbaint_t start,
lbaint_t blkcnt);
lbaint_t is little "cryptic". Any better name suggestions?
lbaint_t is an unsigned 32bit or 64bit number, depending on state of CONFIG_LBA48.
It was chosen because some parts of current block code use it as well, but we can pretty much replace it with size_t (and assume CONFIG_LBA48 is always on)
Pavel Herrmann

Dear Pavel Herrmann,
Hi
On Friday 21 of September 2012 02:19:00 Vikram Narayanan wrote:
On Fri, Sep 21, 2012 at 1:07 AM, Pavel Herrmann morpheus.ibis@gmail.com
wrote:
This core will register all block devices (disk, cards, partitons) and provide unfied access to them, instead of current method with device + partition offset
Signed-off-by: Pavel Herrmann morpheus.ibis@gmail.com
Makefile | 1 + drivers/blockdev/Makefile | 42 ++++++++++++++++ include/dm/blockdev.h | 121 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 164 insertions(+) create mode 100644 drivers/blockdev/Makefile create mode 100644 include/dm/blockdev.h
<snip>
+struct blockdev_ops {
lbaint_t (*read)(struct instance *inst, lbaint_t start,
lbaint_t blkcnt, void *buffer);
lbaint_t (*write)(struct instance *inst, lbaint_t start,
lbaint_t blkcnt, void *buffer);
lbaint_t (*erase)(struct instance *inst, lbaint_t start,
lbaint_t blkcnt);
lbaint_t is little "cryptic". Any better name suggestions?
lbaint_t is an unsigned 32bit or 64bit number, depending on state of CONFIG_LBA48.
It was chosen because some parts of current block code use it as well, but we can pretty much replace it with size_t (and assume CONFIG_LBA48 is always on)
lbaint_t seems ok indeed.
Pavel Herrmann
Best regards, Marek Vasut

Enable blockdev core to automatically create partitions based on DOS partition table. This code is based on /disk/, and should eventually replace it.
Signed-off-by: Pavel Herrmann morpheus.ibis@gmail.com --- drivers/blockdev/Makefile | 1 + drivers/blockdev/core.c | 752 +++++++++++++++++++++++++++++++ drivers/blockdev/part_types/part_dos.c | 148 ++++++ drivers/blockdev/part_types/part_dos.h | 49 ++ drivers/blockdev/part_types/part_types.h | 34 ++ 5 files changed, 984 insertions(+) create mode 100644 drivers/blockdev/core.c create mode 100644 drivers/blockdev/part_types/part_dos.c create mode 100644 drivers/blockdev/part_types/part_dos.h create mode 100644 drivers/blockdev/part_types/part_types.h
diff --git a/drivers/blockdev/Makefile b/drivers/blockdev/Makefile index 693e236..a988924 100644 --- a/drivers/blockdev/Makefile +++ b/drivers/blockdev/Makefile @@ -22,6 +22,7 @@ include $(TOPDIR)/config.mk LIB := $(obj)libblockdev.o
COBJS-${CONFIG_DM_BLOCK} := core.o +COBJS-${CONFIG_DOS_PARTITION} += part_types/part_dos.o
COBJS := $(COBJS-y) SRCS := $(COBJS:.o=.c) diff --git a/drivers/blockdev/core.c b/drivers/blockdev/core.c new file mode 100644 index 0000000..bf1c70d --- /dev/null +++ b/drivers/blockdev/core.c @@ -0,0 +1,752 @@ +/* + * (C) Copyright 2012 + * Pavel Herrmann morpheus.ibis@gmail.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <dm/blockdev.h> +#include <dm/manager.h> +#include <malloc.h> +#include "part_types/part_types.h" + +static const char * const blockdev_name[] = {"unk", "unk", "ata", "sd", "usb"}; +static const char * const iftype_name[] = {"unknown", "-", "ATAPI", "SD/MMC", + "USB"}; + +#define BLOCKDEV_PARTITION_SEPARATOR ':' + +#define BLOCKDEV_IFTYPE_BITS 4 +#define BLOCKDEV_IFTYPE_COUNT (1<<BLOCKDEV_IFTYPE_BITS) +#define BLOCKDEV_IFTYPE_MAX BLOCKDEV_IFTYPE_COUNT-1 + +struct blockdev_id { + struct { + unsigned type:BLOCKDEV_IFTYPE_BITS; + unsigned number:(16-BLOCKDEV_IFTYPE_BITS); + } disk; + unsigned partition:16; +}; + +static struct blockdev_id invalid_id = {{0xf, 0xfff}, 0xffff}; +static struct blockdev_id empty_id = {{0x0, 0x0}, 0x0}; + +static inline int id_cmp(const struct blockdev_id *left, + const struct blockdev_id *right) +{ + return memcmp(left, right, sizeof(struct blockdev_id)); +} + +struct blockdev_core_entry { + struct list_head list; + struct instance *instance; + struct blockdev_ops *ops; + struct blockdev_id name; +}; + +struct blockdev_core_private { + /* Put cache here */ +}; + +struct bdid_instance_pair { + struct blockdev_id id; + struct instance *inst; +}; + +static struct blockdev_core_entry *get_entry_by_instance(struct instance *i) +{ + struct blockdev_core_entry *tmp; + struct core_instance *core = get_core_instance(CORE_BLOCKDEV); + + if (!core) + return NULL; + + list_for_each_entry(tmp, &core->succ, list) + if (tmp->instance == i) + return tmp; + + return NULL; +} + +static struct blockdev_core_entry *get_entry_by_id(struct blockdev_id id) +{ + struct blockdev_core_entry *tmp; + struct core_instance *core = get_core_instance(CORE_BLOCKDEV); + + if (!core) + return NULL; + + list_for_each_entry(tmp, &core->succ, list) + if (!id_cmp(&tmp->name, &id)) + return tmp; + + return NULL; +} + +static inline int try_match_name(enum blockdev_iftype type, + struct blockdev_id *id, char **name) +{ + int len = strlen(blockdev_name[type]); + + if (!strncmp(*name, blockdev_name[type], len)) { + id->disk.type = type; + *name += len; + return 0; + } + return 1; +} + +static struct blockdev_id get_id_from_name(char *name) +{ + struct blockdev_id disk_id = empty_id; + + if (!try_match_name(BLOCKDEV_IFTYPE_UNKNOWN, &disk_id, &name)) + goto get_number; + if (!try_match_name(BLOCKDEV_IFTYPE_ATA, &disk_id, &name)) + goto get_number; + if (!try_match_name(BLOCKDEV_IFTYPE_SD, &disk_id, &name)) + goto get_number; + if (!try_match_name(BLOCKDEV_IFTYPE_USB, &disk_id, &name)) + goto get_number; + + return invalid_id; + +get_number: + /* get disk number from name */ + if ((*name < '0') || (*name > '9')) + return invalid_id; + + disk_id.disk.number *= 10; + disk_id.disk.number += (*name-'0'); + name++; + + switch (*name) { + case 0: + return disk_id; + case BLOCKDEV_PARTITION_SEPARATOR: + name += 1; + goto get_part; + default: + goto get_number; + } + return invalid_id; + +get_part: + /* get partition number fron name */ + if ((*name < '0') || (*name > '9')) + return invalid_id; + + disk_id.partition *= 10; + disk_id.partition += (*name-'0'); + name++; + + switch (*name) { + case 0: + return disk_id; + default: + goto get_part; + } + + return invalid_id; +} + +static int get_free_index(struct core_instance *core, enum blockdev_iftype type) +{ + int retval = 0; + struct blockdev_core_entry *entry; + + list_for_each_entry(entry, &core->succ, list) { + if ((entry->name.disk.type == type) && + (entry->name.disk.number >= retval)) + retval = entry->name.disk.number + 1; + } + + return retval; +} + +static struct blockdev_id create_id_from_hint(struct core_instance *core, + struct instance *dev, void* data) +{ + struct blockdev_id retval = empty_id; + struct blockdev_core_entry *entry; + struct blockdev_core_hint *hint = data; + + /* no hint means we have no idea what type of device we have */ + if (!hint) + retval.disk.type = BLOCKDEV_IFTYPE_UNKNOWN; + else { + /* for a partition, we find its parent and use its name */ + if (hint->iftype == BLOCKDEV_IFTYPE_PARTITION) { + entry = get_entry_by_instance(dev->bus); + retval.disk = entry->name.disk; + retval.partition = hint->part_number; + return retval; + /* if we have a valid hint for a disk, get a free index */ + } else { + retval.disk.type = hint->iftype; + retval.disk.number = get_free_index(core, hint->iftype); + retval.partition = 0; + } + } + + return retval; +} + +/* Core API functions */ +static int get_count(struct core_instance *core) +{ + int cnt = 0; + struct blockdev_core_entry *entry = NULL; + + list_for_each_entry(entry, &core->succ, list) + cnt++; + + return cnt; +} + +static struct instance *get_child(struct core_instance *core, int index) +{ + struct blockdev_core_entry *entry = NULL; + + list_for_each_entry(entry, &core->succ, list) { + if (!index) + return entry->instance; + index--; + } + + return NULL; +} + +static int bind(struct core_instance *core, struct instance *dev, void *ops, + void *data) +{ + struct blockdev_core_entry *entry; + + if (ops == NULL) + return -EINVAL; + + entry = malloc(sizeof(*entry)); + if (entry == NULL) + return -ENOMEM; + + INIT_LIST_HEAD(&entry->list); + entry->instance = dev; + entry->ops = ops; + entry->name = create_id_from_hint(core, dev, data); + list_add_tail(&entry->list, &core->succ); + + return 0; +} + +static int unbind(struct core_instance *core, struct instance *dev) +{ + struct blockdev_core_entry *entry, *n; + + list_for_each_entry_safe(entry, n, &core->succ, list) { + if (entry->instance == dev) { + list_del(&entry->list); + free(entry); + } + } + + return 0; +} + +static int replace(struct core_instance *core, struct instance *new, + struct instance *old) +{ + struct blockdev_core_entry *entry = get_entry_by_instance(old); + + if (!entry) + return -ENOENT; + + entry->instance = new; + + return 0; +} + +static int init(struct core_instance *core) +{ + INIT_LIST_HEAD(&core->succ); + core->private_data = NULL; + + return 0; +} + +static int reloc(struct core_instance *core, struct core_instance *old) +{ + struct blockdev_core_entry *entry, *new; + + /* no private_data to copy, yet */ + + /* fixup links in old list and prepare new list head */ + /* FIXME */ + /* list_fix_reloc(&old->succ); */ + INIT_LIST_HEAD(&core->succ); + core->private_data = NULL; + + /* copy list entries to new memory */ + list_for_each_entry(entry, &old->succ, list) { + new = malloc(sizeof(*new)); + if (!new) + return -ENOMEM; + + INIT_LIST_HEAD(&new->list); + new->instance = entry->instance; + new->ops = entry->ops; + new->name = entry->name; + list_add_tail(&new->list, &core->succ); + /*no free at this point, old memory should not be freed*/ + } + + return 0; +} + +static int destroy(struct core_instance *core) +{ + struct blockdev_core_entry *entry, *n; + + /* destroy private data */ + free(core->private_data); + core->private_data = NULL; + + /* destroy successor list */ + list_for_each_entry_safe(entry, n, &core->succ, list) { + list_del(&entry->list); + free(entry); + } + + return 0; +} + +U_BOOT_CORE(CORE_BLOCKDEV, + init, + reloc, + destroy, + get_count, + get_child, + bind, + unbind, + replace); + +/* Driver wrapping API */ +lbaint_t blockdev_read(struct instance *i, lbaint_t start, lbaint_t blkcnt, + void *buffer) +{ + struct blockdev_core_entry *entry = NULL; + struct blockdev_ops *device_ops = NULL; + int error; + + entry = get_entry_by_instance(i); + if (!entry) + return -ENOENT; + + error = driver_activate(i); + if (error) + return error; + + device_ops = entry->ops; + if (!device_ops || !device_ops->read) + return -EINVAL; + + return device_ops->read(i, start, blkcnt, buffer); +} + +lbaint_t blockdev_write(struct instance *i, lbaint_t start, lbaint_t blkcnt, + void *buffer) +{ + struct blockdev_core_entry *entry = NULL; + struct blockdev_ops *device_ops = NULL; + int error; + + entry = get_entry_by_instance(i); + if (!entry) + return -ENOENT; + + error = driver_activate(i); + if (error) + return error; + + device_ops = entry->ops; + if (!device_ops || !device_ops->write) + return -EINVAL; + + return device_ops->write(i, start, blkcnt, buffer); +} + +lbaint_t blockdev_erase(struct instance *i, lbaint_t start, lbaint_t blkcnt) +{ + struct blockdev_core_entry *entry = NULL; + struct blockdev_ops *device_ops = NULL; + int error; + + entry = get_entry_by_instance(i); + if (!entry) + return -ENOENT; + + error = driver_activate(i); + if (error) + return error; + + device_ops = entry->ops; + if (!device_ops) + return -EINVAL; + + return device_ops->erase(i, start, blkcnt); +} + +int blockdev_get_option(struct instance *i, enum blockdev_option_code op, + struct option *result) +{ + struct blockdev_core_entry *entry = NULL; + struct blockdev_ops *device_ops = NULL; + int error; + + entry = get_entry_by_instance(i); + if (!entry) + return -ENOENT; + + error = driver_activate(i); + if (error) + return error; + + device_ops = entry->ops; + if (!device_ops) + return -EINVAL; + + return device_ops->get_option(i, op, result); +} + +int blockdev_set_option(struct instance *i, enum blockdev_option_code op, + struct option *value) +{ + struct blockdev_core_entry *entry = NULL; + struct blockdev_ops *device_ops = NULL; + int error; + + entry = get_entry_by_instance(i); + if (!entry) + return -ENOENT; + + error = driver_activate(i); + if (error) + return error; + + device_ops = entry->ops; + if (!device_ops) + return -EINVAL; + + return device_ops->set_option(i, op, value); +} + +/* Command related functions */ +struct instance *get_blockdev_by_name(char *name) +{ + struct blockdev_id disk_id = empty_id; + struct blockdev_core_entry *entry; + + if (!name) + return NULL; + + disk_id = get_id_from_name(name); + + if (id_cmp(&disk_id, &invalid_id)) { + entry = get_entry_by_id(disk_id); + if (entry) + return entry->instance; + } + + return NULL; +} + +int scan_partitions(struct instance *dev) +{ + struct blockdev_core_entry *entry; + struct driver_instance *di, *tmp; + + entry = get_entry_by_instance(dev); + /* ignore if instance is partition or not a blockdev */ + if (!entry || (entry->name.partition != 0)) + return -EINVAL; + + /* remove all children */ + list_for_each_entry_safe(di, tmp, &dev->succ, list) { + driver_remove(&di->i); + driver_unbind(&di->i); + } + + /* determine type of partition table and scan for partitions */ +#ifdef CONFIG_DOS_PARTITION + if (!test_partitions_dos(dev)) + return scan_partitions_dos(dev); +#endif + + return -ENOENT; +} + +static inline int part_number_overflow(int number) +{ + /* just support 128 partitions for now */ + return (number > 128); +} + +int add_partition(struct instance *parent, lbaint_t start, lbaint_t length, + unsigned int number) +{ + struct blockdev_partition_platform_data *platform = NULL; + struct driver_info *info = NULL; + + /* check for overflow in partition number */ + if (part_number_overflow(number)) + return -EINVAL; + + platform = malloc(sizeof(*platform)); + info = malloc(sizeof(*info)); + if (!platform || !info) { + /* malloc went wrong, cleanup and indicate imminent death */ + free(platform); + free(info); + return -ENOMEM; + } + + platform->offset = start; + platform->block_count = length; + platform->part_number = number; + info->name = "blockdev_partition"; + info->platform_data = platform; + if (!driver_bind(parent, info)) + return -ENOMEM; + + return 0; +} + +/* Info printing stuff */ +static char *type_name(unsigned type) +{ + switch (type) { + case BLOCKDEV_TYPE_UNKNOWN: + return "Unknown/Not Connected"; + case BLOCKDEV_TYPE_HARDDISK: + return "Hard drive"; + case BLOCKDEV_TYPE_TAPE: + return "Tape"; + case BLOCKDEV_TYPE_CDROM: + return "CDROM"; + case BLOCKDEV_TYPE_OPDISK: + return "Optical disk"; + default: + return "Unknown"; + }; +} + +static inline int get_opt_u(struct blockdev_ops *ops, struct instance *dev, + enum blockdev_option_code code, struct option *opt) +{ + int retval = ops->get_option(dev, code, opt); + if (retval) + return retval; + + /* If we dont get the correct type we fail. */ + if (OPTION_TYPE(*opt) != OPTION_TYPE_U) + retval = -EINVAL; + + /* If we get a mallocated string we should free it. */ + if (opt->flags & OPTION_PTR_MALLOCED) + free(opt->data.data_s); + + return retval; +} + +static inline int get_opt_s(struct blockdev_ops *ops, struct instance *dev, + enum blockdev_option_code code, struct option *opt) +{ + int retval = ops->get_option(dev, code, opt); + if (retval) + return retval; + + /* If we dont get the correct type we fail. */ + if (OPTION_TYPE(*opt) != OPTION_TYPE_S) + retval = -EINVAL; + + return retval; +} + +int print_blockdev_info(struct instance *dev) +{ + struct option opt; + unsigned int type = 0; + unsigned int block_size = 0; + lbaint_t offset = 0; + lbaint_t block_count = 0; + char *vendor = NULL; + char *product = NULL; + char *revision = NULL; + int vendor_malloc = 0; + int product_malloc = 0; + int revision_malloc = 0; + struct blockdev_id id = empty_id; + struct blockdev_core_entry *entry = NULL; + struct blockdev_ops *ops = NULL; + int retval = 0; + enum blockdev_iftype iftype; + + entry = get_entry_by_instance(dev); + if (!entry) + return -ENOENT; + else { + id = entry->name; + ops = entry->ops; + } + + /* we are not using blockdev_get_option, so we activate manually here */ + retval = driver_activate(dev); + if (retval) + return retval; + + retval = get_opt_u(ops, dev, BLKD_OPT_TYPE, &opt); + if (retval) + return retval; + type = opt.data.data_u; + + if (type == BLOCKDEV_TYPE_PARTITION) { + /* get options that make sense for a partition */ + retval = get_opt_u(ops, dev, BLKD_OPT_BLOCKCOUNT, &opt); + if (retval) + return retval; + block_count = opt.data.data_u; + + retval = get_opt_u(ops, dev, BLKD_OPT_OFFSET, &opt); + if (retval) + return retval; + offset = opt.data.data_u; + + /* print some information message */ + printf("%s%d:%d\n\tpartition on %s%d\n\t" + "offset: %lu\n\tblock count: %lu\n\n", + blockdev_name[id.disk.type], id.disk.number, + id.partition, blockdev_name[id.disk.type], + id.disk.number, offset, block_count); + + } else { + /* get options that make sense for a disk */ + retval = get_opt_u(ops, dev, BLKD_OPT_IFTYPE, &opt); + if (retval) + return retval; + iftype = opt.data.data_u; + + retval = get_opt_u(ops, dev, BLKD_OPT_BLOCKSIZE, &opt); + if (retval) + return retval; + block_size = opt.data.data_u; + + retval = get_opt_u(ops, dev, BLKD_OPT_BLOCKCOUNT, &opt); + if (retval) + return retval; + block_count = opt.data.data_u; + + retval = get_opt_s(ops, dev, BLKD_OPT_VENDOR, &opt); + if (retval) + return retval; + vendor = opt.data.data_s; + vendor_malloc = opt.flags & OPTION_PTR_MALLOCED; + + retval = get_opt_s(ops, dev, BLKD_OPT_PRODUCT, &opt); + if (retval) + return retval; + product = opt.data.data_s; + product_malloc = opt.flags & OPTION_PTR_MALLOCED; + + retval = get_opt_s(ops, dev, BLKD_OPT_REVISION, &opt); + if (retval) + return retval; + revision = opt.data.data_s; + revision_malloc = opt.flags & OPTION_PTR_MALLOCED; + + /* print some information message */ + printf("%s%d\n\tvendor: %s\n\tproduct: %s\n\t" + "revision: %s\n\ttype: %s\n\tiftype: %s\n\t" + "block size: %d\n\tblock count: %lu\n\n", + blockdev_name[id.disk.type], id.disk.number, + vendor, product, revision, type_name(type), + iftype_name[iftype], block_size, block_count); + + /*cleanup if we got dynamic memory pointers*/ + if (vendor_malloc) + free(vendor); + + if (product_malloc) + free(product); + + if (revision_malloc) + free(revision); + } + + return retval; +} + +static void sort_bdid_i(struct bdid_instance_pair *data, size_t count) +{ + /* use bubble sort for now */ + int a, b; + struct bdid_instance_pair tswap; + + for (a = 1; a < count; a++) { + for (b = a; b > 0; b--) { + if (id_cmp(&data[b].id, &data[b-1].id) < 0) { + /*swap position b and b-1 */ + tswap = data[b-1]; + data[b-1] = data[b]; + data[b] = tswap; + } + } + } +} + +int print_blockdev_info_all(void) +{ + struct core_instance *core = NULL; + struct bdid_instance_pair *sorted_pairs = NULL; + struct blockdev_core_entry *entry = NULL; + int count = 0; + int idx = 0; + + core = get_core_instance(CORE_BLOCKDEV); + if (!core) + return -ENOMEM; + + count = core_get_count(CORE_BLOCKDEV); + sorted_pairs = malloc(sizeof(*sorted_pairs) * count); + if (!sorted_pairs) + return -ENOMEM; + + /* get list of all instances and associated IDs */ + list_for_each_entry(entry, &core->succ, list) { + sorted_pairs[idx].id = entry->name; + sorted_pairs[idx].inst = entry->instance; + idx++; + } + + /* sort isntances by ID */ + sort_bdid_i(sorted_pairs, count); + + /* print info about each instance */ + for (idx = 0; idx < count; idx++) + print_blockdev_info(sorted_pairs[idx].inst); + return 0; +} diff --git a/drivers/blockdev/part_types/part_dos.c b/drivers/blockdev/part_types/part_dos.c new file mode 100644 index 0000000..7d19818 --- /dev/null +++ b/drivers/blockdev/part_types/part_dos.c @@ -0,0 +1,148 @@ +/* + * (C) Copyright 2001 + * Raymond Lo, lo@routefree.com + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* + * Support for harddisk partitions. + * + * To be compatible with LinuxPPC and Apple we use the standard Apple + * SCSI disk partitioning scheme. For more information see: + * http://developer.apple.com/techpubs/mac/Devices/Devices-126.html#MARKER-14-9... + */ + +#include <common.h> +#include <ide.h> +#include "part_dos.h" +#include <dm/blockdev.h> + +#if defined(CONFIG_CMD_IDE) || \ + defined(CONFIG_CMD_MG_DISK) || \ + defined(CONFIG_CMD_SATA) || \ + defined(CONFIG_CMD_SCSI) || \ + defined(CONFIG_CMD_USB) || \ + defined(CONFIG_MMC) || \ + defined(CONFIG_SYSTEMACE) + +/* Convert char[4] in little endian format to the host format integer + */ +static inline int le32_to_int(unsigned char *le32) +{ + return ((le32[3] << 24) + + (le32[2] << 16) + + (le32[1] << 8) + + le32[0]); +} + +static inline int is_extended(int part_type) +{ + return (part_type == 0x5 || + part_type == 0xf || + part_type == 0x85); +} + +int test_partitions_dos(struct instance *dev) +{ + struct option blksz; + int error = blockdev_get_option(dev, BLKD_OPT_BLOCKSIZE, &blksz); + if (error) + return error; + + ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buffer, blksz.data.data_u); + + if ((blockdev_read(dev, 0, 1, buffer) != 1) || + (buffer[DOS_PART_MAGIC_OFFSET + 0] != 0x55) || + (buffer[DOS_PART_MAGIC_OFFSET + 1] != 0xaa)) { + return -EINVAL; + } + return 0; +} + + + +int scan_partitions_dos(struct instance *dev) +{ + struct dos_partition *pt; + lbaint_t extpt_sector = 0; + struct option blksz; + int error = blockdev_get_option(dev, BLKD_OPT_BLOCKSIZE, &blksz); + if (error) + return error; + + ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buffer, blksz.data.data_u); + + if (blockdev_read(dev, 0, 1, buffer) != 1) { + printf("** Can't read partition table **\n"); + return -EINVAL; + } + + if (buffer[DOS_PART_MAGIC_OFFSET] != 0x55 || + buffer[DOS_PART_MAGIC_OFFSET + 1] != 0xaa) { + printf("bad MBR sector signature 0x%02x%02x\n", + buffer[DOS_PART_MAGIC_OFFSET], + buffer[DOS_PART_MAGIC_OFFSET + 1]); + return -EINVAL; + } + + pt = (struct dos_partition *) (buffer + DOS_PART_TBL_OFFSET); + int i; + for (i = 0; i < 4; i++, pt++) { + if (((pt->boot_ind & ~0x80) == 0) && + (pt->sys_ind != 0) && + (is_extended(pt->sys_ind) == 0)) { + add_partition(dev, le32_to_int(pt->start4), + le32_to_int(pt->size4), i+1); + } + if (is_extended(pt->sys_ind)) + extpt_sector = le32_to_int(pt->start4); + } + + if (extpt_sector == 0) + return 0; + + /* repeat once for extended partitions */ + if (blockdev_read(dev, extpt_sector, 1, buffer) != 1) { + printf("** Can't read extended partition table **\n"); + return -EINVAL; + } + + if (buffer[DOS_PART_MAGIC_OFFSET] != 0x55 || + buffer[DOS_PART_MAGIC_OFFSET + 1] != 0xaa) { + printf("bad MBR sector signature 0x%02x%02x\n", + buffer[DOS_PART_MAGIC_OFFSET], + buffer[DOS_PART_MAGIC_OFFSET + 1]); + return -EINVAL; + } + + pt = (struct dos_partition *) (buffer + DOS_PART_TBL_OFFSET); + for (i = 0; i < 4; i++, pt++) { + if (((pt->boot_ind & ~0x80) == 0) && + (pt->sys_ind != 0) && + (is_extended(pt->sys_ind) == 0)) { + add_partition(dev, le32_to_int(pt->start4), + le32_to_int(pt->size4), i+5); + } + } + + return 0; +} +#endif diff --git a/drivers/blockdev/part_types/part_dos.h b/drivers/blockdev/part_types/part_dos.h new file mode 100644 index 0000000..98b0293 --- /dev/null +++ b/drivers/blockdev/part_types/part_dos.h @@ -0,0 +1,49 @@ +/* + * (C) Copyright 2000 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef _DISK_PART_DOS_H +#define _DISK_PART_DOS_H + + +#define DOS_PART_TBL_OFFSET 0x1be +#define DOS_PART_MAGIC_OFFSET 0x1fe +#define DOS_PBR_FSTYPE_OFFSET 0x36 +#define DOS_PBR32_FSTYPE_OFFSET 0x52 +#define DOS_PBR_MEDIA_TYPE_OFFSET 0x15 +#define DOS_MBR 0 +#define DOS_PBR 1 + +struct dos_partition { + unsigned char boot_ind; /* 0x80 - active */ + unsigned char head; /* starting head */ + unsigned char sector; /* starting sector */ + unsigned char cyl; /* starting cylinder */ + unsigned char sys_ind; /* What partition type */ + unsigned char end_head; /* end head */ + unsigned char end_sector; /* end sector */ + unsigned char end_cyl; /* end cylinder */ + unsigned char start4[4]; /* starting sector counting from 0*/ + unsigned char size4[4]; /* nr of sectors in partition */ +}; + +#endif /* _DISK_PART_DOS_H */ diff --git a/drivers/blockdev/part_types/part_types.h b/drivers/blockdev/part_types/part_types.h new file mode 100644 index 0000000..d5e6f61 --- /dev/null +++ b/drivers/blockdev/part_types/part_types.h @@ -0,0 +1,34 @@ +/* + * (C) Copyright 2012 + * Pavel Herrmann morpheus.ibis@gmail.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef _BLOCKDEV_PART_TYPES_H_ +#define _BLOCKDEV_PART_TYPES_H_ 1 + +#include <dm/structures.h> + +#ifdef CONFIG_DOS_PARTITION +int test_partitions_dos(struct instance *i); +int scan_partitions_dos(struct instance *i); +#endif + +#endif

Dear Pavel Herrmann,
[..]
+#define BLOCKDEV_IFTYPE_BITS 4 +#define BLOCKDEV_IFTYPE_COUNT (1<<BLOCKDEV_IFTYPE_BITS) +#define BLOCKDEV_IFTYPE_MAX BLOCKDEV_IFTYPE_COUNT-1
I saw this in blockdev.h
+struct blockdev_id {
- struct {
unsigned type:BLOCKDEV_IFTYPE_BITS;
unsigned number:(16-BLOCKDEV_IFTYPE_BITS);
- } disk;
- unsigned partition:16;
+};
+static struct blockdev_id invalid_id = {{0xf, 0xfff}, 0xffff}; +static struct blockdev_id empty_id = {{0x0, 0x0}, 0x0};
+static inline int id_cmp(const struct blockdev_id *left,
- const struct blockdev_id *right)
+{
- return memcmp(left, right, sizeof(struct blockdev_id));
+}
+struct blockdev_core_entry {
- struct list_head list;
- struct instance *instance;
- struct blockdev_ops *ops;
- struct blockdev_id name;
+};
+struct blockdev_core_private {
- /* Put cache here */
+};
+struct bdid_instance_pair {
- struct blockdev_id id;
- struct instance *inst;
+};
+static struct blockdev_core_entry *get_entry_by_instance(struct instance *i) +{
- struct blockdev_core_entry *tmp;
- struct core_instance *core = get_core_instance(CORE_BLOCKDEV);
- if (!core)
return NULL;
- list_for_each_entry(tmp, &core->succ, list)
if (tmp->instance == i)
return tmp;
- return NULL;
+}
+static struct blockdev_core_entry *get_entry_by_id(struct blockdev_id id) +{
- struct blockdev_core_entry *tmp;
- struct core_instance *core = get_core_instance(CORE_BLOCKDEV);
- if (!core)
return NULL;
- list_for_each_entry(tmp, &core->succ, list)
if (!id_cmp(&tmp->name, &id))
return tmp;
- return NULL;
+}
+static inline int try_match_name(enum blockdev_iftype type,
- struct blockdev_id *id, char **name)
+{
- int len = strlen(blockdev_name[type]);
- if (!strncmp(*name, blockdev_name[type], len)) {
id->disk.type = type;
*name += len;
return 0;
- }
- return 1;
+}
+static struct blockdev_id get_id_from_name(char *name) +{
- struct blockdev_id disk_id = empty_id;
- if (!try_match_name(BLOCKDEV_IFTYPE_UNKNOWN, &disk_id, &name))
goto get_number;
- if (!try_match_name(BLOCKDEV_IFTYPE_ATA, &disk_id, &name))
goto get_number;
- if (!try_match_name(BLOCKDEV_IFTYPE_SD, &disk_id, &name))
goto get_number;
- if (!try_match_name(BLOCKDEV_IFTYPE_USB, &disk_id, &name))
goto get_number;
- return invalid_id;
+get_number:
- /* get disk number from name */
- if ((*name < '0') || (*name > '9'))
return invalid_id;
- disk_id.disk.number *= 10;
- disk_id.disk.number += (*name-'0');
- name++;
- switch (*name) {
- case 0:
return disk_id;
- case BLOCKDEV_PARTITION_SEPARATOR:
name += 1;
goto get_part;
- default:
goto get_number;
- }
- return invalid_id;
+get_part:
- /* get partition number fron name */
- if ((*name < '0') || (*name > '9'))
return invalid_id;
- disk_id.partition *= 10;
- disk_id.partition += (*name-'0');
- name++;
- switch (*name) {
- case 0:
return disk_id;
- default:
goto get_part;
- }
- return invalid_id;
+}
+static int get_free_index(struct core_instance *core, enum blockdev_iftype type) +{
- int retval = 0;
- struct blockdev_core_entry *entry;
- list_for_each_entry(entry, &core->succ, list) {
if ((entry->name.disk.type == type) &&
(entry->name.disk.number >= retval))
retval = entry->name.disk.number + 1;
- }
- return retval;
+}
+static struct blockdev_id create_id_from_hint(struct core_instance *core,
- struct instance *dev, void* data)
+{
- struct blockdev_id retval = empty_id;
- struct blockdev_core_entry *entry;
- struct blockdev_core_hint *hint = data;
- /* no hint means we have no idea what type of device we have */
- if (!hint)
retval.disk.type = BLOCKDEV_IFTYPE_UNKNOWN;
return here ... you don't need else then.
- else {
/* for a partition, we find its parent and use its name */
if (hint->iftype == BLOCKDEV_IFTYPE_PARTITION) {
entry = get_entry_by_instance(dev->bus);
retval.disk = entry->name.disk;
retval.partition = hint->part_number;
return retval;
/* if we have a valid hint for a disk, get a free index */
} else {
retval.disk.type = hint->iftype;
retval.disk.number = get_free_index(core, hint->iftype);
retval.partition = 0;
}
- }
- return retval;
+}
+/* Core API functions */ +static int get_count(struct core_instance *core) +{
- int cnt = 0;
- struct blockdev_core_entry *entry = NULL;
- list_for_each_entry(entry, &core->succ, list)
cnt++;
- return cnt;
+}
+static struct instance *get_child(struct core_instance *core, int index) +{
- struct blockdev_core_entry *entry = NULL;
- list_for_each_entry(entry, &core->succ, list) {
if (!index)
return entry->instance;
index--;
- }
- return NULL;
+}
+static int bind(struct core_instance *core, struct instance *dev, void *ops, + void *data) +{
- struct blockdev_core_entry *entry;
- if (ops == NULL)
return -EINVAL;
- entry = malloc(sizeof(*entry));
- if (entry == NULL)
return -ENOMEM;
- INIT_LIST_HEAD(&entry->list);
- entry->instance = dev;
- entry->ops = ops;
- entry->name = create_id_from_hint(core, dev, data);
- list_add_tail(&entry->list, &core->succ);
- return 0;
+}
+static int unbind(struct core_instance *core, struct instance *dev) +{
- struct blockdev_core_entry *entry, *n;
- list_for_each_entry_safe(entry, n, &core->succ, list) {
if (entry->instance == dev) {
list_del(&entry->list);
free(entry);
}
- }
- return 0;
+}
+static int replace(struct core_instance *core, struct instance *new,
- struct instance *old)
+{
- struct blockdev_core_entry *entry = get_entry_by_instance(old);
- if (!entry)
return -ENOENT;
- entry->instance = new;
- return 0;
+}
+static int init(struct core_instance *core)
I'd say, rename it to block_core_init() or something, so the syms in u-boot.map are unique.
+{
- INIT_LIST_HEAD(&core->succ);
- core->private_data = NULL;
- return 0;
+}
+static int reloc(struct core_instance *core, struct core_instance *old) +{
- struct blockdev_core_entry *entry, *new;
- /* no private_data to copy, yet */
- /* fixup links in old list and prepare new list head */
- /* FIXME */
- /* list_fix_reloc(&old->succ); */
- INIT_LIST_HEAD(&core->succ);
- core->private_data = NULL;
- /* copy list entries to new memory */
- list_for_each_entry(entry, &old->succ, list) {
new = malloc(sizeof(*new));
if (!new)
return -ENOMEM;
INIT_LIST_HEAD(&new->list);
new->instance = entry->instance;
new->ops = entry->ops;
new->name = entry->name;
list_add_tail(&new->list, &core->succ);
/*no free at this point, old memory should not be freed*/
- }
- return 0;
+}
+static int destroy(struct core_instance *core) +{
- struct blockdev_core_entry *entry, *n;
- /* destroy private data */
- free(core->private_data);
- core->private_data = NULL;
- /* destroy successor list */
- list_for_each_entry_safe(entry, n, &core->succ, list) {
list_del(&entry->list);
free(entry);
- }
- return 0;
+}
+U_BOOT_CORE(CORE_BLOCKDEV,
- init,
- reloc,
- destroy,
- get_count,
- get_child,
- bind,
- unbind,
- replace);
Sep the stuff below away into separate file. Conditionally compile in one or the other.
+/* Driver wrapping API */ +lbaint_t blockdev_read(struct instance *i, lbaint_t start, lbaint_t blkcnt, + void *buffer) +{
- struct blockdev_core_entry *entry = NULL;
- struct blockdev_ops *device_ops = NULL;
- int error;
- entry = get_entry_by_instance(i);
- if (!entry)
return -ENOENT;
- error = driver_activate(i);
- if (error)
return error;
- device_ops = entry->ops;
- if (!device_ops || !device_ops->read)
return -EINVAL;
- return device_ops->read(i, start, blkcnt, buffer);
+}
+lbaint_t blockdev_write(struct instance *i, lbaint_t start, lbaint_t blkcnt, + void *buffer) +{
- struct blockdev_core_entry *entry = NULL;
- struct blockdev_ops *device_ops = NULL;
- int error;
- entry = get_entry_by_instance(i);
- if (!entry)
return -ENOENT;
- error = driver_activate(i);
- if (error)
return error;
- device_ops = entry->ops;
- if (!device_ops || !device_ops->write)
return -EINVAL;
- return device_ops->write(i, start, blkcnt, buffer);
+}
+lbaint_t blockdev_erase(struct instance *i, lbaint_t start, lbaint_t blkcnt) +{
- struct blockdev_core_entry *entry = NULL;
- struct blockdev_ops *device_ops = NULL;
- int error;
- entry = get_entry_by_instance(i);
- if (!entry)
return -ENOENT;
- error = driver_activate(i);
- if (error)
return error;
- device_ops = entry->ops;
- if (!device_ops)
return -EINVAL;
- return device_ops->erase(i, start, blkcnt);
+}
+int blockdev_get_option(struct instance *i, enum blockdev_option_code op,
- struct option *result)
+{
- struct blockdev_core_entry *entry = NULL;
- struct blockdev_ops *device_ops = NULL;
- int error;
- entry = get_entry_by_instance(i);
- if (!entry)
return -ENOENT;
- error = driver_activate(i);
- if (error)
return error;
- device_ops = entry->ops;
- if (!device_ops)
return -EINVAL;
- return device_ops->get_option(i, op, result);
+}
+int blockdev_set_option(struct instance *i, enum blockdev_option_code op,
- struct option *value)
+{
- struct blockdev_core_entry *entry = NULL;
- struct blockdev_ops *device_ops = NULL;
- int error;
- entry = get_entry_by_instance(i);
- if (!entry)
return -ENOENT;
- error = driver_activate(i);
- if (error)
return error;
- device_ops = entry->ops;
- if (!device_ops)
return -EINVAL;
- return device_ops->set_option(i, op, value);
+}
+/* Command related functions */ +struct instance *get_blockdev_by_name(char *name) +{
- struct blockdev_id disk_id = empty_id;
- struct blockdev_core_entry *entry;
- if (!name)
return NULL;
- disk_id = get_id_from_name(name);
- if (id_cmp(&disk_id, &invalid_id)) {
entry = get_entry_by_id(disk_id);
if (entry)
return entry->instance;
- }
- return NULL;
+}
+int scan_partitions(struct instance *dev) +{
- struct blockdev_core_entry *entry;
- struct driver_instance *di, *tmp;
- entry = get_entry_by_instance(dev);
- /* ignore if instance is partition or not a blockdev */
- if (!entry || (entry->name.partition != 0))
return -EINVAL;
- /* remove all children */
- list_for_each_entry_safe(di, tmp, &dev->succ, list) {
driver_remove(&di->i);
driver_unbind(&di->i);
- }
- /* determine type of partition table and scan for partitions */
+#ifdef CONFIG_DOS_PARTITION
- if (!test_partitions_dos(dev))
return scan_partitions_dos(dev);
+#endif
- return -ENOENT;
+}
+static inline int part_number_overflow(int number) +{
- /* just support 128 partitions for now */
- return (number > 128);
+}
+int add_partition(struct instance *parent, lbaint_t start, lbaint_t length, + unsigned int number) +{
- struct blockdev_partition_platform_data *platform = NULL;
- struct driver_info *info = NULL;
- /* check for overflow in partition number */
- if (part_number_overflow(number))
return -EINVAL;
- platform = malloc(sizeof(*platform));
- info = malloc(sizeof(*info));
- if (!platform || !info) {
/* malloc went wrong, cleanup and indicate imminent death */
free(platform);
free(info);
return -ENOMEM;
- }
- platform->offset = start;
- platform->block_count = length;
- platform->part_number = number;
- info->name = "blockdev_partition";
- info->platform_data = platform;
- if (!driver_bind(parent, info))
return -ENOMEM;
- return 0;
+}
+/* Info printing stuff */ +static char *type_name(unsigned type) +{
- switch (type) {
- case BLOCKDEV_TYPE_UNKNOWN:
return "Unknown/Not Connected";
- case BLOCKDEV_TYPE_HARDDISK:
return "Hard drive";
- case BLOCKDEV_TYPE_TAPE:
return "Tape";
- case BLOCKDEV_TYPE_CDROM:
return "CDROM";
- case BLOCKDEV_TYPE_OPDISK:
return "Optical disk";
- default:
return "Unknown";
- };
+}
+static inline int get_opt_u(struct blockdev_ops *ops, struct instance *dev, + enum blockdev_option_code code, struct option *opt) +{
- int retval = ops->get_option(dev, code, opt);
- if (retval)
return retval;
- /* If we dont get the correct type we fail. */
- if (OPTION_TYPE(*opt) != OPTION_TYPE_U)
retval = -EINVAL;
- /* If we get a mallocated string we should free it. */
- if (opt->flags & OPTION_PTR_MALLOCED)
free(opt->data.data_s);
- return retval;
+}
+static inline int get_opt_s(struct blockdev_ops *ops, struct instance *dev, + enum blockdev_option_code code, struct option *opt) +{
- int retval = ops->get_option(dev, code, opt);
- if (retval)
return retval;
- /* If we dont get the correct type we fail. */
- if (OPTION_TYPE(*opt) != OPTION_TYPE_S)
retval = -EINVAL;
- return retval;
+}
+int print_blockdev_info(struct instance *dev) +{
- struct option opt;
- unsigned int type = 0;
- unsigned int block_size = 0;
- lbaint_t offset = 0;
- lbaint_t block_count = 0;
- char *vendor = NULL;
- char *product = NULL;
- char *revision = NULL;
- int vendor_malloc = 0;
- int product_malloc = 0;
- int revision_malloc = 0;
- struct blockdev_id id = empty_id;
- struct blockdev_core_entry *entry = NULL;
- struct blockdev_ops *ops = NULL;
- int retval = 0;
- enum blockdev_iftype iftype;
- entry = get_entry_by_instance(dev);
- if (!entry)
return -ENOENT;
- else {
id = entry->name;
ops = entry->ops;
- }
- /* we are not using blockdev_get_option, so we activate manually here */
- retval = driver_activate(dev);
- if (retval)
return retval;
- retval = get_opt_u(ops, dev, BLKD_OPT_TYPE, &opt);
- if (retval)
return retval;
- type = opt.data.data_u;
- if (type == BLOCKDEV_TYPE_PARTITION) {
/* get options that make sense for a partition */
retval = get_opt_u(ops, dev, BLKD_OPT_BLOCKCOUNT, &opt);
if (retval)
return retval;
block_count = opt.data.data_u;
retval = get_opt_u(ops, dev, BLKD_OPT_OFFSET, &opt);
if (retval)
return retval;
offset = opt.data.data_u;
/* print some information message */
printf("%s%d:%d\n\tpartition on %s%d\n\t"
"offset: %lu\n\tblock count: %lu\n\n",
blockdev_name[id.disk.type], id.disk.number,
id.partition, blockdev_name[id.disk.type],
id.disk.number, offset, block_count);
- } else {
/* get options that make sense for a disk */
retval = get_opt_u(ops, dev, BLKD_OPT_IFTYPE, &opt);
if (retval)
return retval;
iftype = opt.data.data_u;
retval = get_opt_u(ops, dev, BLKD_OPT_BLOCKSIZE, &opt);
if (retval)
return retval;
block_size = opt.data.data_u;
retval = get_opt_u(ops, dev, BLKD_OPT_BLOCKCOUNT, &opt);
if (retval)
return retval;
block_count = opt.data.data_u;
retval = get_opt_s(ops, dev, BLKD_OPT_VENDOR, &opt);
if (retval)
return retval;
vendor = opt.data.data_s;
vendor_malloc = opt.flags & OPTION_PTR_MALLOCED;
retval = get_opt_s(ops, dev, BLKD_OPT_PRODUCT, &opt);
if (retval)
return retval;
product = opt.data.data_s;
product_malloc = opt.flags & OPTION_PTR_MALLOCED;
retval = get_opt_s(ops, dev, BLKD_OPT_REVISION, &opt);
if (retval)
return retval;
revision = opt.data.data_s;
revision_malloc = opt.flags & OPTION_PTR_MALLOCED;
/* print some information message */
printf("%s%d\n\tvendor: %s\n\tproduct: %s\n\t"
"revision: %s\n\ttype: %s\n\tiftype: %s\n\t"
"block size: %d\n\tblock count: %lu\n\n",
blockdev_name[id.disk.type], id.disk.number,
vendor, product, revision, type_name(type),
iftype_name[iftype], block_size, block_count);
/*cleanup if we got dynamic memory pointers*/
if (vendor_malloc)
free(vendor);
if (product_malloc)
free(product);
if (revision_malloc)
free(revision);
- }
- return retval;
+}
+static void sort_bdid_i(struct bdid_instance_pair *data, size_t count) +{
- /* use bubble sort for now */
- int a, b;
- struct bdid_instance_pair tswap;
- for (a = 1; a < count; a++) {
for (b = a; b > 0; b--) {
if (id_cmp(&data[b].id, &data[b-1].id) < 0) {
/*swap position b and b-1 */
tswap = data[b-1];
data[b-1] = data[b];
data[b] = tswap;
}
}
- }
+}
+int print_blockdev_info_all(void) +{
- struct core_instance *core = NULL;
- struct bdid_instance_pair *sorted_pairs = NULL;
- struct blockdev_core_entry *entry = NULL;
- int count = 0;
- int idx = 0;
- core = get_core_instance(CORE_BLOCKDEV);
- if (!core)
return -ENOMEM;
- count = core_get_count(CORE_BLOCKDEV);
- sorted_pairs = malloc(sizeof(*sorted_pairs) * count);
- if (!sorted_pairs)
return -ENOMEM;
- /* get list of all instances and associated IDs */
- list_for_each_entry(entry, &core->succ, list) {
sorted_pairs[idx].id = entry->name;
sorted_pairs[idx].inst = entry->instance;
idx++;
- }
- /* sort isntances by ID */
- sort_bdid_i(sorted_pairs, count);
- /* print info about each instance */
- for (idx = 0; idx < count; idx++)
print_blockdev_info(sorted_pairs[idx].inst);
- return 0;
+} diff --git a/drivers/blockdev/part_types/part_dos.c b/drivers/blockdev/part_types/part_dos.c new file mode 100644 index 0000000..7d19818 --- /dev/null +++ b/drivers/blockdev/part_types/part_dos.c @@ -0,0 +1,148 @@ +/*
- (C) Copyright 2001
- Raymond Lo, lo@routefree.com
- Wolfgang Denk, DENX Software Engineering, wd@denx.de.
- See file CREDITS for list of people who contributed to this
- project.
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2 of
- the License, or (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- MA 02111-1307 USA
- */
+/*
- Support for harddisk partitions.
- To be compatible with LinuxPPC and Apple we use the standard Apple
- SCSI disk partitioning scheme. For more information see:
http://developer.apple.com/techpubs/mac/Devices/Devices-126.html#MARKER-14 -92 + */
+#include <common.h> +#include <ide.h> +#include "part_dos.h" +#include <dm/blockdev.h>
+#if defined(CONFIG_CMD_IDE) || \
- defined(CONFIG_CMD_MG_DISK) || \
- defined(CONFIG_CMD_SATA) || \
- defined(CONFIG_CMD_SCSI) || \
- defined(CONFIG_CMD_USB) || \
- defined(CONFIG_MMC) || \
- defined(CONFIG_SYSTEMACE)
+/* Convert char[4] in little endian format to the host format integer
- */
+static inline int le32_to_int(unsigned char *le32) +{
- return ((le32[3] << 24) +
(le32[2] << 16) +
(le32[1] << 8) +
le32[0]);
+}
+static inline int is_extended(int part_type) +{
- return (part_type == 0x5 ||
part_type == 0xf ||
part_type == 0x85);
+}
+int test_partitions_dos(struct instance *dev) +{
- struct option blksz;
- int error = blockdev_get_option(dev, BLKD_OPT_BLOCKSIZE, &blksz);
- if (error)
return error;
- ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buffer, blksz.data.data_u);
- if ((blockdev_read(dev, 0, 1, buffer) != 1) ||
(buffer[DOS_PART_MAGIC_OFFSET + 0] != 0x55) ||
(buffer[DOS_PART_MAGIC_OFFSET + 1] != 0xaa)) {
return -EINVAL;
- }
- return 0;
+}
+int scan_partitions_dos(struct instance *dev) +{
- struct dos_partition *pt;
- lbaint_t extpt_sector = 0;
- struct option blksz;
- int error = blockdev_get_option(dev, BLKD_OPT_BLOCKSIZE, &blksz);
- if (error)
return error;
- ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buffer, blksz.data.data_u);
- if (blockdev_read(dev, 0, 1, buffer) != 1) {
printf("** Can't read partition table **\n");
return -EINVAL;
- }
- if (buffer[DOS_PART_MAGIC_OFFSET] != 0x55 ||
buffer[DOS_PART_MAGIC_OFFSET + 1] != 0xaa) {
printf("bad MBR sector signature 0x%02x%02x\n",
buffer[DOS_PART_MAGIC_OFFSET],
buffer[DOS_PART_MAGIC_OFFSET + 1]);
return -EINVAL;
- }
- pt = (struct dos_partition *) (buffer + DOS_PART_TBL_OFFSET);
- int i;
- for (i = 0; i < 4; i++, pt++) {
if (((pt->boot_ind & ~0x80) == 0) &&
(pt->sys_ind != 0) &&
(is_extended(pt->sys_ind) == 0)) {
add_partition(dev, le32_to_int(pt->start4),
le32_to_int(pt->size4), i+1);
}
if (is_extended(pt->sys_ind))
extpt_sector = le32_to_int(pt->start4);
- }
- if (extpt_sector == 0)
return 0;
- /* repeat once for extended partitions */
- if (blockdev_read(dev, extpt_sector, 1, buffer) != 1) {
printf("** Can't read extended partition table **\n");
return -EINVAL;
- }
- if (buffer[DOS_PART_MAGIC_OFFSET] != 0x55 ||
buffer[DOS_PART_MAGIC_OFFSET + 1] != 0xaa) {
printf("bad MBR sector signature 0x%02x%02x\n",
buffer[DOS_PART_MAGIC_OFFSET],
buffer[DOS_PART_MAGIC_OFFSET + 1]);
return -EINVAL;
- }
- pt = (struct dos_partition *) (buffer + DOS_PART_TBL_OFFSET);
- for (i = 0; i < 4; i++, pt++) {
if (((pt->boot_ind & ~0x80) == 0) &&
(pt->sys_ind != 0) &&
(is_extended(pt->sys_ind) == 0)) {
add_partition(dev, le32_to_int(pt->start4),
le32_to_int(pt->size4), i+5);
}
- }
- return 0;
+} +#endif diff --git a/drivers/blockdev/part_types/part_dos.h b/drivers/blockdev/part_types/part_dos.h new file mode 100644 index 0000000..98b0293 --- /dev/null +++ b/drivers/blockdev/part_types/part_dos.h @@ -0,0 +1,49 @@ +/*
- (C) Copyright 2000
- Wolfgang Denk, DENX Software Engineering, wd@denx.de.
- See file CREDITS for list of people who contributed to this
- project.
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2 of
- the License, or (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- MA 02111-1307 USA
- */
+#ifndef _DISK_PART_DOS_H +#define _DISK_PART_DOS_H
+#define DOS_PART_TBL_OFFSET 0x1be +#define DOS_PART_MAGIC_OFFSET 0x1fe +#define DOS_PBR_FSTYPE_OFFSET 0x36 +#define DOS_PBR32_FSTYPE_OFFSET 0x52 +#define DOS_PBR_MEDIA_TYPE_OFFSET 0x15 +#define DOS_MBR 0 +#define DOS_PBR 1
+struct dos_partition {
- unsigned char boot_ind; /* 0x80 - active */
- unsigned char head; /* starting head */
- unsigned char sector; /* starting sector */
- unsigned char cyl; /* starting cylinder */
- unsigned char sys_ind; /* What partition type */
- unsigned char end_head; /* end head */
- unsigned char end_sector; /* end sector */
- unsigned char end_cyl; /* end cylinder */
- unsigned char start4[4]; /* starting sector counting from 0*/
- unsigned char size4[4]; /* nr of sectors in partition */
+};
+#endif /* _DISK_PART_DOS_H */ diff --git a/drivers/blockdev/part_types/part_types.h b/drivers/blockdev/part_types/part_types.h new file mode 100644 index 0000000..d5e6f61 --- /dev/null +++ b/drivers/blockdev/part_types/part_types.h @@ -0,0 +1,34 @@ +/*
- (C) Copyright 2012
- Pavel Herrmann morpheus.ibis@gmail.com
- See file CREDITS for list of people who contributed to this
- project.
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2 of
- the License, or (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- MA 02111-1307 USA
- */
+#ifndef _BLOCKDEV_PART_TYPES_H_ +#define _BLOCKDEV_PART_TYPES_H_ 1
+#include <dm/structures.h>
+#ifdef CONFIG_DOS_PARTITION +int test_partitions_dos(struct instance *i); +int scan_partitions_dos(struct instance *i); +#endif
+#endif

On Thursday 20 of September 2012 22:03:05 Marek Vasut wrote:
Dear Pavel Herrmann,
[..]
+#define BLOCKDEV_IFTYPE_BITS 4 +#define BLOCKDEV_IFTYPE_COUNT (1<<BLOCKDEV_IFTYPE_BITS) +#define BLOCKDEV_IFTYPE_MAX BLOCKDEV_IFTYPE_COUNT-1
I saw this in blockdev.h
My bad then, sorry.
...
+}
+static int replace(struct core_instance *core, struct instance *new,
- struct instance *old)
+{
- struct blockdev_core_entry *entry = get_entry_by_instance(old);
- if (!entry)
return -ENOENT;
- entry->instance = new;
- return 0;
+}
+static int init(struct core_instance *core)
I'd say, rename it to block_core_init() or something, so the syms in u-boot.map are unique.
thic being static, how could it show in u-boot.map?
+{
- INIT_LIST_HEAD(&core->succ);
- core->private_data = NULL;
- return 0;
+}
+static int reloc(struct core_instance *core, struct core_instance *old) +{
- struct blockdev_core_entry *entry, *new;
- /* no private_data to copy, yet */
- /* fixup links in old list and prepare new list head */
- /* FIXME */
- /* list_fix_reloc(&old->succ); */
- INIT_LIST_HEAD(&core->succ);
- core->private_data = NULL;
- /* copy list entries to new memory */
- list_for_each_entry(entry, &old->succ, list) {
new = malloc(sizeof(*new));
if (!new)
return -ENOMEM;
INIT_LIST_HEAD(&new->list);
new->instance = entry->instance;
new->ops = entry->ops;
new->name = entry->name;
list_add_tail(&new->list, &core->succ);
/*no free at this point, old memory should not be freed*/
- }
- return 0;
+}
+static int destroy(struct core_instance *core) +{
- struct blockdev_core_entry *entry, *n;
- /* destroy private data */
- free(core->private_data);
- core->private_data = NULL;
- /* destroy successor list */
- list_for_each_entry_safe(entry, n, &core->succ, list) {
list_del(&entry->list);
free(entry);
- }
- return 0;
+}
+U_BOOT_CORE(CORE_BLOCKDEV,
- init,
- reloc,
- destroy,
- get_count,
- get_child,
- bind,
- unbind,
- replace);
Sep the stuff below away into separate file. Conditionally compile in one or the other.
I distinctly remember you saying to put all this into one file (as opposed to 3 it was before), so why the turn-around now? No idea what you mean by "one or the other" - you need all this code for it to work.
+/* Driver wrapping API */ +lbaint_t blockdev_read(struct instance *i, lbaint_t start, lbaint_t blkcnt, + void *buffer) +{
- struct blockdev_core_entry *entry = NULL;
- struct blockdev_ops *device_ops = NULL;
- int error;
- entry = get_entry_by_instance(i);
- if (!entry)
return -ENOENT;
- error = driver_activate(i);
- if (error)
return error;
- device_ops = entry->ops;
- if (!device_ops || !device_ops->read)
return -EINVAL;
- return device_ops->read(i, start, blkcnt, buffer);
+}
Pavel Herrmann

Dear Pavel Herrmann,
[...]
+static int init(struct core_instance *core)
I'd say, rename it to block_core_init() or something, so the syms in u-boot.map are unique.
thic being static, how could it show in u-boot.map?
Argh, not u-boot.map, sorry. But it's much easier for git grep to look up unique syms than this.
+{
- INIT_LIST_HEAD(&core->succ);
- core->private_data = NULL;
- return 0;
+}
+static int reloc(struct core_instance *core, struct core_instance *old) +{
- struct blockdev_core_entry *entry, *new;
- /* no private_data to copy, yet */
- /* fixup links in old list and prepare new list head */
- /* FIXME */
- /* list_fix_reloc(&old->succ); */
- INIT_LIST_HEAD(&core->succ);
- core->private_data = NULL;
- /* copy list entries to new memory */
- list_for_each_entry(entry, &old->succ, list) {
new = malloc(sizeof(*new));
if (!new)
return -ENOMEM;
INIT_LIST_HEAD(&new->list);
new->instance = entry->instance;
new->ops = entry->ops;
new->name = entry->name;
list_add_tail(&new->list, &core->succ);
/*no free at this point, old memory should not be freed*/
- }
- return 0;
+}
+static int destroy(struct core_instance *core) +{
- struct blockdev_core_entry *entry, *n;
- /* destroy private data */
- free(core->private_data);
- core->private_data = NULL;
- /* destroy successor list */
- list_for_each_entry_safe(entry, n, &core->succ, list) {
list_del(&entry->list);
free(entry);
- }
- return 0;
+}
+U_BOOT_CORE(CORE_BLOCKDEV,
- init,
- reloc,
- destroy,
- get_count,
- get_child,
- bind,
- unbind,
- replace);
Sep the stuff below away into separate file. Conditionally compile in one or the other.
I distinctly remember you saying to put all this into one file (as opposed to 3 it was before), so why the turn-around now?
Well, I didn't see the code before, so I couldn't make a firm decision, sorry.
No idea what you mean by "one or the other" - you need all this code for it to work.
You need the "driver wrapping API" if DM is enabled? I do not understand this, please elaborate!
What about having a common part for both cases and then compile either the DM part or non-DM part conditionally?
+/* Driver wrapping API */ +lbaint_t blockdev_read(struct instance *i, lbaint_t start, lbaint_t blkcnt, + void *buffer) +{
- struct blockdev_core_entry *entry = NULL;
- struct blockdev_ops *device_ops = NULL;
- int error;
- entry = get_entry_by_instance(i);
- if (!entry)
return -ENOENT;
- error = driver_activate(i);
- if (error)
return error;
- device_ops = entry->ops;
- if (!device_ops || !device_ops->read)
return -EINVAL;
- return device_ops->read(i, start, blkcnt, buffer);
+}
Pavel Herrmann
Best regards, Marek Vasut

On Friday 21 of September 2012 14:47:24 Marek Vasut wrote:
Dear Pavel Herrmann,
[...]
+static int init(struct core_instance *core)
I'd say, rename it to block_core_init() or something, so the syms in u-boot.map are unique.
thic being static, how could it show in u-boot.map?
Argh, not u-boot.map, sorry. But it's much easier for git grep to look up unique syms than this.
ah, OK then
+{
- INIT_LIST_HEAD(&core->succ);
- core->private_data = NULL;
- return 0;
+}
+static int reloc(struct core_instance *core, struct core_instance *old) +{
- struct blockdev_core_entry *entry, *new;
- /* no private_data to copy, yet */
- /* fixup links in old list and prepare new list head */
- /* FIXME */
- /* list_fix_reloc(&old->succ); */
- INIT_LIST_HEAD(&core->succ);
- core->private_data = NULL;
- /* copy list entries to new memory */
- list_for_each_entry(entry, &old->succ, list) {
new = malloc(sizeof(*new));
if (!new)
return -ENOMEM;
INIT_LIST_HEAD(&new->list);
new->instance = entry->instance;
new->ops = entry->ops;
new->name = entry->name;
list_add_tail(&new->list, &core->succ);
/*no free at this point, old memory should not be freed*/
- }
- return 0;
+}
+static int destroy(struct core_instance *core) +{
- struct blockdev_core_entry *entry, *n;
- /* destroy private data */
- free(core->private_data);
- core->private_data = NULL;
- /* destroy successor list */
- list_for_each_entry_safe(entry, n, &core->succ, list) {
list_del(&entry->list);
free(entry);
- }
- return 0;
+}
+U_BOOT_CORE(CORE_BLOCKDEV,
- init,
- reloc,
- destroy,
- get_count,
- get_child,
- bind,
- unbind,
- replace);
Sep the stuff below away into separate file. Conditionally compile in one or the other.
I distinctly remember you saying to put all this into one file (as opposed to 3 it was before), so why the turn-around now?
Well, I didn't see the code before, so I couldn't make a firm decision, sorry.
No idea what you mean by "one or the other" - you need all this code for it to work.
You need the "driver wrapping API" if DM is enabled? I do not understand this, please elaborate!
What about having a common part for both cases and then compile either the DM part or non-DM part conditionally?
this is all DM-only. driver-wrapping API is wrapper/proxy functions to driver ops (aka it wraps around the ops, doing lookup and activate and whatnot), not a wrapper for old API (which would be in a driver mind you)
+/* Driver wrapping API */ +lbaint_t blockdev_read(struct instance *i, lbaint_t start, lbaint_t blkcnt, + void *buffer) +{
- struct blockdev_core_entry *entry = NULL;
- struct blockdev_ops *device_ops = NULL;
- int error;
- entry = get_entry_by_instance(i);
- if (!entry)
return -ENOENT;
- error = driver_activate(i);
- if (error)
return error;
- device_ops = entry->ops;
- if (!device_ops || !device_ops->read)
return -EINVAL;
- return device_ops->read(i, start, blkcnt, buffer);
+}
Pavel Herrmann
Best regards, Marek Vasut

Dear Pavel Herrmann,
[...]
You need the "driver wrapping API" if DM is enabled? I do not understand this, please elaborate!
What about having a common part for both cases and then compile either the DM part or non-DM part conditionally?
this is all DM-only. driver-wrapping API is wrapper/proxy functions to driver ops (aka it wraps around the ops, doing lookup and activate and whatnot), not a wrapper for old API (which would be in a driver mind you)
I see ... do you still fail to understand why I'm being such a documentation/comments bitch?
[...]
Best regards, Marek Vasut

This core provides unified access to different block controllers (SATA, SCSI).
Signed-off-by: Pavel Herrmann morpheus.ibis@gmail.com --- Makefile | 1 + drivers/blockctrl/Makefile | 42 ++++++ drivers/blockctrl/core.c | 349 +++++++++++++++++++++++++++++++++++++++++++++ include/dm/blockctrl.h | 75 ++++++++++ 4 files changed, 467 insertions(+) create mode 100644 drivers/blockctrl/Makefile create mode 100644 drivers/blockctrl/core.c create mode 100644 include/dm/blockctrl.h
diff --git a/Makefile b/Makefile index e43fd9d..4420484 100644 --- a/Makefile +++ b/Makefile @@ -304,6 +304,7 @@ LIBS-y += test/libtest.o LIBS-$(CONFIG_DM) += common/dm/libdm.o LIBS-$(CONFIG_DM) += drivers/demo/libdemo.o LIBS-${CONFIG_DM_BLOCK} += drivers/blockdev/libblockdev.o +LIBS-${CONFIG_DM_BLOCK} += drivers/blockctrl/libblockctrl.o
ifneq ($(CONFIG_AM33XX)$(CONFIG_OMAP34XX)$(CONFIG_OMAP44XX)$(CONFIG_OMAP54XX),) LIBS-y += $(CPUDIR)/omap-common/libomap-common.o diff --git a/drivers/blockctrl/Makefile b/drivers/blockctrl/Makefile new file mode 100644 index 0000000..21a9094 --- /dev/null +++ b/drivers/blockctrl/Makefile @@ -0,0 +1,42 @@ +# See file CREDITS for list of people who contributed to this +# project. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# + +include $(TOPDIR)/config.mk + +LIB := $(obj)libblockctrl.o + +COBJS-${CONFIG_DM_BLOCK} := core.o + +COBJS := $(COBJS-y) +SRCS := $(COBJS:.o=.c) +OBJS := $(addprefix $(obj),$(COBJS)) + +all: $(LIB) + +$(LIB): $(obj).depend $(OBJS) + $(call cmd_link_o_target, $(OBJS)) + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/drivers/blockctrl/core.c b/drivers/blockctrl/core.c new file mode 100644 index 0000000..1f1f834 --- /dev/null +++ b/drivers/blockctrl/core.c @@ -0,0 +1,349 @@ +/* + * (C) Copyright 2012 + * Pavel Herrmann morpheus.ibis@gmail.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <dm/blockctrl.h> +#include <dm/manager.h> +#include <malloc.h> + +struct blockctrl_core_entry { + struct list_head list; + struct instance *instance; + struct blockctrl_ops *ops; +}; + +static struct blockctrl_core_entry *get_entry_by_instance(struct instance *dev) +{ + struct blockctrl_core_entry *entry; + struct core_instance *core = get_core_instance(CORE_BLOCKCTRL); + + if (!core) + return NULL; + + list_for_each_entry(entry, &core->succ, list) { + if (entry->instance == dev) + return entry; + } + + return NULL; +} + +/* Core API functions */ +static int get_count(struct core_instance *core) +{ + int count = 0; + struct blockctrl_core_entry *entry; + + list_for_each_entry(entry, &core->succ, list) { + count++; + } + + return count; +} + +static struct instance *get_child(struct core_instance *core, int index) +{ + struct blockctrl_core_entry *entry = NULL; + + list_for_each_entry(entry, &core->succ, list) { + if (!index) + return entry->instance; + index--; + } + + return NULL; +} + +static int bind(struct core_instance *core, struct instance *dev, void *ops, + void *data) +{ + struct blockctrl_core_entry *entry; + + if (ops == NULL) + return -EINVAL; + + entry = malloc(sizeof(*entry)); + if (entry == NULL) + return -ENOMEM; + + INIT_LIST_HEAD(&entry->list); + entry->instance = dev; + entry->ops = ops; + list_add_tail(&entry->list, &core->succ); + + return 0; +} + +static int unbind(struct core_instance *core, struct instance *dev) +{ + struct blockctrl_core_entry *entry, *n; + + list_for_each_entry_safe(entry, n, &core->succ, list) { + if (entry->instance == dev) { + list_del(&entry->list); + free(entry); + } + } + + return 0; +} + +static int replace(struct core_instance *core, struct instance *new, + struct instance *old) +{ + struct blockctrl_core_entry *entry = get_entry_by_instance(old); + + if (!entry) + return -ENOENT; + + entry->instance = new; + + return 0; +} + +static int init(struct core_instance *core) +{ + INIT_LIST_HEAD(&core->succ); + core->private_data = NULL; + + return 0; +} + +static int reloc(struct core_instance *core, struct core_instance *old) +{ + struct blockctrl_core_entry *entry, *new; + + /* no private_data to copy, yet */ + + /* fixup links in old list and prepare new list head */ + /* FIXME */ + /* list_fix_reloc(&old->succ); */ + INIT_LIST_HEAD(&core->succ); + core->private_data = NULL; + + /* copy list entries to new memory */ + list_for_each_entry(entry, &old->succ, list) { + new = malloc(sizeof(*new)); + if (!new) + return -ENOMEM; + + INIT_LIST_HEAD(&new->list); + new->instance = entry->instance; + new->ops = entry->ops; + list_add_tail(&new->list, &core->succ); + /*no free at this point, old memory should not be freed*/ + } + + return 0; +} + +static int destroy(struct core_instance *core) +{ + struct blockctrl_core_entry *entry, *n; + + /* destroy private data */ + free(core->private_data); + core->private_data = NULL; + + /* destroy successor list */ + list_for_each_entry_safe(entry, n, &core->succ, list) { + list_del(&entry->list); + free(entry); + } + + return 0; +} + +U_BOOT_CORE(CORE_BLOCKCTRL, + init, + reloc, + destroy, + get_count, + get_child, + bind, + unbind, + replace); + +lbaint_t blockctrl_read(struct instance *i, int port, lbaint_t start, + lbaint_t length, void *buffer) +{ + struct blockctrl_core_entry *entry; + struct blockctrl_ops *driver_ops; + int error; + + entry = get_entry_by_instance(i); + if (!entry) + return -ENOENT; + + error = driver_activate(i); + if (error) + return error; + + driver_ops = entry->ops; + if (!driver_ops || !driver_ops->read) + return -EINVAL; + + return driver_ops->read(i, port, start, length, buffer); +} + +lbaint_t blockctrl_write(struct instance *i, int port, lbaint_t start, + lbaint_t length, void *buffer) +{ + struct blockctrl_core_entry *entry; + struct blockctrl_ops *driver_ops; + int error; + + entry = get_entry_by_instance(i); + if (!entry) + return -ENOENT; + + error = driver_activate(i); + if (error) + return error; + + driver_ops = entry->ops; + if (!driver_ops || !driver_ops->write) + return -EINVAL; + + return driver_ops->write(i, port, start, length, buffer); +} + +int blockctrl_scan(struct instance *i, int port) +{ + struct blockctrl_core_entry *entry; + struct blockctrl_ops *driver_ops; + int error; + + entry = get_entry_by_instance(i); + if (!entry) + return -ENOENT; + + error = driver_activate(i); + if (error) + return error; + + driver_ops = entry->ops; + if (!driver_ops || !driver_ops->scan) + return -EINVAL; + + return driver_ops->scan(i, port); +} + +int blockctrl_get_port_count(struct instance *i) +{ + struct blockctrl_core_entry *entry; + struct blockctrl_ops *driver_ops; + int error; + + entry = get_entry_by_instance(i); + if (!entry) + return -ENOENT; + + error = driver_activate(i); + if (error) + return error; + + driver_ops = entry->ops; + if (!driver_ops || !driver_ops->get_port_count) + return -EINVAL; + + return driver_ops->get_port_count(i); +} + +int blockctrl_get_port_option(struct instance *i, int port, + enum blockctrl_port_option_code op, struct option *result) +{ + struct blockctrl_core_entry *entry; + struct blockctrl_ops *driver_ops; + int error; + + entry = get_entry_by_instance(i); + if (!entry) + return -ENOENT; + + error = driver_activate(i); + if (error) + return error; + + driver_ops = entry->ops; + if (!driver_ops || !driver_ops->get_port_option) + return -EINVAL; + + return driver_ops->get_port_option(i, port, op, result); +} + +struct instance *blockctrl_rescan_port(struct instance *i, int port) +{ + /* we assume that all children of blockctrl are blockdev_ata */ + struct instance *child = NULL; + struct blockctrl_core_entry *entry; + struct driver_instance *di; + struct blockdev_ata_platform_data *pdata; + struct driver_info *info; + int nfound; + + entry = get_entry_by_instance(i); + if (!entry) + return NULL; + + list_for_each_entry(di, &i->succ, list) { + if (di->i.info) + pdata = di->i.info->platform_data; + else + pdata = NULL; + + if (pdata && (pdata->port_number == port)) + child = &di->i; + } + + /* + * If we have an active link, we check whether this is a new device, + * in which case we simply bind a new instance, or an old device, + * in which case we reactivate the device to force partition rescan. + * If we dont have an active link, we remove any device attached. + */ + nfound = blockctrl_scan(i, port); + if (!nfound) { + if (child) { + /* rescan the disk size and partitions, just in case */ + driver_remove(child); + scan_partitions(child); + } else { + pdata = malloc(sizeof(*pdata)); + pdata->port_number = port; + info = malloc(sizeof(*info)); + info->platform_data = pdata; + info->name = "blockdev_ata"; + child = driver_bind(i, info); + scan_partitions(child); + return child; + } + } else { + /* link is not active, remove and unbind the child device */ + if (child) { + driver_remove(child); + driver_unbind(child); + } + } + + return NULL; +} diff --git a/include/dm/blockctrl.h b/include/dm/blockctrl.h new file mode 100644 index 0000000..4b6d582 --- /dev/null +++ b/include/dm/blockctrl.h @@ -0,0 +1,75 @@ +/* + * (C) Copyright 2012 + * Pavel Herrmann morpheus.ibis@gmail.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef _DM_BLOCKCTRL_H_ +#define _DM_BLOCKCTRL_H 1 + +#include <dm/structures.h> +#include <dm/blockdev.h> + +enum blockctrl_port_option_code { + BLKP_OPT_IFTYPE = 0, + BLKP_OPT_IFSPEED, + BLKP_OPT_BLOCKSIZE, + BLKP_OPT_BLOCKCOUNT, + BLKP_OPT_REMOVABLE, + BLKP_OPT_LBA48, + BLKP_OPT_VENDOR, + BLKP_OPT_PRODUCT, + BLKP_OPT_REVISION, +}; + +enum blockctrl_iftype { + BLKP_IFTYPE_SATA, + BLKP_IFTYPE_PATA, + BLKP_IFTYPE_SCSI, + BLKP_IFTYPE_VIRTUAL, +}; + + +struct blockctrl_ops { + lbaint_t (*read)(struct instance *i, int port, lbaint_t start, + lbaint_t length, void *buffer); + lbaint_t (*write)(struct instance *i, int port, lbaint_t start, + lbaint_t length, void *buffer); + int (*scan)(struct instance *i, int port); + int (*get_port_count)(struct instance *i); + int (*get_port_option)(struct instance *i, int port, + enum blockctrl_port_option_code op, + struct option *result); +}; + +/* driver wrappers */ +lbaint_t blockctrl_read(struct instance *i, int port, lbaint_t start, + lbaint_t length, void *buffer); +lbaint_t blockctrl_write(struct instance *i, int port, lbaint_t start, + lbaint_t length, void *buffer); +int blockctrl_scan(struct instance *i, int port); +int blockctrl_get_port_count(struct instance *i); +int blockctrl_get_port_option(struct instance *i, int port, + enum blockctrl_port_option_code op, struct option *result); + +/* command helpers */ +struct instance *blockctrl_rescan_port(struct instance *i, int port); + +#endif

Dear Pavel Herrmann,
This core provides unified access to different block controllers (SATA, SCSI).
Description of the patch missing or is sub-par. You should work on this skill.
Signed-off-by: Pavel Herrmann morpheus.ibis@gmail.com
Makefile | 1 + drivers/blockctrl/Makefile | 42 ++++++ drivers/blockctrl/core.c | 349 +++++++++++++++++++++++++++++++++++++++++++++ include/dm/blockctrl.h | 75 ++++++++++ 4 files changed, 467 insertions(+) create mode 100644 drivers/blockctrl/Makefile create mode 100644 drivers/blockctrl/core.c create mode 100644 include/dm/blockctrl.h
diff --git a/Makefile b/Makefile index e43fd9d..4420484 100644 --- a/Makefile +++ b/Makefile @@ -304,6 +304,7 @@ LIBS-y += test/libtest.o LIBS-$(CONFIG_DM) += common/dm/libdm.o LIBS-$(CONFIG_DM) += drivers/demo/libdemo.o LIBS-${CONFIG_DM_BLOCK} += drivers/blockdev/libblockdev.o +LIBS-${CONFIG_DM_BLOCK} += drivers/blockctrl/libblockctrl.o
${} ? What is this ?
[..]
This handles SCSI? Sata ? what ?
Should this not be called scsi_core ? sata_core ? What did the previous core do? sata? scsi? block? I'm lost.
I stop here, I don't know what this is all about, sorry.
Best regards, Marek Vasut

On Thursday 20 of September 2012 22:05:36 Marek Vasut wrote:
Dear Pavel Herrmann,
This core provides unified access to different block controllers (SATA, SCSI).
Description of the patch missing or is sub-par. You should work on this skill.
Signed-off-by: Pavel Herrmann morpheus.ibis@gmail.com
Makefile | 1 + drivers/blockctrl/Makefile | 42 ++++++ drivers/blockctrl/core.c | 349
+++++++++++++++++++++++++++++++++++++++++++++ include/dm/blockctrl.h |
75 ++++++++++ 4 files changed, 467 insertions(+) create mode 100644 drivers/blockctrl/Makefile create mode 100644 drivers/blockctrl/core.c create mode 100644 include/dm/blockctrl.h
diff --git a/Makefile b/Makefile index e43fd9d..4420484 100644 --- a/Makefile +++ b/Makefile @@ -304,6 +304,7 @@ LIBS-y += test/libtest.o
LIBS-$(CONFIG_DM) += common/dm/libdm.o LIBS-$(CONFIG_DM) += drivers/demo/libdemo.o LIBS-${CONFIG_DM_BLOCK} += drivers/blockdev/libblockdev.o
+LIBS-${CONFIG_DM_BLOCK} += drivers/blockctrl/libblockctrl.o
${} ? What is this ?
[..]
This handles SCSI? Sata ? what ?
Should this not be called scsi_core ? sata_core ? What did the previous core do? sata? scsi? block? I'm lost.
the previous core handled disks (and cards and stuff) and partitions (think /dev/sdxy), and was largely a replacement of /disk this core handles any interface those disks are connected to (SATA, PATA, SCSI), and should replace /drivers/block
I stop here, I don't know what this is all about, sorry.
Best regards, Marek Vasut

Dear Pavel Herrmann,
On Thursday 20 of September 2012 22:05:36 Marek Vasut wrote:
Dear Pavel Herrmann,
This core provides unified access to different block controllers (SATA, SCSI).
Description of the patch missing or is sub-par. You should work on this skill.
Signed-off-by: Pavel Herrmann morpheus.ibis@gmail.com
Makefile | 1 + drivers/blockctrl/Makefile | 42 ++++++ drivers/blockctrl/core.c | 349
+++++++++++++++++++++++++++++++++++++++++++++ include/dm/blockctrl.h |
75 ++++++++++ 4 files changed, 467 insertions(+) create mode 100644 drivers/blockctrl/Makefile create mode 100644 drivers/blockctrl/core.c create mode 100644 include/dm/blockctrl.h
diff --git a/Makefile b/Makefile index e43fd9d..4420484 100644 --- a/Makefile +++ b/Makefile @@ -304,6 +304,7 @@ LIBS-y += test/libtest.o
LIBS-$(CONFIG_DM) += common/dm/libdm.o LIBS-$(CONFIG_DM) += drivers/demo/libdemo.o LIBS-${CONFIG_DM_BLOCK} += drivers/blockdev/libblockdev.o
+LIBS-${CONFIG_DM_BLOCK} += drivers/blockctrl/libblockctrl.o
${} ? What is this ?
Why not just reuse drivers/block and in drivers/block compile in the libblock.o so you don't polute the top-level makefile ? Easy as that.
[..]
This handles SCSI? Sata ? what ?
Should this not be called scsi_core ? sata_core ? What did the previous core do? sata? scsi? block? I'm lost.
the previous core handled disks (and cards and stuff) and partitions (think /dev/sdxy), and was largely a replacement of /disk this core handles any interface those disks are connected to (SATA, PATA, SCSI), and should replace /drivers/block
Why is this not in the commit message then ? I have a proposal, before you submit a patchset, prepare it, work on something else for a bit, then read again the commit message only and see if you still understand what it means.
Am I correct that this will look as such: user -> [ 01/11 ] -> [ 03/11 or something else ] -> [ if 03/11, then disc ]
I stop here, I don't know what this is all about, sorry.
Best regards, Marek Vasut
Best regards, Marek Vasut

On Friday 21 of September 2012 14:51:33 Marek Vasut wrote:
Dear Pavel Herrmann,
On Thursday 20 of September 2012 22:05:36 Marek Vasut wrote:
Dear Pavel Herrmann,
This core provides unified access to different block controllers (SATA, SCSI).
Description of the patch missing or is sub-par. You should work on this skill.
Signed-off-by: Pavel Herrmann morpheus.ibis@gmail.com
Makefile | 1 + drivers/blockctrl/Makefile | 42 ++++++ drivers/blockctrl/core.c | 349
+++++++++++++++++++++++++++++++++++++++++++++ include/dm/blockctrl.h
75 ++++++++++ 4 files changed, 467 insertions(+) create mode 100644 drivers/blockctrl/Makefile create mode 100644 drivers/blockctrl/core.c create mode 100644 include/dm/blockctrl.h
diff --git a/Makefile b/Makefile index e43fd9d..4420484 100644 --- a/Makefile +++ b/Makefile @@ -304,6 +304,7 @@ LIBS-y += test/libtest.o
LIBS-$(CONFIG_DM) += common/dm/libdm.o LIBS-$(CONFIG_DM) += drivers/demo/libdemo.o LIBS-${CONFIG_DM_BLOCK} += drivers/blockdev/libblockdev.o
+LIBS-${CONFIG_DM_BLOCK} += drivers/blockctrl/libblockctrl.o
${} ? What is this ?
Why not just reuse drivers/block and in drivers/block compile in the libblock.o so you don't polute the top-level makefile ? Easy as that.
[..]
This handles SCSI? Sata ? what ?
Should this not be called scsi_core ? sata_core ? What did the previous core do? sata? scsi? block? I'm lost.
the previous core handled disks (and cards and stuff) and partitions (think /dev/sdxy), and was largely a replacement of /disk this core handles any interface those disks are connected to (SATA, PATA, SCSI), and should replace /drivers/block
Why is this not in the commit message then ? I have a proposal, before you submit a patchset, prepare it, work on something else for a bit, then read again the commit message only and see if you still understand what it means.
I actually did. the "something else" was splitting it into smaller patches, so the original text information got distributed into the other patches. if i put it all here you would surely complain about it not being there, or it being duplicated
Am I correct that this will look as such: user -> [ 01/11 ] -> [ 03/11 or something else ] -> [ if 03/11, then disc ]
no idea what this means, sorry
Pavel Herrmann

Dear Pavel Herrmann,
On Friday 21 of September 2012 14:51:33 Marek Vasut wrote:
Dear Pavel Herrmann,
On Thursday 20 of September 2012 22:05:36 Marek Vasut wrote:
Dear Pavel Herrmann,
This core provides unified access to different block controllers (SATA, SCSI).
Description of the patch missing or is sub-par. You should work on this skill.
Signed-off-by: Pavel Herrmann morpheus.ibis@gmail.com
Makefile | 1 + drivers/blockctrl/Makefile | 42 ++++++ drivers/blockctrl/core.c | 349
+++++++++++++++++++++++++++++++++++++++++++++ include/dm/blockctrl.h
75 ++++++++++ 4 files changed, 467 insertions(+) create mode 100644 drivers/blockctrl/Makefile create mode 100644 drivers/blockctrl/core.c create mode 100644 include/dm/blockctrl.h
diff --git a/Makefile b/Makefile index e43fd9d..4420484 100644 --- a/Makefile +++ b/Makefile @@ -304,6 +304,7 @@ LIBS-y += test/libtest.o
LIBS-$(CONFIG_DM) += common/dm/libdm.o LIBS-$(CONFIG_DM) += drivers/demo/libdemo.o LIBS-${CONFIG_DM_BLOCK} += drivers/blockdev/libblockdev.o
+LIBS-${CONFIG_DM_BLOCK} += drivers/blockctrl/libblockctrl.o
${} ? What is this ?
Why not just reuse drivers/block and in drivers/block compile in the libblock.o so you don't polute the top-level makefile ? Easy as that.
[..]
This handles SCSI? Sata ? what ?
Should this not be called scsi_core ? sata_core ? What did the previous core do? sata? scsi? block? I'm lost.
the previous core handled disks (and cards and stuff) and partitions (think /dev/sdxy), and was largely a replacement of /disk this core handles any interface those disks are connected to (SATA, PATA, SCSI), and should replace /drivers/block
Why is this not in the commit message then ? I have a proposal, before you submit a patchset, prepare it, work on something else for a bit, then read again the commit message only and see if you still understand what it means.
I actually did. the "something else" was splitting it into smaller patches,
I mean something totally different, so you won't have the code in front of you. You DO understand the code because you wrote it, you need to work on the part where you explain others properly what your change does. Even if it mean writing essay-esque commit message.
so the original text information got distributed into the other patches. if i put it all here you would surely complain about it not being there, or it being duplicated
Not really ...
Am I correct that this will look as such: user -> [ 01/11 ] -> [ 03/11 or something else ] -> [ if 03/11, then disc ]
no idea what this means, sorry
Patch numbers, how the code added in them connect into each other.
Pavel Herrmann
Best regards, Marek Vasut

On Friday 21 of September 2012 15:56:38 Marek Vasut wrote:
Dear Pavel Herrmann,
On Friday 21 of September 2012 14:51:33 Marek Vasut wrote:
Dear Pavel Herrmann,
On Thursday 20 of September 2012 22:05:36 Marek Vasut wrote:
Dear Pavel Herrmann,
This core provides unified access to different block controllers (SATA, SCSI).
Description of the patch missing or is sub-par. You should work on this skill.
Signed-off-by: Pavel Herrmann morpheus.ibis@gmail.com
Makefile | 1 + drivers/blockctrl/Makefile | 42 ++++++ drivers/blockctrl/core.c | 349
+++++++++++++++++++++++++++++++++++++++++++++ include/dm/blockctrl.h
75 ++++++++++ 4 files changed, 467 insertions(+) create mode 100644 drivers/blockctrl/Makefile create mode 100644 drivers/blockctrl/core.c create mode 100644 include/dm/blockctrl.h
diff --git a/Makefile b/Makefile index e43fd9d..4420484 100644 --- a/Makefile +++ b/Makefile @@ -304,6 +304,7 @@ LIBS-y += test/libtest.o
LIBS-$(CONFIG_DM) += common/dm/libdm.o LIBS-$(CONFIG_DM) += drivers/demo/libdemo.o LIBS-${CONFIG_DM_BLOCK} += drivers/blockdev/libblockdev.o
+LIBS-${CONFIG_DM_BLOCK} += drivers/blockctrl/libblockctrl.o
${} ? What is this ?
Why not just reuse drivers/block and in drivers/block compile in the libblock.o so you don't polute the top-level makefile ? Easy as that.
[..]
This handles SCSI? Sata ? what ?
Should this not be called scsi_core ? sata_core ? What did the previous core do? sata? scsi? block? I'm lost.
the previous core handled disks (and cards and stuff) and partitions (think /dev/sdxy), and was largely a replacement of /disk this core handles any interface those disks are connected to (SATA, PATA, SCSI), and should replace /drivers/block
Why is this not in the commit message then ? I have a proposal, before you submit a patchset, prepare it, work on something else for a bit, then read again the commit message only and see if you still understand what it means.
I actually did. the "something else" was splitting it into smaller patches,
I mean something totally different, so you won't have the code in front of you. You DO understand the code because you wrote it, you need to work on the part where you explain others properly what your change does. Even if it mean writing essay-esque commit message.
ok, next time
so the original text information got distributed into the other patches. if i put it all here you would surely complain about it not being there, or it being duplicated
Not really ...
Am I correct that this will look as such: user -> [ 01/11 ] -> [ 03/11 or something else ] -> [ if 03/11, then disc ]
no idea what this means, sorry
Patch numbers, how the code added in them connect into each other.
ok then
user -> [7/11] -> [1/11] -> [5/11] (partition) -> [1/11] -> [5/11] (ata) -> [3/11] -> [4/11] (or another driver)
if you have FS on a whole disk and not just a partition, you omit the first [5/11] -> [1/11] bit, if your filesystem is on a card or a flash driver you replace the [5/11] -> [3/11] bit
Pavel Herrmann

On Friday 21 of September 2012 14:51:33 Marek Vasut wrote:
Dear Pavel Herrmann,
On Thursday 20 of September 2012 22:05:36 Marek Vasut wrote:
Dear Pavel Herrmann,
This core provides unified access to different block controllers (SATA, SCSI).
Description of the patch missing or is sub-par. You should work on this skill.
Signed-off-by: Pavel Herrmann morpheus.ibis@gmail.com
Makefile | 1 + drivers/blockctrl/Makefile | 42 ++++++ drivers/blockctrl/core.c | 349
+++++++++++++++++++++++++++++++++++++++++++++ include/dm/blockctrl.h
75 ++++++++++ 4 files changed, 467 insertions(+) create mode 100644 drivers/blockctrl/Makefile create mode 100644 drivers/blockctrl/core.c create mode 100644 include/dm/blockctrl.h
diff --git a/Makefile b/Makefile index e43fd9d..4420484 100644 --- a/Makefile +++ b/Makefile @@ -304,6 +304,7 @@ LIBS-y += test/libtest.o
LIBS-$(CONFIG_DM) += common/dm/libdm.o LIBS-$(CONFIG_DM) += drivers/demo/libdemo.o LIBS-${CONFIG_DM_BLOCK} += drivers/blockdev/libblockdev.o
+LIBS-${CONFIG_DM_BLOCK} += drivers/blockctrl/libblockctrl.o
${} ? What is this ?
Why not just reuse drivers/block and in drivers/block compile in the libblock.o so you don't polute the top-level makefile ? Easy as that.
to make a distinction between drivers that are converted to new API and those that are not, and to enable drivers to have the same filename for original and converted versions.
Pavel Herrmann

Dear Pavel Herrmann,
On Friday 21 of September 2012 14:51:33 Marek Vasut wrote:
Dear Pavel Herrmann,
On Thursday 20 of September 2012 22:05:36 Marek Vasut wrote:
Dear Pavel Herrmann,
This core provides unified access to different block controllers (SATA, SCSI).
Description of the patch missing or is sub-par. You should work on this skill.
Signed-off-by: Pavel Herrmann morpheus.ibis@gmail.com
Makefile | 1 + drivers/blockctrl/Makefile | 42 ++++++ drivers/blockctrl/core.c | 349
+++++++++++++++++++++++++++++++++++++++++++++ include/dm/blockctrl.h
75 ++++++++++ 4 files changed, 467 insertions(+) create mode 100644 drivers/blockctrl/Makefile create mode 100644 drivers/blockctrl/core.c create mode 100644 include/dm/blockctrl.h
diff --git a/Makefile b/Makefile index e43fd9d..4420484 100644 --- a/Makefile +++ b/Makefile @@ -304,6 +304,7 @@ LIBS-y += test/libtest.o
LIBS-$(CONFIG_DM) += common/dm/libdm.o LIBS-$(CONFIG_DM) += drivers/demo/libdemo.o LIBS-${CONFIG_DM_BLOCK} += drivers/blockdev/libblockdev.o
+LIBS-${CONFIG_DM_BLOCK} += drivers/blockctrl/libblockctrl.o
${} ? What is this ?
Why not just reuse drivers/block and in drivers/block compile in the libblock.o so you don't polute the top-level makefile ? Easy as that.
to make a distinction between drivers that are converted to new API and those that are not, and to enable drivers to have the same filename for original and converted versions.
Can't the old driver just have a compat section in them? Like I did with serial stuff:
1) rename the internal functions to ${driver}_${function_name} from pure ${function_name} and introduce section which behaves as a wrapper (implement ${function_name} calling ${driver}_${function_name} ). 2) Add your DM goo, implement #ifdef around it so either the compat section or DM section is enabled.
How does that work? It's much cleaner.
Pavel Herrmann
Best regards, Marek Vasut

On Friday 21 of September 2012 15:58:55 Marek Vasut wrote:
Dear Pavel Herrmann,
On Friday 21 of September 2012 14:51:33 Marek Vasut wrote:
Dear Pavel Herrmann,
On Thursday 20 of September 2012 22:05:36 Marek Vasut wrote:
Dear Pavel Herrmann,
This core provides unified access to different block controllers (SATA, SCSI).
Description of the patch missing or is sub-par. You should work on this skill.
Signed-off-by: Pavel Herrmann morpheus.ibis@gmail.com
Makefile | 1 + drivers/blockctrl/Makefile | 42 ++++++ drivers/blockctrl/core.c | 349
+++++++++++++++++++++++++++++++++++++++++++++ include/dm/blockctrl.h
75 ++++++++++ 4 files changed, 467 insertions(+) create mode 100644 drivers/blockctrl/Makefile create mode 100644 drivers/blockctrl/core.c create mode 100644 include/dm/blockctrl.h
diff --git a/Makefile b/Makefile index e43fd9d..4420484 100644 --- a/Makefile +++ b/Makefile @@ -304,6 +304,7 @@ LIBS-y += test/libtest.o
LIBS-$(CONFIG_DM) += common/dm/libdm.o LIBS-$(CONFIG_DM) += drivers/demo/libdemo.o LIBS-${CONFIG_DM_BLOCK} += drivers/blockdev/libblockdev.o
+LIBS-${CONFIG_DM_BLOCK} += drivers/blockctrl/libblockctrl.o
${} ? What is this ?
Why not just reuse drivers/block and in drivers/block compile in the libblock.o so you don't polute the top-level makefile ? Easy as that.
to make a distinction between drivers that are converted to new API and those that are not, and to enable drivers to have the same filename for original and converted versions.
Can't the old driver just have a compat section in them? Like I did with serial stuff:
- rename the internal functions to ${driver}_${function_name} from pure
${function_name} and introduce section which behaves as a wrapper (implement ${function_name} calling ${driver}_${function_name} ). 2) Add your DM goo, implement #ifdef around it so either the compat section or DM section is enabled.
I actually did something of this sort, see [4/11], with less touching.
the problem is that while SATA drivers are easy to convert, IDE ones are not. I would actually propose to do a ide_legacy driver (mostly out of the code currently in common/cmd_ide.c), and keep it as the only option until IDE dies completely.
How does that work? It's much cleaner.
Pavel Herrmann
Best regards, Marek Vasut

Dear Pavel Herrmann,
[...]
Can't the old driver just have a compat section in them? Like I did with serial stuff:
- rename the internal functions to ${driver}_${function_name} from pure
${function_name} and introduce section which behaves as a wrapper (implement ${function_name} calling ${driver}_${function_name} ). 2) Add your DM goo, implement #ifdef around it so either the compat section or DM section is enabled.
I actually did something of this sort, see [4/11], with less touching.
the problem is that while SATA drivers are easy to convert, IDE ones are not. I would actually propose to do a ide_legacy driver (mostly out of the code currently in common/cmd_ide.c), and keep it as the only option until IDE dies completely.
IDE will be around for a LONG time.
You introduce that CONFIG_SYS_SATA_LEGACY for no reason, if you did it as said above, simple CONFIG_DM would suffice as the drivers would be intacts with DM disabled. Note the compiler will opt-out these proxy calls.
Besides, with this approach of yours, you need to enable SATA_LEGACY for every single board now, introducing a lot of churn into the patches and if it's not defined, every board using SATA is broken, right?
How does that work? It's much cleaner.
Pavel Herrmann
Best regards, Marek Vasut
Best regards, Marek Vasut

On Friday 21 of September 2012 17:39:21 Marek Vasut wrote:
Dear Pavel Herrmann,
[...]
Can't the old driver just have a compat section in them? Like I did with serial stuff:
- rename the internal functions to ${driver}_${function_name} from pure
${function_name} and introduce section which behaves as a wrapper (implement ${function_name} calling ${driver}_${function_name} ). 2) Add your DM goo, implement #ifdef around it so either the compat section or DM section is enabled.
I actually did something of this sort, see [4/11], with less touching.
the problem is that while SATA drivers are easy to convert, IDE ones are not. I would actually propose to do a ide_legacy driver (mostly out of the code currently in common/cmd_ide.c), and keep it as the only option until IDE dies completely.
IDE will be around for a LONG time.
You introduce that CONFIG_SYS_SATA_LEGACY for no reason, if you did it as said above, simple CONFIG_DM would suffice as the drivers would be intacts with DM disabled. Note the compiler will opt-out these proxy calls.
Besides, with this approach of yours, you need to enable SATA_LEGACY for every single board now, introducing a lot of churn into the patches and if it's not defined, every board using SATA is broken, right?
No, if you dont define CONFIG_DM, you get the old way of interacting with disks. only if you define CONFIG_DM you only need CONFIG_SATA_LEGACY to plug old SATA drivers into DM codepaths
How does that work? It's much cleaner.
Pavel Herrmann
Best regards, Marek Vasut
Best regards, Marek Vasut

Dear Pavel Herrmann,
On Friday 21 of September 2012 17:39:21 Marek Vasut wrote:
Dear Pavel Herrmann,
[...]
Can't the old driver just have a compat section in them? Like I did with serial stuff:
- rename the internal functions to ${driver}_${function_name} from
pure ${function_name} and introduce section which behaves as a wrapper (implement ${function_name} calling ${driver}_${function_name} ). 2) Add your DM goo, implement #ifdef around it so either the compat section or DM section is enabled.
I actually did something of this sort, see [4/11], with less touching.
the problem is that while SATA drivers are easy to convert, IDE ones are not. I would actually propose to do a ide_legacy driver (mostly out of the code currently in common/cmd_ide.c), and keep it as the only option until IDE dies completely.
IDE will be around for a LONG time.
You introduce that CONFIG_SYS_SATA_LEGACY for no reason, if you did it as said above, simple CONFIG_DM would suffice as the drivers would be intacts with DM disabled. Note the compiler will opt-out these proxy calls.
Besides, with this approach of yours, you need to enable SATA_LEGACY for every single board now, introducing a lot of churn into the patches and if it's not defined, every board using SATA is broken, right?
No, if you dont define CONFIG_DM, you get the old way of interacting with disks. only if you define CONFIG_DM you only need CONFIG_SATA_LEGACY to plug old SATA drivers into DM codepaths
So if you enable DM for a board, you also need to enable this compat layer? My opinion is, that you either enable DM on the board and the board is ready for it or don't enable it.
Would you need the compat layer at all were you to follow my advice?
The whole idea goes deeper, see if you prepended this patchset with such a conversion as above, you'd already have a readily defined structure of blockdev operations in each driver to use in this patchset. This patchset would then really only be the DM stuff. The DM-part addition to the drivers would be mechanical.
How does that work? It's much cleaner.
Pavel Herrmann
Best regards, Marek Vasut
Best regards, Marek Vasut
Best regards, Marek Vasut

On Friday 21 of September 2012 18:08:13 Marek Vasut wrote:
Dear Pavel Herrmann,
On Friday 21 of September 2012 17:39:21 Marek Vasut wrote:
Dear Pavel Herrmann,
[...]
Can't the old driver just have a compat section in them? Like I did with serial stuff:
- rename the internal functions to ${driver}_${function_name} from
pure ${function_name} and introduce section which behaves as a wrapper (implement ${function_name} calling ${driver}_${function_name} ). 2) Add your DM goo, implement #ifdef around it so either the compat section or DM section is enabled.
I actually did something of this sort, see [4/11], with less touching.
the problem is that while SATA drivers are easy to convert, IDE ones are not. I would actually propose to do a ide_legacy driver (mostly out of the code currently in common/cmd_ide.c), and keep it as the only option until IDE dies completely.
IDE will be around for a LONG time.
You introduce that CONFIG_SYS_SATA_LEGACY for no reason, if you did it as said above, simple CONFIG_DM would suffice as the drivers would be intacts with DM disabled. Note the compiler will opt-out these proxy calls.
Besides, with this approach of yours, you need to enable SATA_LEGACY for every single board now, introducing a lot of churn into the patches and if it's not defined, every board using SATA is broken, right?
No, if you dont define CONFIG_DM, you get the old way of interacting with disks. only if you define CONFIG_DM you only need CONFIG_SATA_LEGACY to plug old SATA drivers into DM codepaths
So if you enable DM for a board, you also need to enable this compat layer? My opinion is, that you either enable DM on the board and the board is ready for it or don't enable it.
if you enable DM on a board, you can either use the compat layer and the old driver, or use a ported driver and get rid of the compat layer
Would you need the compat layer at all were you to follow my advice?
if i understand what you meant, i would build this compat layer into every one of the drivers currently in tree (with some cleanup). in that case, i would not need it
The whole idea goes deeper, see if you prepended this patchset with such a conversion as above, you'd already have a readily defined structure of blockdev operations in each driver to use in this patchset. This patchset would then really only be the DM stuff. The DM-part addition to the drivers would be mechanical.
How does that work? It's much cleaner.
Pavel Herrmann
Best regards, Marek Vasut
Best regards, Marek Vasut
Best regards, Marek Vasut

Dear Pavel Herrmann,
On Friday 21 of September 2012 18:08:13 Marek Vasut wrote:
Dear Pavel Herrmann,
On Friday 21 of September 2012 17:39:21 Marek Vasut wrote:
Dear Pavel Herrmann,
[...]
Can't the old driver just have a compat section in them? Like I did with serial stuff:
- rename the internal functions to ${driver}_${function_name}
from pure ${function_name} and introduce section which behaves as a wrapper (implement ${function_name} calling ${driver}_${function_name} ). 2) Add your DM goo, implement #ifdef around it so either the compat section or DM section is enabled.
I actually did something of this sort, see [4/11], with less touching.
the problem is that while SATA drivers are easy to convert, IDE ones are not. I would actually propose to do a ide_legacy driver (mostly out of the code currently in common/cmd_ide.c), and keep it as the only option until IDE dies completely.
IDE will be around for a LONG time.
You introduce that CONFIG_SYS_SATA_LEGACY for no reason, if you did it as said above, simple CONFIG_DM would suffice as the drivers would be intacts with DM disabled. Note the compiler will opt-out these proxy calls.
Besides, with this approach of yours, you need to enable SATA_LEGACY for every single board now, introducing a lot of churn into the patches and if it's not defined, every board using SATA is broken, right?
No, if you dont define CONFIG_DM, you get the old way of interacting with disks. only if you define CONFIG_DM you only need CONFIG_SATA_LEGACY to plug old SATA drivers into DM codepaths
So if you enable DM for a board, you also need to enable this compat layer? My opinion is, that you either enable DM on the board and the board is ready for it or don't enable it.
if you enable DM on a board, you can either use the compat layer and the old driver, or use a ported driver and get rid of the compat layer
Would you need the compat layer at all were you to follow my advice?
if i understand what you meant, i would build this compat layer into every one of the drivers currently in tree (with some cleanup). in that case, i would not need it
That's correct. You would prepare every driver to be DM-ish and the final deployment of DM would be mechanical. So would be the removal of the non-DM part later on.
The whole idea goes deeper, see if you prepended this patchset with such a conversion as above, you'd already have a readily defined structure of blockdev operations in each driver to use in this patchset. This patchset would then really only be the DM stuff. The DM-part addition to the drivers would be mechanical.
How does that work? It's much cleaner.
> Pavel Herrmann
Best regards, Marek Vasut
Best regards, Marek Vasut
Best regards, Marek Vasut
Best regards, Marek Vasut

On Friday 21 of September 2012 20:01:27 Marek Vasut wrote:
Dear Pavel Herrmann,
On Friday 21 of September 2012 18:08:13 Marek Vasut wrote:
Dear Pavel Herrmann,
On Friday 21 of September 2012 17:39:21 Marek Vasut wrote:
Dear Pavel Herrmann,
[...]
> Can't the old driver just have a compat section in them? Like I > did with serial stuff: > > 1) rename the internal functions to ${driver}_${function_name} > from pure ${function_name} and introduce section which behaves > as a wrapper (implement ${function_name} calling > ${driver}_${function_name} ). 2) Add your DM goo, implement > #ifdef around it so either the compat section or DM section is > enabled.
I actually did something of this sort, see [4/11], with less touching.
the problem is that while SATA drivers are easy to convert, IDE ones are not. I would actually propose to do a ide_legacy driver (mostly out of the code currently in common/cmd_ide.c), and keep it as the only option until IDE dies completely.
IDE will be around for a LONG time.
You introduce that CONFIG_SYS_SATA_LEGACY for no reason, if you did it as said above, simple CONFIG_DM would suffice as the drivers would be intacts with DM disabled. Note the compiler will opt-out these proxy calls.
Besides, with this approach of yours, you need to enable SATA_LEGACY for every single board now, introducing a lot of churn into the patches and if it's not defined, every board using SATA is broken, right?
No, if you dont define CONFIG_DM, you get the old way of interacting with disks. only if you define CONFIG_DM you only need CONFIG_SATA_LEGACY to plug old SATA drivers into DM codepaths
So if you enable DM for a board, you also need to enable this compat layer? My opinion is, that you either enable DM on the board and the board is ready for it or don't enable it.
if you enable DM on a board, you can either use the compat layer and the old driver, or use a ported driver and get rid of the compat layer
Would you need the compat layer at all were you to follow my advice?
if i understand what you meant, i would build this compat layer into every one of the drivers currently in tree (with some cleanup). in that case, i would not need it
That's correct. You would prepare every driver to be DM-ish and the final deployment of DM would be mechanical. So would be the removal of the non-DM part later on.
that would lead to massive code duplication. im not talking about the SATA drivers now, there its just about ready for DM already (static for all functions, remove dependency on static block_dev_desc array, include driver registration functions, done), but about IDE drivers, where the drivers have ~200 lines, whereas cmd_ide.c has ~2000 lines. as for the SCSI drivers, ahci.c is not really SCSI, more like a SATA driver with SCSI wrapper built in, the other one is a bit more complex, and would require some wrapper code addition (cmd_scsi is ~600 lines)
The whole idea goes deeper, see if you prepended this patchset with such a conversion as above, you'd already have a readily defined structure of blockdev operations in each driver to use in this patchset. This patchset would then really only be the DM stuff. The DM-part addition to the drivers would be mechanical.
> How does that work? It's much cleaner. > > > Pavel Herrmann > > Best regards, > Marek Vasut
Best regards, Marek Vasut
Best regards, Marek Vasut
Best regards, Marek Vasut

Dear Pavel Herrmann,
On Friday 21 of September 2012 20:01:27 Marek Vasut wrote:
Dear Pavel Herrmann,
On Friday 21 of September 2012 18:08:13 Marek Vasut wrote:
Dear Pavel Herrmann,
On Friday 21 of September 2012 17:39:21 Marek Vasut wrote:
Dear Pavel Herrmann,
[...]
> > Can't the old driver just have a compat section in them? Like > > I did with serial stuff: > > > > 1) rename the internal functions to > > ${driver}_${function_name} from pure ${function_name} and > > introduce section which behaves as a wrapper (implement > > ${function_name} calling > > ${driver}_${function_name} ). 2) Add your DM goo, implement > > #ifdef around it so either the compat section or DM section > > is enabled. > > I actually did something of this sort, see [4/11], with less > touching. > > the problem is that while SATA drivers are easy to convert, IDE > ones are not. I would actually propose to do a ide_legacy > driver (mostly out of the code currently in common/cmd_ide.c), > and keep it as the only option until IDE dies completely.
IDE will be around for a LONG time.
You introduce that CONFIG_SYS_SATA_LEGACY for no reason, if you did it as said above, simple CONFIG_DM would suffice as the drivers would be intacts with DM disabled. Note the compiler will opt-out these proxy calls.
Besides, with this approach of yours, you need to enable SATA_LEGACY for every single board now, introducing a lot of churn into the patches and if it's not defined, every board using SATA is broken, right?
No, if you dont define CONFIG_DM, you get the old way of interacting with disks. only if you define CONFIG_DM you only need CONFIG_SATA_LEGACY to plug old SATA drivers into DM codepaths
So if you enable DM for a board, you also need to enable this compat layer? My opinion is, that you either enable DM on the board and the board is ready for it or don't enable it.
if you enable DM on a board, you can either use the compat layer and the old driver, or use a ported driver and get rid of the compat layer
Would you need the compat layer at all were you to follow my advice?
if i understand what you meant, i would build this compat layer into every one of the drivers currently in tree (with some cleanup). in that case, i would not need it
That's correct. You would prepare every driver to be DM-ish and the final deployment of DM would be mechanical. So would be the removal of the non-DM part later on.
that would lead to massive code duplication.
How?
im not talking about the SATA drivers now, there its just about ready for DM already (static for all functions, remove dependency on static block_dev_desc array, include driver registration functions, done), but about IDE drivers, where the drivers have ~200 lines, whereas cmd_ide.c has ~2000 lines.
IDE implements some nasty hooks into cmd_ide.c, right ? I think if you managed to clean up and analyze cmd_ide.c, it'd be possible to figure out a path to fix the IDE drivers.
as for the SCSI drivers, ahci.c is not really SCSI, more like a SATA driver with SCSI wrapper built in, the other one is a bit more complex, and would require some wrapper code addition (cmd_scsi is ~600 lines)
Might need some thinking here. Can the SCSI handling be abstracted out?
[...]
Best regards, Marek Vasut

This driver works by wrapping the old SATA API to new blockctrl API
Signed-off-by: Pavel Herrmann morpheus.ibis@gmail.com --- drivers/blockctrl/Makefile | 1 + drivers/blockctrl/sata_legacy.c | 166 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 167 insertions(+) create mode 100644 drivers/blockctrl/sata_legacy.c
diff --git a/drivers/blockctrl/Makefile b/drivers/blockctrl/Makefile index 21a9094..5df1ce1 100644 --- a/drivers/blockctrl/Makefile +++ b/drivers/blockctrl/Makefile @@ -22,6 +22,7 @@ include $(TOPDIR)/config.mk LIB := $(obj)libblockctrl.o
COBJS-${CONFIG_DM_BLOCK} := core.o +COBJS-${CONFIG_BLOCK_SATA_LEGACY} += sata_legacy.o
COBJS := $(COBJS-y) SRCS := $(COBJS:.o=.c) diff --git a/drivers/blockctrl/sata_legacy.c b/drivers/blockctrl/sata_legacy.c new file mode 100644 index 0000000..9cc41a2 --- /dev/null +++ b/drivers/blockctrl/sata_legacy.c @@ -0,0 +1,166 @@ +/* + * (C) Copyright 2012 + * Pavel Herrmann morpheus.ibis@gmail.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <dm/blockctrl.h> +#include <dm/structures.h> +#include <dm/manager.h> +#include <sata.h> + +block_dev_desc_t sata_dev_desc[CONFIG_SYS_SATA_MAX_DEVICE]; + +static lbaint_t read(struct instance *i, int port, lbaint_t start, + lbaint_t length, void *buffer) +{ + return sata_read(port, start, length, buffer); +} + +static lbaint_t write(struct instance *i, int port, lbaint_t start, + lbaint_t length, void *buffer) +{ + return sata_write(port, start, length, buffer); +} + +static int scan(struct instance *i, int port) +{ + int error; + + error = scan_sata(port); + if (error) + return error; + + if (!sata_dev_desc[port].lba) + return -ENOENT; + + return 0; +} + +static int get_port_count(struct instance *i) +{ + return CONFIG_SYS_SATA_MAX_DEVICE; +} + +static int get_port_option(struct instance *i, int port, + enum blockctrl_port_option_code op, struct option *result) +{ + switch (op) { + case BLKP_OPT_IFTYPE: + result->flags = OPTION_TYPE_U; + result->data.data_u = BLKP_IFTYPE_SATA; + return 0; + case BLKP_OPT_IFSPEED: + result->flags = OPTION_TYPE_U; + result->data.data_u = 150; + return 0; + case BLKP_OPT_BLOCKSIZE: + result->flags = OPTION_TYPE_U; + result->data.data_u = sata_dev_desc[port].blksz; + return 0; + case BLKP_OPT_BLOCKCOUNT: + result->flags = OPTION_TYPE_U; + result->data.data_u = sata_dev_desc[port].lba; + return 0; + case BLKP_OPT_REMOVABLE: + result->flags = OPTION_TYPE_U; + result->data.data_u = sata_dev_desc[port].removable; + return 0; + case BLKP_OPT_LBA48: +#ifdef CONFIG_LBA48 + result->flags = OPTION_TYPE_U; + result->data.data_u = sata_dev_desc[port].lba48; + return 0; +#else + return -EINVAL; +#endif + case BLKP_OPT_VENDOR: + result->flags = OPTION_TYPE_S; + result->data.data_s = sata_dev_desc[port].vendor; + return 0; + case BLKP_OPT_PRODUCT: + result->flags = OPTION_TYPE_S; + result->data.data_s = sata_dev_desc[port].product; + return 0; + case BLKP_OPT_REVISION: + result->flags = OPTION_TYPE_S; + result->data.data_s = sata_dev_desc[port].revision; + return 0; + } + return -EINVAL; +} + +static struct blockctrl_ops ops = { + .read = read, + .write = write, + .scan = scan, + .get_port_count = get_port_count, + .get_port_option = get_port_option, +}; + +static int sata_init(void) +{ + int rc; + int i; + + for (i = 0; i < CONFIG_SYS_SATA_MAX_DEVICE; i++) { + memset(&sata_dev_desc[i], 0, sizeof(struct block_dev_desc)); + sata_dev_desc[i].if_type = IF_TYPE_SATA; + sata_dev_desc[i].dev = i; + sata_dev_desc[i].part_type = PART_TYPE_UNKNOWN; + sata_dev_desc[i].type = DEV_TYPE_HARDDISK; + sata_dev_desc[i].lba = 0; + sata_dev_desc[i].blksz = 512; + sata_dev_desc[i].block_read = sata_read; + sata_dev_desc[i].block_write = sata_write; + + rc = init_sata(i); + if (!rc) + rc = scan_sata(i); + } + return rc; +} + +static int bind(struct instance *dev) +{ + return core_bind(CORE_BLOCKCTRL, dev, &ops, NULL); +} + +static int probe(struct instance *dev) +{ + return sata_init(); +} + +static int reloc(struct instance *dev, struct instance *old) +{ + return core_replace(CORE_BLOCKCTRL, dev, old); +} + +static int remove(struct instance *dev) +{ + return 0; +} + +static int unbind(struct instance *dev) +{ + return core_unbind(CORE_BLOCKDEV, dev); +} + +U_BOOT_DRIVER(sata_legacy, bind, probe, reloc, remove, unbind);

ata blockdev is an universal child of a blockctrl device, be it (P/S)ATA or SCSI partition blockdev is a child of other blockdev drivers
Signed-off-by: Pavel Herrmann morpheus.ibis@gmail.com --- drivers/blockdev/Makefile | 2 +- drivers/blockdev/ata.c | 234 +++++++++++++++++++++++++++++++++++++++++++ drivers/blockdev/ata.h | 37 +++++++ drivers/blockdev/partition.c | 179 +++++++++++++++++++++++++++++++++ 4 files changed, 451 insertions(+), 1 deletion(-) create mode 100644 drivers/blockdev/ata.c create mode 100644 drivers/blockdev/ata.h create mode 100644 drivers/blockdev/partition.c
diff --git a/drivers/blockdev/Makefile b/drivers/blockdev/Makefile index a988924..668ffbd 100644 --- a/drivers/blockdev/Makefile +++ b/drivers/blockdev/Makefile @@ -21,7 +21,7 @@ include $(TOPDIR)/config.mk
LIB := $(obj)libblockdev.o
-COBJS-${CONFIG_DM_BLOCK} := core.o +COBJS-${CONFIG_DM_BLOCK} := core.o ata.o partition.o COBJS-${CONFIG_DOS_PARTITION} += part_types/part_dos.o
COBJS := $(COBJS-y) diff --git a/drivers/blockdev/ata.c b/drivers/blockdev/ata.c new file mode 100644 index 0000000..698dc18 --- /dev/null +++ b/drivers/blockdev/ata.c @@ -0,0 +1,234 @@ +/* + * (C) Copyright 2012 + * Pavel Herrmann morpheus.ibis@gmail.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include "ata.h" +#include <dm/blockctrl.h> +#include <dm/manager.h> +#include <common.h> +#include <malloc.h> + +static lbaint_t read(struct instance *dev, lbaint_t start, lbaint_t blkcnt, + void *buffer) +{ + if (!buffer) + return 0; + + struct blockdev_ata_platform_data *platform = dev->info->platform_data; + struct blockdev_ata_private_data *priv = dev->private_data; + /* check for access beyond disk boundary */ + if ((start + blkcnt) > priv->block_count) + blkcnt = (priv->block_count - start); + + return blockctrl_read(dev->bus, platform->port_number, + start, blkcnt, buffer); +} + +static lbaint_t write(struct instance *dev, lbaint_t start, lbaint_t blkcnt, + void *buffer) +{ + if (!buffer) + return 0; + + struct blockdev_ata_platform_data *platform = dev->info->platform_data; + struct blockdev_ata_private_data *priv = dev->private_data; + /* check for access beyond disk boundary */ + if ((start + blkcnt) > priv->block_count) + blkcnt = (priv->block_count - start); + + return blockctrl_write(dev->bus, platform->port_number, + start, blkcnt, buffer); +} + +static lbaint_t erase(struct instance *dev, lbaint_t start, lbaint_t blkcnt) +{ + /* TRIM is not supported on ATA, so we just pretend to do something */ + return blkcnt; +} + +static int get_option(struct instance *dev, enum blockdev_option_code op, + struct option *result) +{ + struct blockdev_ata_private_data *priv = dev->private_data; + struct blockdev_ata_platform_data *plat = dev->info->platform_data; + int port = plat->port_number; + + if (!result || !priv) + return -EINVAL; + + switch (op) { + case BLKD_OPT_IFTYPE: + result->flags = OPTION_TYPE_U; + result->data.data_u = BLOCKDEV_IFTYPE_ATA; + return 0; + case BLKD_OPT_TYPE: + result->flags = OPTION_TYPE_U; + result->data.data_u = BLOCKDEV_TYPE_HARDDISK; + return 0; + case BLKD_OPT_OFFSET: + result->flags = OPTION_TYPE_U; + result->data.data_u = 0; + return 0; + case BLKD_OPT_BLOCKSIZE: + result->flags = OPTION_TYPE_U; + result->data.data_u = priv->block_size; + return 0; + case BLKD_OPT_BLOCKCOUNT: + result->flags = OPTION_TYPE_U; + result->data.data_u = priv->block_count; + return 0; + case BLKD_OPT_VENDOR: + result->flags = OPTION_TYPE_S; + result->data.data_s = priv->vendor; + return 0; + case BLKD_OPT_PRODUCT: + result->flags = OPTION_TYPE_S; + result->data.data_s = priv->product; + return 0; + case BLKD_OPT_REVISION: + result->flags = OPTION_TYPE_S; + result->data.data_s = priv->revision; + return 0; + case BLKD_OPT_LBA48: + return blockctrl_get_port_option(dev->bus, port, + BLKP_OPT_LBA48, result); + default: + break; + /* TODO: more options */ + + } + return -EINVAL; +} + +static int set_option(struct instance *dev, enum blockdev_option_code op, + struct option *value) +{ + /* there are currently no meaningful options to set */ + return -EINVAL; +} + +static struct blockdev_ops ops = { + .read = read, + .write = write, + .erase = erase, + .get_option = get_option, + .set_option = set_option, +}; + + +static int bind(struct instance *dev) +{ + /* prepare hint for the core to properly identify this as a ATA disk */ + struct blockdev_core_hint hint = { + .iftype = BLOCKDEV_IFTYPE_ATA + }; + core_bind(CORE_BLOCKDEV, dev, &ops, &hint); + return 0; +} + +static int probe(struct instance *dev) +{ + struct option op; + struct blockdev_ata_private_data *priv; + int error; + struct blockdev_ata_platform_data *plat = dev->info->platform_data; + int port = plat->port_number; + + priv = calloc(sizeof(*priv), 1); + if (!priv) + return -ENOMEM; + + error = blockctrl_get_port_option(dev->bus, port, BLKP_OPT_BLOCKSIZE, + &op); + if (error || (OPTION_TYPE(op) != OPTION_TYPE_U)) + return -EINVAL; + priv->block_size = op.data.data_u; + + error = blockctrl_get_port_option(dev->bus, port, BLKP_OPT_BLOCKCOUNT, + &op); + if (error || (OPTION_TYPE(op) != OPTION_TYPE_U)) + return -EINVAL; + priv->block_count = op.data.data_u; + + error = blockctrl_get_port_option(dev->bus, port, BLKP_OPT_VENDOR, &op); + if (error || (OPTION_TYPE(op) != OPTION_TYPE_S)) + return -EINVAL; + strncpy(priv->vendor, op.data.data_s, 40); + priv->vendor[40] = 0; + if (op.flags & OPTION_PTR_MALLOCED) + free(op.data.data_s); + + error = blockctrl_get_port_option(dev->bus, port, BLKP_OPT_PRODUCT, + &op); + if (error || (OPTION_TYPE(op) != OPTION_TYPE_S)) + return -EINVAL; + strncpy(priv->product, op.data.data_s, 20); + priv->vendor[20] = 0; + if (op.flags & OPTION_PTR_MALLOCED) + free(op.data.data_s); + + error = blockctrl_get_port_option(dev->bus, port, BLKP_OPT_REVISION, + &op); + if (error || (OPTION_TYPE(op) != OPTION_TYPE_S)) + return -EINVAL; + strncpy(priv->revision, op.data.data_s, 8); + priv->revision[8] = 0; + if (op.flags & OPTION_PTR_MALLOCED) + free(op.data.data_s); + + dev->private_data = priv; + + return 0; +} + +static int reloc(struct instance *dev, struct instance *old) +{ + core_replace(CORE_BLOCKDEV, dev, old); + dev->private_data = malloc(sizeof(struct blockdev_ata_private_data)); + if (!dev->private_data) + return -ENOMEM; + + memcpy(dev->private_data, old->private_data, + sizeof(struct blockdev_ata_private_data)); + + return 0; +} + +static int remove(struct instance *dev) +{ + /* remove our metadata cache */ + free(dev->private_data); + return 0; +} + +static int unbind(struct instance *dev) +{ + core_unbind(CORE_BLOCKDEV, dev); + return 0; +} + +U_BOOT_DRIVER(blockdev_ata, + bind, + probe, + reloc, + remove, + unbind); diff --git a/drivers/blockdev/ata.h b/drivers/blockdev/ata.h new file mode 100644 index 0000000..da63b5d --- /dev/null +++ b/drivers/blockdev/ata.h @@ -0,0 +1,37 @@ +/* + * (C) Copyright 2012 + * Pavel Herrmann morpheus.ibis@gmail.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef _BLOCKDEV_ATA_H_ +#define _BLOCKDEV_ATA_H_ +#include <dm/blockdev.h> + +struct blockdev_ata_private_data { + /* cache for get_option() */ + lbaint_t block_size; + lbaint_t block_count; + char vendor[40+1]; + char product[20+1]; + char revision[8+1]; +}; + +#endif diff --git a/drivers/blockdev/partition.c b/drivers/blockdev/partition.c new file mode 100644 index 0000000..c5c0f48 --- /dev/null +++ b/drivers/blockdev/partition.c @@ -0,0 +1,179 @@ +/* + * (C) Copyright 2012 + * Pavel Herrmann morpheus.ibis@gmail.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <dm/blockdev.h> +#include <dm/manager.h> + +static lbaint_t read(struct instance *dev, lbaint_t start, lbaint_t blkcnt, + void *buffer) +{ + if (!buffer) + return 0; + + struct blockdev_partition_platform_data *platform = + dev->info->platform_data; + /* check for access beyond partition boundary */ + if ((start + blkcnt) > platform->block_count) + blkcnt = (platform->block_count - start); + + start += platform->offset; + + return blockdev_read(dev->bus, start, blkcnt, buffer); +} + +static lbaint_t write(struct instance *dev, lbaint_t start, lbaint_t blkcnt, + void *buffer) +{ + if (!buffer) + return 0; + + struct blockdev_partition_platform_data *platform = + dev->info->platform_data; + /* check for access beyond partition boundary */ + if ((start + blkcnt) > platform->block_count) + blkcnt = (platform->block_count - start); + + start += platform->offset; + + return blockdev_write(dev->bus, start, blkcnt, buffer); +} + +static lbaint_t erase(struct instance *dev, lbaint_t start, lbaint_t blkcnt) +{ + struct blockdev_partition_platform_data *platform = + dev->info->platform_data; + /* check for access beyond partition boundary */ + if ((start + blkcnt) > platform->block_count) + blkcnt = (platform->block_count - start); + + start += platform->offset; + + return blockdev_erase(dev->bus, start, blkcnt); +} + +static int get_option(struct instance *dev, enum blockdev_option_code op, + struct option *result) +{ + if (!result) + return -EINVAL; + + struct blockdev_partition_platform_data *platform = + dev->info->platform_data; + + switch (op) { + case BLKD_OPT_TYPE: + result->flags = OPTION_TYPE_U; + result->data.data_u = BLOCKDEV_TYPE_PARTITION; + return 0; + case BLKD_OPT_BLOCKCOUNT: + result->flags = OPTION_TYPE_U; + result->data.data_u = platform->block_count; + return 0; + case BLKD_OPT_OFFSET: + result->flags = OPTION_TYPE_U; + result->data.data_u = platform->offset; + return 0; + case BLKD_OPT_IFTYPE: + case BLKD_OPT_BLOCKSIZE: + case BLKD_OPT_REMOVABLE: + case BLKD_OPT_LBA48: + case BLKD_OPT_VENDOR: + case BLKD_OPT_PRODUCT: + case BLKD_OPT_REVISION: + case BLKD_OPT_SCSILUN: + case BLKD_OPT_SCSITARGET: + return blockdev_get_option(dev->bus, op, result); + + default: + break; + } + + return -EINVAL; +} + + +static int set_option(struct instance *dev, enum blockdev_option_code op, + struct option *value) +{ + /* there are currently no meaningful options to set */ + return -EINVAL; +} + +static struct blockdev_ops ops = { + .read = read, + .write = write, + .erase = erase, + .get_option = get_option, + .set_option = set_option +}; + + +static int bind(struct instance *dev) +{ + /* prepare hint for the core to properly identify this as a partition */ + struct blockdev_partition_platform_data *platform = + dev->info->platform_data; + + struct blockdev_core_hint hint = { + .iftype = BLOCKDEV_IFTYPE_PARTITION, + .part_number = platform->part_number + }; + core_bind(CORE_BLOCKDEV, dev, &ops, &hint); + + return 0; +} + +static int probe(struct instance *dev) +{ + /* there is nothing to activate */ + return 0; +} + +static int reloc(struct instance *dev, struct instance *old) +{ + core_replace(CORE_BLOCKDEV, dev, old); + /* there are no private data to relocate */ + + return 0; +} + +static int remove(struct instance *dev) +{ + /* nothing to do here */ + return 0; +} + +static int unbind(struct instance *dev) +{ + core_unbind(CORE_BLOCKDEV, dev); + + return 0; +} + + +U_BOOT_DRIVER(blockdev_partition, + bind, + probe, + reloc, + remove, + unbind);

cmd_block is the equivalent of cmd_sata for DM blockdev/blockctrl devices.
Signed-off-by: Pavel Herrmann morpheus.ibis@gmail.com --- common/Makefile | 2 + common/cmd_block.c | 139 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 141 insertions(+) create mode 100644 common/cmd_block.c
diff --git a/common/Makefile b/common/Makefile index 3d62775..aa09f17 100644 --- a/common/Makefile +++ b/common/Makefile @@ -66,6 +66,7 @@ COBJS-$(CONFIG_SOURCE) += cmd_source.o COBJS-$(CONFIG_CMD_SOURCE) += cmd_source.o COBJS-$(CONFIG_CMD_BDI) += cmd_bdinfo.o COBJS-$(CONFIG_CMD_BEDBUG) += bedbug.o cmd_bedbug.o +COBJS-${CONFIG_DM_BLOCK} += cmd_block.o COBJS-$(CONFIG_CMD_BMP) += cmd_bmp.o COBJS-$(CONFIG_CMD_BOOTLDR) += cmd_bootldr.o COBJS-$(CONFIG_CMD_CACHE) += cmd_cache.o @@ -163,6 +164,7 @@ COBJS-$(CONFIG_CMD_XIMG) += cmd_ximg.o COBJS-$(CONFIG_YAFFS2) += cmd_yaffs2.o COBJS-$(CONFIG_CMD_SPL) += cmd_spl.o COBJS-$(CONFIG_CMD_ZFS) += cmd_zfs.o +endif
# others ifdef CONFIG_DDR_SPD diff --git a/common/cmd_block.c b/common/cmd_block.c new file mode 100644 index 0000000..d7674c3 --- /dev/null +++ b/common/cmd_block.c @@ -0,0 +1,139 @@ +/* + * (C) Copyright 2012 + * Pavel Herrmann morpheus.ibis@gmail.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <command.h> +#include <dm/blockdev.h> +#include <dm/blockctrl.h> +#include <dm/manager.h> + +/* based on common/cmd_sata.c */ + +int do_block(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + struct instance *dev; + struct option op; + int devcount; + int portcount; + int blocksize; + int error; + + switch (argc) { + case 0: + case 1: + case 4: + return CMD_RET_USAGE; + case 2: + if (strncmp(argv[1], "init", 4) == 0) { + int i, j; + devcount = core_get_count(CORE_BLOCKCTRL); + for (i = 0; i < devcount; i++) { + dev = core_get_child(CORE_BLOCKCTRL, i); + portcount = blockctrl_get_port_count(dev); + for (j = 0; j < portcount; j++) + blockctrl_rescan_port(dev, j); + } + return 0; + } else if (strncmp(argv[1], "info", 4) == 0) { + putc('\n'); + print_blockdev_info_all(); + return 0; + } + return CMD_RET_USAGE; + case 3: + if (strncmp(argv[1], "info", 4) == 0) { + putc('\n'); + dev = get_blockdev_by_name(argv[2]); + print_blockdev_info(dev); + return 0; + } + return CMD_RET_USAGE; + default: /* at least 5 args */ + if (strncmp(argv[1], "read", 4) == 0) { + ulong addr = simple_strtoul(argv[3], NULL, 16); + ulong cnt = simple_strtoul(argv[5], NULL, 16); + ulong n; + lbaint_t blk = simple_strtoul(argv[4], NULL, 16); + + dev = get_blockdev_by_name(argv[2]); + if (!dev) { + printf("\nNo such device found: %s\n", argv[2]); + return 0; + } + + error = blockdev_get_option(dev, BLKD_OPT_BLOCKSIZE, + &op); + if (error || (OPTION_TYPE(op) != OPTION_TYPE_U)) { + printf("\nUnable to get blocksize from device " + "%s\n", argv[2]); + return 0; + } + blocksize = op.data.data_u; + + printf("\nblock read: device %s block # %ld, " + "count %ld ... ", argv[2], blk, cnt); + + n = blockdev_read(dev, blk, cnt, (u32 *)addr); + + /* flush cache after read */ + flush_cache(addr, cnt * blocksize); + + printf("%ld blocks read: %s\n", + n, (n == cnt) ? "OK" : "ERROR"); + return (n == cnt) ? 0 : 1; + } else if (strncmp(argv[1], "write", 5) == 0) { + ulong addr = simple_strtoul(argv[3], NULL, 16); + ulong cnt = simple_strtoul(argv[5], NULL, 16); + ulong n; + lbaint_t blk = simple_strtoul(argv[4], NULL, 16); + + dev = get_blockdev_by_name(argv[2]); + if (!dev) { + printf("\nNo such device found: %s\n", argv[2]); + return 0; + } + + printf("\nblock write: device %s block # %ld, " + "count %ld ... ", argv[2], blk, cnt); + + n = blockdev_write(dev, blk, cnt, (u32 *)addr); + + printf("%ld blocks written: %s\n", + n, (n == cnt) ? "OK" : "ERROR"); + return (n == cnt) ? 0 : 1; + } else { + return CMD_RET_USAGE; + } + + return 0; + } +} + +U_BOOT_CMD( + block, 5, 1, do_block, + "block sub system", + "init\n" + "block info - show available block devices\n" + "block read devname addr blk# cnt\n" + "block write devname addr blk# cnt" +);

cmd_fatdm.c is a copy of cmd_fat.c with just trivaial changes, but those touch large portion of the lines due to different number of parameters (old API has a separate parameter for interface and for disk number, new API has this as one)
Signed-off-by: Pavel Herrmann morpheus.ibis@gmail.com --- common/Makefile | 4 ++ common/cmd_fatdm.c | 192 +++++++++++++++++++++++++++++++++++++++++++++++++++++ fs/fat/Makefile | 7 +- fs/fat/dev_dm.c | 141 +++++++++++++++++++++++++++++++++++++++ include/fat.h | 8 +++ 5 files changed, 351 insertions(+), 1 deletion(-) create mode 100644 common/cmd_fatdm.c create mode 100644 fs/fat/dev_dm.c
diff --git a/common/Makefile b/common/Makefile index aa09f17..29e5798 100644 --- a/common/Makefile +++ b/common/Makefile @@ -88,7 +88,11 @@ COBJS-$(CONFIG_CMD_EEPROM) += cmd_eeprom.o COBJS-$(CONFIG_CMD_ELF) += cmd_elf.o COBJS-$(CONFIG_SYS_HUSH_PARSER) += cmd_exit.o COBJS-$(CONFIG_CMD_EXT2) += cmd_ext2.o +ifdef CONFIG_DM +COBJS-$(CONFIG_CMD_FAT) += cmd_fatdm.o +else COBJS-$(CONFIG_CMD_FAT) += cmd_fat.o +endif COBJS-$(CONFIG_CMD_FDC)$(CONFIG_CMD_FDOS) += cmd_fdc.o COBJS-$(CONFIG_OF_LIBFDT) += cmd_fdt.o fdt_support.o COBJS-$(CONFIG_CMD_FDOS) += cmd_fdos.o diff --git a/common/cmd_fatdm.c b/common/cmd_fatdm.c new file mode 100644 index 0000000..d91c53f --- /dev/null +++ b/common/cmd_fatdm.c @@ -0,0 +1,192 @@ +/* + * (C) Copyright 2002 + * Richard Jones, rjones@nexus-tech.net + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* + * Boot support + */ +#include <common.h> +#include <command.h> +#include <s_record.h> +#include <net.h> +#include <ata.h> +#include <part.h> +#include <fat.h> +#include <dm/structures.h> +#include <dm/blockdev.h> + +int do_fat_fsload(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + long size; + unsigned long offset; + unsigned long count; + char buf[12]; + struct instance *bdev; + + if (argc < 4) + return CMD_RET_USAGE; + + bdev = get_blockdev_by_name(argv[1]); + if (!bdev) { + puts("\n** Invalid boot device **\n"); + return -EINVAL; + } + if (fat_register_device(bdev)) { + printf("\n** Unable to use %s for fatload **\n", argv[1]); + return -EINVAL; + } + offset = simple_strtoul(argv[2], NULL, 16); + if (argc == 5) + count = simple_strtoul(argv[5], NULL, 16); + else + count = 0; + size = file_fat_read(argv[3], (unsigned char *)offset, count); + + if (size == -1) { + printf("\n** Unable to read "%s" from %s **\n", + argv[3], argv[1]); + return -EIO; + } + + printf("\n%ld bytes read\n", size); + + sprintf(buf, "%lX", size); + setenv("filesize", buf); + + return 0; +} + + +U_BOOT_CMD( + fatload, 6, 0, do_fat_fsload, + "load binary file from a dos filesystem", + "<dev[:part]> <addr> <filename> [bytes]\n" + " - load binary file 'filename' from 'dev'\n" + " to address 'addr' from dos filesystem" +); + +int do_fat_ls(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + char *filename = "/"; + int ret; + struct instance *bdev; + + if (argc < 2) + return CMD_RET_USAGE; + + bdev = get_blockdev_by_name(argv[1]); + if (!bdev) { + puts("\n** Invalid boot device **\n"); + return -EINVAL; + } + if (fat_register_device(bdev)) { + printf("\n** Unable to use %s for fatls **\n", argv[1]); + return -EINVAL; + } + if (argc == 3) + ret = file_fat_ls(argv[2]); + else + ret = file_fat_ls(filename); + + if (ret != 0) + printf("No Fat FS detected\n"); + return ret; +} + +U_BOOT_CMD( + fatls, 3, 1, do_fat_ls, + "list files in a directory (default /)", + "<dev[:part]> [directory]\n" + " - list files from 'dev' in a 'directory'" +); + +int do_fat_fsinfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + struct instance *bdev; + + if (argc < 2) + return CMD_RET_USAGE; + + bdev = get_blockdev_by_name(argv[1]); + if (!bdev) { + puts("\n** Invalid boot device **\n"); + return -EINVAL; + } + if (fat_register_device(bdev)) { + printf("\n** Unable to use %s for fatinfo **\n", argv[1]); + return -EIO; + } + return file_fat_detectfs(); +} + +U_BOOT_CMD( + fatinfo, 2, 1, do_fat_fsinfo, + "print information about filesystem", + "<dev[:part]>\n" + " - print information about filesystem from 'dev' on 'interface'" +); + +#ifdef CONFIG_FAT_WRITE +static int do_fat_fswrite(cmd_tbl_t *cmdtp, int flag, + int argc, char * const argv[]) +{ + long size; + unsigned long addr; + unsigned long count; + struct instance *bdev; + + if (argc < 4) + return CMD_RET_USAGE; + + bdev = get_blockdev_by_name(argv[1]); + if (!bdev) { + puts("\n** Invalid boot device **\n"); + return 1; + } + if (fat_register_device(bdev)) { + printf("\n** Unable to use %s for fatwrite **\n", + argv[1]); + return 1; + } + addr = simple_strtoul(argv[2], NULL, 16); + count = simple_strtoul(argv[4], NULL, 16); + + size = file_fat_write(argv[3], (void *)addr, count); + if (size == -1) { + printf("\n** Unable to write "%s" to %s **\n", + argv[3], argv[1]); + return 1; + } + + printf("%ld bytes written\n", size); + + return 0; +} + +U_BOOT_CMD( + fatwrite, 6, 0, do_fat_fswrite, + "write file into a dos filesystem", + "<dev[:part]> <addr> <filename> <bytes>\n" + " - write file 'filename' from the address 'addr' in RAM\n" + " to 'dev' on 'interface'" +); +#endif diff --git a/fs/fat/Makefile b/fs/fat/Makefile index 176e6f4..f85480c 100644 --- a/fs/fat/Makefile +++ b/fs/fat/Makefile @@ -24,8 +24,13 @@ include $(TOPDIR)/config.mk LIB = $(obj)libfat.o
AOBJS = -COBJS-$(CONFIG_CMD_FAT) := fat.o dev.o +COBJS-$(CONFIG_CMD_FAT) := fat.o COBJS-$(CONFIG_FAT_WRITE) := fat_write.o +ifdef CONFIG_DM +COBJS-$(CONFIG_CMD_FAT) += dev_dm.o +else +COBJS-$(CONFIG_CMD_FAT) += dev.o +endif
ifndef CONFIG_SPL_BUILD COBJS-$(CONFIG_CMD_FAT) += file.o diff --git a/fs/fat/dev_dm.c b/fs/fat/dev_dm.c new file mode 100644 index 0000000..3f66e54 --- /dev/null +++ b/fs/fat/dev_dm.c @@ -0,0 +1,141 @@ +/* + * (C) Copyright 2012 + * Pavel Herrmann morpheus.ibis@gmail.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <dm/structures.h> +#include <dm/blockdev.h> +#include <fat.h> +#include <errno.h> + +static struct instance *bdev; + +#define DOS_BOOT_MAGIC_OFFSET 0x1fe +#define DOS_FS_TYPE_OFFSET 0x36 +#define DOS_FS32_TYPE_OFFSET 0x52 + +int fat_disk_read(__u32 block, __u32 nr_blocks, void *buf) +{ + if (!bdev) + return -1; + + return blockdev_read(bdev, block, nr_blocks, buf); +} + +int fat_disk_write(__u32 block, __u32 nr_blocks, void *buf) +{ + if (!bdev) + return -1; + + return blockdev_write(bdev, block, nr_blocks, buf); +} + +int fat_get_blksz(void) +{ + struct option op; + int error; + + error = blockdev_get_option(bdev, BLKD_OPT_BLOCKSIZE, &op); + if ((error) || (OPTION_TYPE(op) != OPTION_TYPE_U)) + return -EINVAL; + + return op.data.data_u; +} + +int fat_get_partsize(void) +{ + struct option op; + int error; + + error = blockdev_get_option(bdev, BLKD_OPT_BLOCKCOUNT, &op); + if ((error) || (OPTION_TYPE(op) != OPTION_TYPE_U)) + return -EINVAL; + + return op.data.data_u; +} + +int fat_register_device(struct instance *dev) +{ + int blksz; + + if (!dev) + return -EINVAL; + + bdev = dev; + blksz = fat_get_blksz(); + if (blksz < 0) { + /*this should not happen, lets just warn and guess */ + printf("Error reading device block size!!!\nGuessing 512\n"); + blksz = 512; + } + ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buffer, blksz); + + /* Make sure it has a valid FAT header */ + if (fat_disk_read(0, 1, buffer) != 1) { + bdev = NULL; + return -EIO; + } + + /* Check if it's actually a DOS volume */ + if (memcmp(buffer + DOS_BOOT_MAGIC_OFFSET, "\x55\xAA", 2)) { + bdev = NULL; + return -ENOENT; + } + + /* Check for FAT12/FAT16/FAT32 filesystem */ + if (!memcmp(buffer + DOS_FS_TYPE_OFFSET, "FAT", 3)) + return 0; + if (!memcmp(buffer + DOS_FS32_TYPE_OFFSET, "FAT32", 5)) + return 0; + + bdev = NULL; + return -EINVAL; + +} + +int file_fat_detectfs(void) +{ + boot_sector bs; + volume_info volinfo; + int fatsize; + char vol_label[12]; + + if (!bdev) { + printf("No current device\n"); + return -EINVAL; + } + + print_blockdev_info(bdev); + + if (fat_read_bootsectandvi(&bs, &volinfo, &fatsize)) { + printf("\nNo valid FAT fs found\n"); + return -EINVAL; + } + + memcpy(vol_label, volinfo.volume_label, 11); + vol_label[11] = '\0'; + volinfo.fs_type[5] = '\0'; + + printf("Filesystem: %s "%s"\n", volinfo.fs_type, vol_label); + + return 0; +} + diff --git a/include/fat.h b/include/fat.h index 98f77a5..85f2f0b 100644 --- a/include/fat.h +++ b/include/fat.h @@ -29,6 +29,10 @@
#include <asm/byteorder.h>
+#ifdef CONFIG_DM +#include <dm/structures.h> +#endif + #define CONFIG_SUPPORT_VFAT /* Maximum Long File Name length supported here is 128 UTF-16 code units */ #define VFAT_MAXLEN_BYTES 256 /* Maximum LFN buffer in bytes */ @@ -210,7 +214,11 @@ int file_fat_detectfs(void); int file_fat_ls(const char *dir); long file_fat_read(const char *filename, void *buffer, unsigned long maxsize); const char *file_getfsname(int idx); +#ifdef CONFIG_DM +int fat_register_device(struct instance *dev); +#else int fat_register_device(block_dev_desc_t *dev_desc, int part_no); +#endif
int file_fat_write(const char *filename, void *buffer, unsigned long maxsize);

cmd_ext2dm.c is a copy of cmd_ext2.c with just trivial changes, but those touch large portion of the lines due to different number of parameters (old API has a separate parameter for interface and for disk number, new API has this as one)
Signed-off-by: Pavel Herrmann morpheus.ibis@gmail.com --- common/Makefile | 3 +- common/cmd_ext2dm.c | 211 ++++++++++++++++++++++++++++++++++++++++++++++++++++ fs/ext2/Makefile | 7 +- fs/ext2/dev_dm.c | 107 ++++++++++++++++++++++++++ include/ext2fs.h | 9 ++- 5 files changed, 334 insertions(+), 3 deletions(-) create mode 100644 common/cmd_ext2dm.c create mode 100644 fs/ext2/dev_dm.c
diff --git a/common/Makefile b/common/Makefile index 29e5798..22f9234 100644 --- a/common/Makefile +++ b/common/Makefile @@ -87,10 +87,11 @@ COBJS-$(CONFIG_ENV_IS_IN_EEPROM) += cmd_eeprom.o COBJS-$(CONFIG_CMD_EEPROM) += cmd_eeprom.o COBJS-$(CONFIG_CMD_ELF) += cmd_elf.o COBJS-$(CONFIG_SYS_HUSH_PARSER) += cmd_exit.o -COBJS-$(CONFIG_CMD_EXT2) += cmd_ext2.o ifdef CONFIG_DM +COBJS-$(CONFIG_CMD_EXT2) += cmd_ext2dm.o COBJS-$(CONFIG_CMD_FAT) += cmd_fatdm.o else +COBJS-$(CONFIG_CMD_EXT2) += cmd_ext2.o COBJS-$(CONFIG_CMD_FAT) += cmd_fat.o endif COBJS-$(CONFIG_CMD_FDC)$(CONFIG_CMD_FDOS) += cmd_fdc.o diff --git a/common/cmd_ext2dm.c b/common/cmd_ext2dm.c new file mode 100644 index 0000000..da703eb --- /dev/null +++ b/common/cmd_ext2dm.c @@ -0,0 +1,211 @@ +/* + * (C) Copyright 2004 + * esd gmbh <www.esd-electronics.com> + * Reinhard Arlt reinhard.arlt@esd-electronics.com + * + * made from cmd_reiserfs by + * + * (C) Copyright 2003 - 2004 + * Sysgo Real-Time Solutions, AG <www.elinos.com> + * Pavel Bartusek pba@sysgo.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +/* + * Ext2fs support + */ +#include <common.h> +#include <config.h> +#include <command.h> +#include <image.h> +#include <linux/ctype.h> +#include <asm/byteorder.h> +#include <ext2fs.h> +#include <dm/structures.h> +#include <dm/blockdev.h> + +/* #define EXT2_DEBUG */ + +#ifdef EXT2_DEBUG +#define PRINTF(fmt, args...) printf(fmt, ##args) +#else +#define PRINTF(fmt, args...) +#endif + +int do_ext2ls(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + char *filename = "/"; + struct instance *bdev; + int part_length; + + if (argc < 2) + return CMD_RET_USAGE; + + bdev = get_blockdev_by_name(argv[1]); + + if (bdev == NULL) { + printf("\n** Block device %s not found\n", argv[1]); + return 1; + } + + if (argc == 3) + filename = argv[2]; + + PRINTF("Using device %s, directory: %s\n", argv[1], filename); + + part_length = ext2fs_set_blk_dev(bdev); + if (part_length == 0) { + printf("** Bad partition - %s **\n", argv[1]); + ext2fs_close(); + return 1; + } + + if (!ext2fs_mount(part_length)) { + printf("** Bad ext2 partition or disk - %s**\n", argv[1]); + ext2fs_close(); + return 1; + } + + if (ext2fs_ls(filename)) { + printf("** Error ext2fs_ls() **\n"); + ext2fs_close(); + return 1; + }; + + ext2fs_close(); + + return 0; +} + +U_BOOT_CMD( + ext2ls, 3, 1, do_ext2ls, + "list files in a directory (default /)", + "<dev[:part]> [directory]\n" + " - list files from 'dev' in a 'directory'" +); + +/****************************************************************************** + * Ext2fs boot command intepreter. Derived from diskboot + */ +int do_ext2load(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + char *filename = NULL; + struct instance *bdev; + ulong addr = 0, part_length; + int filelen; + char buf[12]; + unsigned long count; + char *addr_str; + + switch (argc) { + case 2: + addr_str = getenv("loadaddr"); + if (addr_str != NULL) + addr = simple_strtoul(addr_str, NULL, 16); + else + addr = CONFIG_SYS_LOAD_ADDR; + + filename = getenv("bootfile"); + count = 0; + break; + case 3: + addr = simple_strtoul(argv[2], NULL, 16); + filename = getenv("bootfile"); + count = 0; + break; + case 4: + addr = simple_strtoul(argv[2], NULL, 16); + filename = argv[3]; + count = 0; + break; + case 5: + addr = simple_strtoul(argv[2], NULL, 16); + filename = argv[3]; + count = simple_strtoul(argv[4], NULL, 16); + break; + + default: + return CMD_RET_USAGE; + } + + if (!filename) { + puts("** No boot file defined **\n"); + return 1; + } + + bdev = get_blockdev_by_name(argv[1]); + if (!bdev) { + printf("** Block device %s not found\n", argv[1]); + return 1; + } + + PRINTF("Using device %s\n", argv[1]); + + printf("Loading file "%s" from device %s\n", filename, argv[1]); + + part_length = ext2fs_set_blk_dev(bdev); + if (part_length == 0) { + printf("** Bad partition - %s **\n", argv[1]); + ext2fs_close(); + return 1; + } + + if (!ext2fs_mount(part_length)) { + printf("** Bad ext2 partition or disk - %s **\n", argv[1]); + ext2fs_close(); + return 1; + } + + filelen = ext2fs_open(filename); + if (filelen < 0) { + printf("** File not found %s\n", filename); + ext2fs_close(); + return 1; + } + if ((count < filelen) && (count != 0)) + filelen = count; + + if (ext2fs_read((char *)addr, filelen) != filelen) { + printf("** Unable to read "%s" from %s **\n", filename, + argv[1]); + ext2fs_close(); + return 1; + } + + ext2fs_close(); + + /* Loading ok, update default load address */ + load_addr = addr; + + printf("%d bytes read\n", filelen); + sprintf(buf, "%X", filelen); + setenv("filesize", buf); + + return 0; +} + +U_BOOT_CMD( + ext2load, 5, 0, do_ext2load, + "load binary file from a Ext2 filesystem", + "<dev[:part]> [addr] [filename] [bytes]\n" + " - load binary file 'filename' from 'dev'\n" + " to address 'addr' from ext2 filesystem" +); diff --git a/fs/ext2/Makefile b/fs/ext2/Makefile index 3c65d25..ac4ddf2 100644 --- a/fs/ext2/Makefile +++ b/fs/ext2/Makefile @@ -30,7 +30,12 @@ include $(TOPDIR)/config.mk LIB = $(obj)libext2fs.o
AOBJS = -COBJS-$(CONFIG_CMD_EXT2) := ext2fs.o dev.o +COBJS-$(CONFIG_CMD_EXT2) := ext2fs.o +ifdef CONFIG_DM +COBJS-${CONFIG_CMD_EXT2} += dev_dm.o +else +COBJS-${CONFIG_CMD_EXT2} += dev.o +endif
SRCS := $(AOBJS:.o=.S) $(COBJS-y:.o=.c) OBJS := $(addprefix $(obj),$(AOBJS) $(COBJS-y)) diff --git a/fs/ext2/dev_dm.c b/fs/ext2/dev_dm.c new file mode 100644 index 0000000..6539b44 --- /dev/null +++ b/fs/ext2/dev_dm.c @@ -0,0 +1,107 @@ +/* + * (C) Copyright 2004 + * esd gmbh <www.esd-electronics.com> + * Reinhard Arlt reinhard.arlt@esd-electronics.com + * + * based on code of fs/reiserfs/dev.c by + * + * (C) Copyright 2003 - 2004 + * Sysgo AG, <www.elinos.com>, Pavel Bartusek pba@sysgo.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +#include <common.h> +#include <config.h> +#include <ext2fs.h> +#include <dm/structures.h> +#include <dm/blockdev.h> + +static struct instance *bdev; + +int ext2fs_set_blk_dev(struct instance *dev) +{ + struct option opt; + int error; + + if (!dev) + return 0; + + error = blockdev_get_option(dev, BLKD_OPT_BLOCKCOUNT, &opt); + if (error || (OPTION_TYPE(opt) != OPTION_TYPE_U)) + return 0; + + bdev = dev; + + return opt.data.data_u; +} + +int ext2fs_devread(int sector, int byte_offset, int byte_len, char *buf) +{ + ALLOC_CACHE_ALIGN_BUFFER(char, sec_buf, SECTOR_SIZE); + unsigned sectors; + + /* + * Get the read to the beginning of a partition. + */ + sector += byte_offset >> SECTOR_BITS; + byte_offset &= SECTOR_SIZE - 1; + + debug(" <%d, %d, %d>\n", sector, byte_offset, byte_len); + + if (bdev == NULL) { + printf(" ** %s Invalid Block Device Descriptor (NULL)\n", + __func__); + return 0; + } + + if (byte_offset != 0) { + /* read first part which isn't aligned with start of sector */ + if (blockdev_read(bdev, sector, 1, sec_buf) != 1) { + printf(" ** %s read error **\n", __func__); + return 0; + } + memcpy(buf, sec_buf + byte_offset, + min(SECTOR_SIZE - byte_offset, byte_len)); + buf += min(SECTOR_SIZE - byte_offset, byte_len); + byte_len -= min(SECTOR_SIZE - byte_offset, byte_len); + sector++; + } + + /* read sector aligned part */ + sectors = byte_len / SECTOR_SIZE; + + if (sectors > 0) { + if (blockdev_read(bdev, sector, sectors, buf) != sectors) { + printf(" ** %s read error - block\n", __func__); + return 0; + } + + buf += sectors * SECTOR_SIZE; + byte_len -= sectors * SECTOR_SIZE; + sector += sectors; + } + + if (byte_len != 0) { + /* read rest of data which are not in whole sector */ + if (blockdev_read(bdev, sector, 1, sec_buf) != 1) { + printf(" ** %s read error - last part\n", __func__); + return 0; + } + memcpy(buf, sec_buf, byte_len); + } + return 1; +} diff --git a/include/ext2fs.h b/include/ext2fs.h index 163a9bb..d16714e 100644 --- a/include/ext2fs.h +++ b/include/ext2fs.h @@ -25,6 +25,10 @@ * from the original ext2 fs code, as found in the linux kernel. */
+#ifdef CONFIG_DM +#include <dm/structures.h> +#endif +
#define SECTOR_SIZE 0x200 #define SECTOR_BITS 9 @@ -72,8 +76,11 @@ typedef enum MAX_ERR_NUM } ext2fs_error_t;
- +#ifdef CONFIG_DM +extern int ext2fs_set_blk_dev(struct instance *dev); +#else extern int ext2fs_set_blk_dev(block_dev_desc_t *rbdd, int part); +#endif extern int ext2fs_ls (const char *dirname); extern int ext2fs_open (const char *filename); extern int ext2fs_read (char *buf, unsigned len);

cmd_reiserdm.c is a copy of cmd_reiser.c with just trivial changes, but those touch large portion of the lines due to different number of parameters (old API has a separate parameter for interface and for disk number, new API has this as one)
Signed-off-by: Pavel Herrmann morpheus.ibis@gmail.com --- common/Makefile | 4 ++ common/cmd_reiserdm.c | 193 ++++++++++++++++++++++++++++++++++++++++++++++++++ fs/reiserfs/Makefile | 8 ++- fs/reiserfs/dev_dm.c | 104 +++++++++++++++++++++++++++ include/reiserfs.h | 8 ++- 5 files changed, 315 insertions(+), 2 deletions(-) create mode 100644 common/cmd_reiserdm.c create mode 100644 fs/reiserfs/dev_dm.c
diff --git a/common/Makefile b/common/Makefile index 22f9234..d83c66e 100644 --- a/common/Makefile +++ b/common/Makefile @@ -142,7 +142,11 @@ COBJS-y += cmd_pcmcia.o COBJS-$(CONFIG_CMD_PORTIO) += cmd_portio.o COBJS-$(CONFIG_CMD_PXE) += cmd_pxe.o COBJS-$(CONFIG_CMD_REGINFO) += cmd_reginfo.o +ifdef CONFIG_DM +COBJS-$(CONFIG_CMD_REISER) += cmd_reiserdm.o +else COBJS-$(CONFIG_CMD_REISER) += cmd_reiser.o +endif COBJS-$(CONFIG_CMD_SATA) += cmd_sata.o COBJS-$(CONFIG_CMD_SF) += cmd_sf.o COBJS-$(CONFIG_CMD_SCSI) += cmd_scsi.o diff --git a/common/cmd_reiserdm.c b/common/cmd_reiserdm.c new file mode 100644 index 0000000..ed16563 --- /dev/null +++ b/common/cmd_reiserdm.c @@ -0,0 +1,193 @@ +/* + * (C) Copyright 2003 - 2004 + * Sysgo Real-Time Solutions, AG <www.elinos.com> + * Pavel Bartusek pba@sysgo.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +/* + * Reiserfs support + */ +#include <common.h> +#include <config.h> +#include <command.h> +#include <image.h> +#include <linux/ctype.h> +#include <asm/byteorder.h> +#include <reiserfs.h> +#include <dm/structures.h> +#include <dm/blockdev.h> + +/* #define REISER_DEBUG */ + +#ifdef REISER_DEBUG +#define PRINTF(fmt, args...) printf(fmt, ##args) +#else +#define PRINTF(fmt, args...) +#endif + +int do_reiserls(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + char *filename = "/"; + int part_length; + struct instance *bdev; + + if (argc < 2) + return CMD_RET_USAGE; + + bdev = get_blockdev_by_name(argv[1]); + if (!bdev) { + printf("\n** Block device %s not supported\n", argv[1]); + return 1; + } + + if (argc == 3) + filename = argv[2]; + + PRINTF("Using device %s, directory: %s\n", argv[1], filename); + + part_length = reiserfs_set_blk_dev(bdev); + if (part_length == 0) { + printf("** Bad partition - %s **\n", argv[1]); + return 1; + } + + if (!reiserfs_mount(part_length)) { + printf("** Bad Reiserfs partition or disk - %s **\n", argv[1]); + return 1; + } + + if (reiserfs_ls(filename)) { + printf("** Error reiserfs_ls() **\n"); + return 1; + }; + + return 0; +} + +U_BOOT_CMD( + reiserls, 3, 1, do_reiserls, + "list files in a directory (default /)", + "<dev[:part]> [directory]\n" + " - list files from 'dev' on 'interface' in a 'directory'" +); + +/****************************************************************************** + * Reiserfs boot command intepreter. Derived from diskboot + */ +int do_reiserload(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + char *filename = NULL; + ulong addr = 0, part_length, filelen; + char buf[12]; + unsigned long count; + char *addr_str; + struct instance *bdev; + + switch (argc) { + case 2: + addr_str = getenv("loadaddr"); + if (addr_str != NULL) + addr = simple_strtoul(addr_str, NULL, 16); + else + addr = CONFIG_SYS_LOAD_ADDR; + filename = getenv("bootfile"); + count = 0; + break; + case 3: + addr = simple_strtoul(argv[2], NULL, 16); + filename = getenv("bootfile"); + count = 0; + break; + case 4: + addr = simple_strtoul(argv[2], NULL, 16); + filename = argv[3]; + count = 0; + break; + case 5: + addr = simple_strtoul(argv[2], NULL, 16); + filename = argv[3]; + count = simple_strtoul(argv[4], NULL, 16); + break; + + default: + return CMD_RET_USAGE; + } + + if (!filename) { + puts("\n** No boot file defined **\n"); + return 1; + } + + bdev = get_blockdev_by_name(argv[1]); + if (!bdev) { + printf("\n** Block device %s not supported\n", argv[1]); + return 1; + } + + PRINTF("Using device %s\n", argv[1]); + + PRINTF("\nLoading from block device %s, File:%s\n", + argv[1], filename); + + + part_length = reiserfs_set_blk_dev(bdev); + if (part_length == 0) { + printf("** Bad partition - %s **\n", argv[1]); + return 1; + } + + if (!reiserfs_mount(part_length)) { + printf("** Bad Reiserfs partition or disk - %s **\n", argv[1]); + return 1; + } + + filelen = reiserfs_open(filename); + if (filelen < 0) { + printf("** File not found %s\n", filename); + return 1; + } + if ((count < filelen) && (count != 0)) + filelen = count; + + if (reiserfs_read((char *)addr, filelen) != filelen) { + printf("\n** Unable to read "%s" from %s **\n", filename, + argv[1]); + return 1; + } + + /* Loading ok, update default load address */ + load_addr = addr; + + printf("\n%ld bytes read\n", filelen); + sprintf(buf, "%lX", filelen); + setenv("filesize", buf); + + return filelen; +} + +U_BOOT_CMD( + reiserload, 5, 0, do_reiserload, + "load binary file from a Reiser filesystem", + "<dev[:part]> [addr] [filename] [bytes]\n" + " - load binary file 'filename' from 'dev' on 'interface'\n" + " to address 'addr' from dos filesystem" +); diff --git a/fs/reiserfs/Makefile b/fs/reiserfs/Makefile index 495759c..bb30101 100644 --- a/fs/reiserfs/Makefile +++ b/fs/reiserfs/Makefile @@ -30,7 +30,13 @@ include $(TOPDIR)/config.mk LIB = $(obj)libreiserfs.o
AOBJS = -COBJS-$(CONFIG_CMD_REISER) := reiserfs.o dev.o mode_string.o +COBJS-$(CONFIG_CMD_REISER) := reiserfs.o mode_string.o + +ifdef CONFIG_DM +COBJS-${CONFIG_CMD_REISER} += dev_dm.o +else +COBJS-${CONFIG_CMD_REISER} += dev.o +endif
SRCS := $(AOBJS:.o=.S) $(COBJS-y:.o=.c) OBJS := $(addprefix $(obj),$(AOBJS) $(COBJS-y)) diff --git a/fs/reiserfs/dev_dm.c b/fs/reiserfs/dev_dm.c new file mode 100644 index 0000000..4dad499 --- /dev/null +++ b/fs/reiserfs/dev_dm.c @@ -0,0 +1,104 @@ +/* + * (C) Copyright 2003 - 2004 + * Sysgo AG, <www.elinos.com>, Pavel Bartusek pba@sysgo.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +#include <common.h> +#include <config.h> +#include <reiserfs.h> + +#include "reiserfs_private.h" + +#include <dm/structures.h> +#include <dm/blockdev.h> + +static struct instance *bdev; + +int reiserfs_set_blk_dev(struct instance *dev) +{ + struct option op; + int error; + + if (!dev) + return 0; + + error = blockdev_get_option(dev, BLKD_OPT_BLOCKCOUNT, &op); + if (error || (OPTION_TYPE(op) != OPTION_TYPE_U)) + return 0; + bdev = dev; + + return op.data.data_u; +} + + +int reiserfs_devread(int sector, int byte_offset, int byte_len, char *buf) +{ + char sec_buf[SECTOR_SIZE]; + unsigned block_len; + + /* + * Get the read to the beginning of a partition. + */ + sector += byte_offset >> SECTOR_BITS; + byte_offset &= SECTOR_SIZE - 1; + +#if defined(DEBUG) + printf(" <%d, %d, %d> ", sector, byte_offset, byte_len); +#endif + + + if (!bdev) + return 0; + + + if (byte_offset != 0) { + /* read first part which isn't aligned with start of sector */ + if (blockdev_read(bdev, sector, 1, sec_buf) != 1) { + printf(" ** reiserfs_devread() read error\n"); + return 0; + } + memcpy(buf, sec_buf+byte_offset, + min(SECTOR_SIZE-byte_offset, byte_len)); + buf += min(SECTOR_SIZE-byte_offset, byte_len); + byte_len -= min(SECTOR_SIZE-byte_offset, byte_len); + sector++; + } + + /* read sector aligned part */ + block_len = byte_len & ~(SECTOR_SIZE-1); + if (blockdev_read(bdev, sector, block_len / SECTOR_SIZE, buf) != + block_len / SECTOR_SIZE) { + printf(" ** reiserfs_devread() read error - block\n"); + return 0; + } + buf += block_len; + byte_len -= block_len; + sector += block_len/SECTOR_SIZE; + + if (byte_len != 0) { + /* read rest of data which are not in whole sector */ + if (blockdev_read(bdev, sector, 1, sec_buf) != 1) { + printf(" ** reiserfs_devread() read error - " + "last part\n"); + return 0; + } + memcpy(buf, sec_buf, byte_len); + } + + return 1; +} diff --git a/include/reiserfs.h b/include/reiserfs.h index c465b3c..e0ce2c1 100644 --- a/include/reiserfs.h +++ b/include/reiserfs.h @@ -27,6 +27,9 @@ * from the original reiser fs code, as found in the linux kernel. */
+#ifdef CONFIG_DM +#include <dm/structures.h> +#endif
#define SECTOR_SIZE 0x200 #define SECTOR_BITS 9 @@ -74,8 +77,11 @@ typedef enum MAX_ERR_NUM } reiserfs_error_t;
- +#ifdef CONFIG_DM +extern int reiserfs_set_blk_dev(struct instance *bdev); +#else extern int reiserfs_set_blk_dev(block_dev_desc_t *rbdd, int part); +#endif extern int reiserfs_ls (char *dirname); extern int reiserfs_open (char *filename); extern int reiserfs_read (char *buf, unsigned len);

cmd_zfsdm.c is a copy of cmd_zfs.c with just trivial changes, but those touch large portion of the lines due to different number of parameters (old API has a separate parameter for interface and for disk number, new API has this as one)
Signed-off-by: Pavel Herrmann morpheus.ibis@gmail.com --- common/Makefile | 3 + common/cmd_zfsdm.c | 199 +++++++++++++++++++++++++++++++++++++++++++++++++++ fs/zfs/Makefile | 7 +- fs/zfs/dev_dm.c | 117 ++++++++++++++++++++++++++++++ include/zfs_common.h | 8 +++ 5 files changed, 333 insertions(+), 1 deletion(-) create mode 100644 common/cmd_zfsdm.c create mode 100644 fs/zfs/dev_dm.c
diff --git a/common/Makefile b/common/Makefile index d83c66e..11bf888 100644 --- a/common/Makefile +++ b/common/Makefile @@ -172,6 +172,9 @@ endif COBJS-$(CONFIG_CMD_XIMG) += cmd_ximg.o COBJS-$(CONFIG_YAFFS2) += cmd_yaffs2.o COBJS-$(CONFIG_CMD_SPL) += cmd_spl.o +ifdef CONFIG_DM +COBJS-$(CONFIG_CMD_ZFS) += cmd_zfsdm.o +else COBJS-$(CONFIG_CMD_ZFS) += cmd_zfs.o endif
diff --git a/common/cmd_zfsdm.c b/common/cmd_zfsdm.c new file mode 100644 index 0000000..e41f956 --- /dev/null +++ b/common/cmd_zfsdm.c @@ -0,0 +1,199 @@ +/* + * + * ZFS filesystem porting to Uboot by + * Jorgen Lundman <lundman at lundman.net> + * + * zfsfs support + * made from existing GRUB Sources by Sun, GNU and others. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +#include <common.h> +#include <part.h> +#include <config.h> +#include <command.h> +#include <image.h> +#include <linux/ctype.h> +#include <asm/byteorder.h> +#include <zfs_common.h> +#include <linux/stat.h> +#include <malloc.h> +#include <dm/structures.h> +#include <dm/blockdev.h> + +#if defined(CONFIG_CMD_USB) && defined(CONFIG_USB_STORAGE) +#include <usb.h> +#endif + +#if !defined(CONFIG_DOS_PARTITION) && !defined(CONFIG_EFI_PARTITION) +#error DOS or EFI partition support must be selected +#endif + +#define DOS_PART_MAGIC_OFFSET 0x1fe +#define DOS_FS_TYPE_OFFSET 0x36 +#define DOS_FS32_TYPE_OFFSET 0x52 + +static int do_zfs_load(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) +{ + char *filename = NULL; + ulong addr = 0; + ulong part_length; + char buf[12]; + unsigned long count; + const char *addr_str; + struct zfs_file zfile; + struct device_s vdev; + struct instance *bdev; + + if (argc < 2) + return CMD_RET_USAGE; + + count = 0; + switch (argc) { + case 2: + addr_str = getenv("loadaddr"); + if (addr_str != NULL) + addr = simple_strtoul(addr_str, NULL, 16); + else + addr = CONFIG_SYS_LOAD_ADDR; + + break; + case 3: + addr = simple_strtoul(argv[2], NULL, 16); + filename = getenv("bootfile"); + break; + case 4: + addr = simple_strtoul(argv[2], NULL, 16); + filename = argv[3]; + break; + case 5: + addr = simple_strtoul(argv[2], NULL, 16); + filename = argv[3]; + count = simple_strtoul(argv[4], NULL, 16); + break; + + default: + return cmd_usage(cmdtp); + } + + if (!filename) { + puts("** No boot file defined **\n"); + return 1; + } + + bdev = get_blockdev_by_name(argv[1]); + if (!bdev) { + printf("** Block device %s not supported\n", argv[1]); + return 1; + } + + printf("Loading file "%s" from device %s\n", + filename, argv[1]); + + part_length = zfs_set_blk_dev(bdev); + if (part_length == 0) { + printf("**Bad partition - %s **\n", argv[1]); + return 1; + } + + vdev.part_length = part_length; + + memset(&zfile, 0, sizeof(zfile)); + zfile.device = &vdev; + if (zfs_open(&zfile, filename)) { + printf("** File not found %s\n", filename); + return 1; + } + + if ((count < zfile.size) && (count != 0)) + zfile.size = (uint64_t)count; + + if (zfs_read(&zfile, (char *)addr, zfile.size) != zfile.size) { + printf("** Unable to read "%s" from %s **\n", + filename, argv[1]); + zfs_close(&zfile); + return 1; + } + + zfs_close(&zfile); + + /* Loading ok, update default load address */ + load_addr = addr; + + printf("%llu bytes read\n", zfile.size); + sprintf(buf, "%llX", zfile.size); + setenv("filesize", buf); + + return 0; +} + + +int zfs_print(const char *entry, const struct zfs_dirhook_info *data) +{ + printf("%s %s\n", + data->dir ? "<DIR> " : " ", + entry); + return 0; /* 0 continue, 1 stop */ +} + + + +static int do_zfs_ls(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + const char *filename = "/"; + int part_length; + struct device_s vdev; + struct instance *bdev; + + if (argc < 2) + return CMD_RET_USAGE; + + bdev = get_blockdev_by_name(argv[1]); + if (bdev) { + printf("\n** Block device %s not supported\n", argv[1]); + return 1; + } + if (argc == 3) + filename = argv[2]; + + part_length = zfs_set_blk_dev(bdev); + if (part_length == 0) { + printf("** Bad partition - %s **\n", argv[1]); + return 1; + } + + vdev.part_length = part_length; + + zfs_ls(&vdev, filename, + zfs_print); + + return 0; +} + + +U_BOOT_CMD(zfsls, 3, 1, do_zfs_ls, + "list files in a directory (default /)", + "<dev[:part]> [directory]\n" + " - list files from 'dev' in a '/DATASET/@/$dir/'"); + +U_BOOT_CMD(zfsload, 5, 0, do_zfs_load, + "load binary file from a ZFS filesystem", + "<dev[:part]> [addr] [filename] [bytes]\n" + " - load binary file '/DATASET/@/$dir/$file' from 'dev'\n" + " to address 'addr' from ZFS filesystem"); diff --git a/fs/zfs/Makefile b/fs/zfs/Makefile index 938fc5e..4765a56 100644 --- a/fs/zfs/Makefile +++ b/fs/zfs/Makefile @@ -26,7 +26,12 @@ include $(TOPDIR)/config.mk LIB = $(obj)libzfs.o
AOBJS = -COBJS-$(CONFIG_CMD_ZFS) := dev.o zfs.o zfs_fletcher.o zfs_sha256.o zfs_lzjb.o +COBJS-$(CONFIG_CMD_ZFS) := zfs.o zfs_fletcher.o zfs_sha256.o zfs_lzjb.o +ifdef CONFIG_DM +COBJS-$(CONFIG_CMD_ZFS) := deo_dm.o +else +COBJS-$(CONFIG_CMD_ZFS) := dev.o +endif
SRCS := $(AOBJS:.o=.S) $(COBJS-y:.o=.c) OBJS := $(addprefix $(obj),$(AOBJS) $(COBJS-y)) diff --git a/fs/zfs/dev_dm.c b/fs/zfs/dev_dm.c new file mode 100644 index 0000000..8af0546 --- /dev/null +++ b/fs/zfs/dev_dm.c @@ -0,0 +1,117 @@ +/* + * + * based on code of fs/reiserfs/dev.c by + * + * (C) Copyright 2003 - 2004 + * Sysgo AG, <www.elinos.com>, Pavel Bartusek pba@sysgo.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +#include <common.h> +#include <config.h> +#include <zfs_common.h> +#include <dm/structures.h> +#include <dm/blockdev.h> + +static struct instance *bdev; + +int zfs_set_blk_dev(struct instance *dev) +{ + int error; + struct option op; + + if (!dev) + return 0; + + error = blockdev_get_option(dev, BLKD_OPT_BLOCKCOUNT, &op); + if (error || (OPTION_TYPE(op) != OPTION_TYPE_U)) + return 0; + + bdev = dev; + + return op.data.data_u; +} + +/* err */ +int zfs_devread(int sector, int byte_offset, int byte_len, char *buf) +{ + short sec_buffer[SECTOR_SIZE/sizeof(short)]; + char *sec_buf = (char *)sec_buffer; + unsigned block_len; + + /* + * Get the read to the beginning of a partition. + */ + sector += byte_offset >> SECTOR_BITS; + byte_offset &= SECTOR_SIZE - 1; + + debug(" <%d, %d, %d>\n", sector, byte_offset, byte_len); + + if (!bdev) { + printf("** Invalid Block Device Descriptor (NULL)\n"); + return 1; + } + + if (byte_offset != 0) { + /* read first part which isn't aligned with start of sector */ + if (blockdev_read(bdev, sector, 1, sec_buf) != 1) { + printf(" ** zfs_devread() read error **\n"); + return 1; + } + memcpy(buf, sec_buf + byte_offset, + min(SECTOR_SIZE - byte_offset, byte_len)); + buf += min(SECTOR_SIZE - byte_offset, byte_len); + byte_len -= min(SECTOR_SIZE - byte_offset, byte_len); + sector++; + } + + if (byte_len == 0) + return 0; + + /* read sector aligned part */ + block_len = byte_len & ~(SECTOR_SIZE - 1); + + if (block_len == 0) { + u8 p[SECTOR_SIZE]; + + block_len = SECTOR_SIZE; + blockdev_read(bdev, sector, 1, p); + memcpy(buf, p, byte_len); + return 0; + } + + if (blockdev_read(bdev, sector, block_len / SECTOR_SIZE, buf) != + block_len / SECTOR_SIZE) { + printf(" ** zfs_devread() read error - block\n"); + return 1; + } + + block_len = byte_len & ~(SECTOR_SIZE - 1); + buf += block_len; + byte_len -= block_len; + sector += block_len / SECTOR_SIZE; + + if (byte_len != 0) { + /* read rest of data which are not in whole sector */ + if (blockdev_read(bdev, sector, 1, sec_buf) != 1) { + printf(" ** zfs_devread() read error - last part\n"); + return 1; + } + memcpy(buf, sec_buf, byte_len); + } + return 0; +} diff --git a/include/zfs_common.h b/include/zfs_common.h index 04e73d0..e2fcaaf 100644 --- a/include/zfs_common.h +++ b/include/zfs_common.h @@ -22,6 +22,10 @@ #ifndef __ZFS_COMMON__ #define __ZFS_COMMON__
+#ifdef CONFIG_DM +#include <dm/structures.h> +#endif + #define SECTOR_SIZE 0x200 #define SECTOR_BITS 9
@@ -103,7 +107,11 @@ int zfs_close(zfs_file_t); int zfs_ls(device_t dev, const char *path, int (*hook) (const char *, const struct zfs_dirhook_info *)); int zfs_devread(int sector, int byte_offset, int byte_len, char *buf); +#ifdef CONFIG_DM +int zfs_set_blk_dev(struct instance *dev); +#else int zfs_set_blk_dev(block_dev_desc_t *rbdd, int part); +#endif void zfs_unmount(struct zfs_data *data); int lzjb_decompress(void *, void *, uint32_t, uint32_t); #endif

add CONFIG_DM_BLOCK to include/configs/sandbox.h to enable it all
Signed-off-by: Pavel Herrmann morpheus.ibis@gmail.com --- arch/sandbox/lib/board.c | 8 ++++++++ include/configs/sandbox.h | 4 ++++ 2 files changed, 12 insertions(+)
diff --git a/arch/sandbox/lib/board.c b/arch/sandbox/lib/board.c index c79cc62..a6fc67d 100644 --- a/arch/sandbox/lib/board.c +++ b/arch/sandbox/lib/board.c @@ -243,6 +243,10 @@ void board_init_r(gd_t *id, ulong dest_addr) .name = "gpio_sandbox", .platform_data = NULL }; + static const struct driver_info sata_info = { + .name = "sata_legacy", + .platform_data = NULL + };
struct instance *root = get_root_instance(); struct instance *demo1, *demo2, *demo3; @@ -254,8 +258,12 @@ void board_init_r(gd_t *id, ulong dest_addr) demo3 = driver_bind(demo2, &info); driver_bind(demo2, &info); driver_bind(root, &gs_info); + driver_bind(root, &sata_info);
demo_hello(demo2); + void *startram = os_malloc(1024*1024*16); + void *endram = startram + (1024*1024*16); + printf("scratch memory from %p to %p\n", startram, endram);
/* initialize environment */ env_relocate(); diff --git a/include/configs/sandbox.h b/include/configs/sandbox.h index a713430..70ae37b 100644 --- a/include/configs/sandbox.h +++ b/include/configs/sandbox.h @@ -99,6 +99,10 @@ #define CONFIG_SYS_SATA_MAX_DEVICE 2 #define CONFIG_DOS_PARTITION #define CONFIG_CMD_FAT +#define CONFIG_FAT_WRITE #define CONFIG_CMD_EXT2
+#define CONFIG_DM_BLOCK +#define CONFIG_BLOCK_SATA_LEGACY + #endif
participants (3)
-
Marek Vasut
-
Pavel Herrmann
-
Vikram Narayanan