--- /dev/null
- name = ata_pthru;
- common = disk/ata_pthru.c;
+ AutoGen definitions Makefile.tpl;
+
+ script = {
+ installdir = noinst;
+ name = gensyminfo.sh;
+ common = gensyminfo.sh.in;
+ };
+
+ script = {
+ installdir = noinst;
+ name = genmod.sh;
+ common = genmod.sh.in;
+ };
+
+ kernel = {
+ name = kernel;
+
+ nostrip = emu;
+
+ emu_ldflags = '-Wl,-r,-d';
+ x86_efi_ldflags = '-Wl,-r,-d';
+ x86_efi_stripflags = '--strip-unneeded -K start -R .note -R .comment';
+
+ i386_pc_ldflags = '$(TARGET_IMG_LDFLAGS)';
+ i386_pc_ldflags = '$(TARGET_IMG_BASE_LDOPT),0x8200';
+
+ i386_qemu_ldflags = '$(TARGET_IMG_LDFLAGS)';
+ i386_qemu_ldflags = '$(TARGET_IMG_BASE_LDOPT),0x8200';
+
+ ldadd = '$(LDADD_KERNEL)';
+
+ i386_coreboot_ldflags = '-Wl,-Ttext=0x8200';
+ i386_multiboot_ldflags = '-Wl,-Ttext=0x8200';
+ i386_ieee1275_ldflags = '-Wl,-Ttext=0x10000';
+ mips_yeeloong_ldflags = '-Wl,-Ttext,0x80200000';
+ powerpc_ieee1275_ldflags = '-Wl,-Ttext,0x200000';
+ sparc64_ieee1275_ldflags = '-Wl,-Ttext,0x4400';
+
+ mips_yeeloong_cppflags = '-DUSE_ASCII_FAILBACK';
+ i386_qemu_cppflags = '-DGRUB_BOOT_MACHINE_LINK_ADDR=$(GRUB_BOOT_MACHINE_LINK_ADDR)';
+ emu_cflags = '$(CFLAGS_GNULIB)';
+ emu_cppflags = '$(CPPFLAGS_GNULIB)';
+
+ i386_pc_startup = kern/i386/pc/startup.S;
+ i386_efi_startup = kern/i386/efi/startup.S;
+ x86_64_efi_startup = kern/x86_64/efi/startup.S;
+ i386_qemu_startup = kern/i386/qemu/startup.S;
+ i386_ieee1275_startup = kern/i386/ieee1275/startup.S;
+ i386_coreboot_startup = kern/i386/coreboot/startup.S;
+ i386_multiboot_startup = kern/i386/coreboot/startup.S;
+ mips_yeeloong_startup = kern/mips/startup.S;
+ sparc64_ieee1275_startup = kern/sparc64/ieee1275/crt0.S;
+ powerpc_ieee1275_startup = kern/powerpc/ieee1275/startup.S;
+
+ common = kern/command.c;
+ common = kern/corecmd.c;
+ common = kern/device.c;
+ common = kern/disk.c;
+ common = kern/dl.c;
+ common = kern/env.c;
+ common = kern/err.c;
+ common = kern/file.c;
+ common = kern/fs.c;
+ common = kern/list.c;
+ common = kern/main.c;
+ common = kern/misc.c;
+ common = kern/parser.c;
+ common = kern/partition.c;
+ common = kern/rescue_parser.c;
+ common = kern/rescue_reader.c;
+ common = kern/term.c;
+
+ noemu = kern/mm.c;
+ noemu = kern/time.c;
+ noemu = kern/generic/millisleep.c;
+
+ noemu_nodist = symlist.c;
+
+ i386_pc = kern/generic/rtc_get_time_ms.c;
+ x86_efi = kern/generic/rtc_get_time_ms.c;
+ i386_qemu = kern/generic/rtc_get_time_ms.c;
+ i386_coreboot = kern/generic/rtc_get_time_ms.c;
+ i386_multiboot = kern/generic/rtc_get_time_ms.c;
+ mips_yeeloong = kern/generic/rtc_get_time_ms.c;
+
+ ieee1275 = disk/ieee1275/ofdisk.c;
+ ieee1275 = kern/ieee1275/cmain.c;
+ ieee1275 = kern/ieee1275/ieee1275.c;
+ ieee1275 = kern/ieee1275/mmap.c;
+ ieee1275 = kern/ieee1275/openfw.c;
+ ieee1275 = term/ieee1275/ofconsole.c;
+
+ terminfoinkernel = term/terminfo.c;
+ terminfoinkernel = term/tparm.c;
+ terminfoinkernel = commands/extcmd.c;
+ terminfoinkernel = lib/arg.c;
+
+ i386 = kern/i386/dl.c;
+
+ i386_coreboot_multiboot_qemu = kern/i386/coreboot/init.c;
+ i386_coreboot_multiboot_qemu = term/i386/pc/vga_text.c;
+
+ i386_coreboot_multiboot_qemu = term/i386/vga_common.c;
+ i386_pc = term/i386/vga_common.c;
+
+ x86 = kern/i386/pit.c;
+
+ x86_efi = disk/efi/efidisk.c;
+ x86_efi = kern/efi/efi.c;
+ x86_efi = kern/efi/init.c;
+ x86_efi = kern/efi/mm.c;
+ x86_efi = kern/i386/efi/init.c;
+ x86_efi = term/efi/console.c;
+
+ i386_efi = kern/i386/tsc.c;
+
+ x86_64_efi = kern/i386/tsc.c;
+ x86_64_efi = kern/x86_64/dl.c;
+ x86_64_efi = kern/x86_64/efi/callwrap.S;
+
+ i386_pc = kern/i386/pc/init.c;
+ i386_pc = kern/i386/pc/mmap.c;
+ i386_pc = kern/i386/tsc.c;
+ i386_pc = term/i386/pc/console.c;
+
+ i386_qemu = bus/pci.c;
+ i386_qemu = kern/i386/qemu/init.c;
+ i386_qemu = kern/i386/qemu/mmap.c;
+ i386_qemu = kern/i386/tsc.c;
+
+ i386_coreboot = kern/i386/coreboot/mmap.c;
+ i386_coreboot = kern/i386/tsc.c;
+
+ i386_multiboot = kern/i386/multiboot_mmap.c;
+ i386_multiboot = kern/i386/tsc.c;
+
+ i386_ieee1275 = kern/ieee1275/init.c;
+
+ mips_yeeloong = term/ns8250.c;
+ mips_yeeloong = bus/bonito.c;
+ mips_yeeloong = bus/cs5536.c;
+ mips_yeeloong = bus/pci.c;
+ mips_yeeloong = kern/mips/cache.S;
+ mips_yeeloong = kern/mips/dl.c;
+ mips_yeeloong = kern/mips/init.c;
+ mips_yeeloong = kern/mips/yeeloong/init.c;
+ mips_yeeloong = term/at_keyboard.c;
+ mips_yeeloong = term/serial.c;
+ mips_yeeloong = video/sm712.c;
+ extra_dist = video/sm712_init.c;
+ mips_yeeloong = commands/keylayouts.c;
+
+ powerpc_ieee1275 = kern/ieee1275/init.c;
+ powerpc_ieee1275 = kern/powerpc/cache.S;
+ powerpc_ieee1275 = kern/powerpc/dl.c;
+
+ sparc64_ieee1275 = kern/sparc64/cache.S;
+ sparc64_ieee1275 = kern/sparc64/dl.c;
+ sparc64_ieee1275 = kern/sparc64/ieee1275/ieee1275.c;
+ sparc64_ieee1275 = kern/sparc64/ieee1275/init.c;
+
+ emu = disk/host.c;
+ emu = gnulib/progname.c;
+ emu = gnulib/error.c;
+ emu = kern/emu/cache.S;
+ emu = kern/emu/console.c;
+ emu = kern/emu/getroot.c;
+ emu = kern/emu/hostdisk.c;
+ emu = kern/emu/hostfs.c;
+ emu = kern/emu/main.c;
+ emu = kern/emu/misc.c;
+ emu = kern/emu/mm.c;
+ emu = kern/emu/time.c;
+
+ videoinkernel = term/gfxterm.c;
+ videoinkernel = font/font.c;
+ videoinkernel = font/font_cmd.c;
+ videoinkernel = io/bufio.c;
+ videoinkernel = video/bitmap.c;
+ videoinkernel = video/bitmap_scale.c;
+ videoinkernel = video/fb/fbblit.c;
+ videoinkernel = video/fb/fbfill.c;
+ videoinkernel = video/fb/fbutil.c;
+ videoinkernel = video/fb/video_fb.c;
+ videoinkernel = video/video.c;
+
+ videoinkernel = commands/boot.c;
+
+ extra_dist = kern/i386/realmode.S;
+ extra_dist = kern/i386/pc/lzma_decode.S;
+ extra_dist = kern/mips/cache_flush.S;
+ };
+
+ program = {
+ name = grub-emu;
+ mansection = 1;
+
+ emu = kern/emu/full.c;
+ emu_nodist = grub_emu_init.c;
+
+ ldadd = 'kernel.img$(EXEEXT)';
+ ldadd = '$(MODULE_FILES)';
+ ldadd = '$(LIBUTIL) $(LIBCURSES) $(LIBSDL) $(LIBUSB) $(LIBPCIACCESS) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR)';
+
+ enable = emu;
+ };
+
+ program = {
+ name = grub-emu-lite;
+
+ emu = kern/emu/lite.c;
+ emu_nodist = symlist.c;
+
+ ldadd = 'kernel.img$(EXEEXT)';
+ ldadd = '$(LIBUTIL) $(LIBCURSES) $(LIBSDL) $(LIBUSB) $(LIBPCIACCESS) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR)';
+
+ enable = emu;
+ };
+
+ image = {
+ name = boot;
+ i386_pc = boot/i386/pc/boot.S;
+ i386_qemu = boot/i386/qemu/boot.S;
+ sparc64_ieee1275 = boot/sparc64/ieee1275/boot.S;
+
+ i386_pc_ldflags = '$(TARGET_IMG_LDFLAGS)';
+ i386_pc_ldflags = '$(TARGET_IMG_BASE_LDOPT),0x7C00';
+
+ i386_qemu_ldflags = '$(TARGET_IMG_LDFLAGS)';
+ i386_qemu_ldflags = '$(TARGET_IMG_BASE_LDOPT),$(GRUB_BOOT_MACHINE_LINK_ADDR)';
+ i386_qemu_ccasflags = '-DGRUB_BOOT_MACHINE_LINK_ADDR=$(GRUB_BOOT_MACHINE_LINK_ADDR)';
+
+ sparc64_ieee1275_objcopyflags = '-O a.out-sunos-big';
+ sparc64_ieee1275_ldflags = ' -Wl,-Ttext=0x4000';
+
+ objcopyflags = '-O binary';
+ enable = i386_pc;
+ enable = i386_qemu;
+ enable = sparc64_ieee1275;
+ };
+
+ image = {
+ name = cdboot;
+ i386_pc = boot/i386/pc/cdboot.S;
+ i386_pc_ldflags = '$(TARGET_IMG_LDFLAGS)';
+ i386_pc_ldflags = '$(TARGET_IMG_BASE_LDOPT),0x7C00';
+ objcopyflags = '-O binary';
+ enable = i386_pc;
+ };
+
+ image = {
+ name = pxeboot;
+ i386_pc = boot/i386/pc/pxeboot.S;
+
+ i386_pc_ldflags = '$(TARGET_IMG_LDFLAGS)';
+ i386_pc_ldflags = '$(TARGET_IMG_BASE_LDOPT),0x7C00';
+
+ objcopyflags = '-O binary';
+ enable = i386_pc;
+ };
+
+ image = {
+ name = diskboot;
+ i386_pc = boot/i386/pc/diskboot.S;
+
+ i386_pc_ldflags = '$(TARGET_IMG_LDFLAGS)';
+ i386_pc_ldflags = '$(TARGET_IMG_BASE_LDOPT),0x8000';
+
+ sparc64_ieee1275 = boot/sparc64/ieee1275/diskboot.S;
+ sparc64_ieee1275_ldflags = '-Wl,-Ttext=0x4200';
+
+ objcopyflags = '-O binary';
+
+ enable = i386_pc;
+ enable = sparc64_ieee1275;
+ };
+
+ image = {
+ name = lnxboot;
+ i386_pc = boot/i386/pc/lnxboot.S;
+
+ i386_pc_ldflags = '$(TARGET_IMG_LDFLAGS)';
+ i386_pc_ldflags = '$(TARGET_IMG_BASE_LDOPT),0x6000';
+
+ objcopyflags = '-O binary';
+ enable = i386_pc;
+ };
+
+ image = {
+ name = xz_decompress;
+ mips = boot/mips/startup_raw.S;
+ common = boot/decompressor/minilib.c;
+ common = boot/decompressor/xz.c;
+ common = lib/xzembed/xz_dec_bcj.c;
+ common = lib/xzembed/xz_dec_lzma2.c;
+ common = lib/xzembed/xz_dec_stream.c;
+
+ cppflags = '-I$(srcdir)/lib/posix_wrap -I$(srcdir)/lib/xzembed';
+
+ mips_cppflags = '-I$(srcdir)/lib/posix_wrap -I$(srcdir)/lib/xzembed -DGRUB_EMBED_DECOMPRESSOR=1 -DGRUB_MACHINE_LINK_ADDR=0x80200000';
+
+ objcopyflags = '-O binary';
+ ldflags = '-static-libgcc -Wl,-Ttext,0x80100000';
+ ldadd = '-lgcc';
+ cflags = '-static-libgcc';
+ enable = mips;
+ };
+
+ image = {
+ name = none_decompress;
+ mips = boot/mips/startup_raw.S;
+ common = boot/decompressor/none.c;
+
+ mips_cppflags = '-DGRUB_EMBED_DECOMPRESSOR=1 -DGRUB_MACHINE_LINK_ADDR=0x80200000';
+
+ objcopyflags = '-O binary';
+ ldflags = '-static-libgcc -Wl,-Ttext,0x80100000';
+ ldadd = '-lgcc';
+ cflags = '-static-libgcc';
+ enable = mips;
+ };
+
+ image = {
+ name = fwstart;
+ mips_yeeloong = boot/mips/yeeloong/fwstart.S;
+ objcopyflags = '-O binary';
+ enable = mips_yeeloong;
+ };
+
+ module = {
+ name = trig;
+ common_nodist = trigtables.c;
+ extra_dist = gentrigtables.c;
+ };
+
+ module = {
+ name = cs5536;
+ x86 = bus/cs5536.c;
+ enable = x86;
+ };
+
+ module = {
+ name = libusb;
+ emu = bus/usb/emu/usb.c;
+ enable = emu;
+ condition = COND_GRUB_EMU_USB;
+ };
+
+ module = {
+ name = lsspd;
+ mips_yeeloong = commands/mips/yeeloong/lsspd.c;
+ enable = mips_yeeloong;
+ };
+
+ module = {
+ name = usb;
+ common = bus/usb/usb.c;
+ noemu = bus/usb/usbtrans.c;
+ noemu = bus/usb/usbhub.c;
+ enable = emu;
+ enable = usb;
+ emu_condition = COND_GRUB_EMU_USB;
+ };
+
+ module = {
+ name = usbserial_common;
+ common = bus/usb/serial/common.c;
+ enable = usb;
+ };
+
+ module = {
+ name = usbserial_pl2303;
+ common = bus/usb/serial/pl2303.c;
+ enable = usb;
+ };
+
+ module = {
+ name = usbserial_ftdi;
+ common = bus/usb/serial/ftdi.c;
+ enable = usb;
+ };
+
+ module = {
+ name = uhci;
+ common = bus/usb/uhci.c;
+ enable = x86;
+ };
+
+ module = {
+ name = ohci;
+ common = bus/usb/ohci.c;
+ enable = pci;
+ };
+
+ module = {
+ name = pci;
+ noemu = bus/pci.c;
+ emu = bus/emu/pci.c;
+ emu = commands/lspci.c;
+
+ enable = emu;
+ enable = i386_pc;
+ enable = x86_efi;
+ enable = i386_ieee1275;
+ enable = i386_coreboot;
+ enable = i386_multiboot;
+ emu_condition = COND_GRUB_EMU_PCI;
+ };
+
+ library = {
+ name = libgnulib.a;
+ common = gnulib/regex.c;
+ cflags = '$(CFLAGS_POSIX) $(CFLAGS_GNULIB)';
+ cppflags = '$(CPPFLAGS_POSIX) $(CPPFLAGS_GNULIB)';
+ };
+
+ module = {
+ name = cmostest;
+ common = commands/i386/cmostest.c;
+ enable = cmos;
+ };
+
+ module = {
+ name = iorw;
+ common = commands/iorw.c;
+ enable = x86;
+ };
+
+ module = {
+ name = regexp;
+ common = commands/regexp.c;
+ common = commands/wildcard.c;
+ ldadd = libgnulib.a;
+ cflags = '$(CFLAGS_POSIX) $(CFLAGS_GNULIB)';
+ cppflags = '$(CPPFLAGS_POSIX) $(CPPFLAGS_GNULIB)';
+ };
+
+ module = {
+ name = acpi;
+
+ common = commands/acpi.c;
+ x86_efi = commands/efi/acpi.c;
+ i386_pc = commands/i386/pc/acpi.c;
+ i386_coreboot = commands/i386/pc/acpi.c;
+ i386_multiboot = commands/i386/pc/acpi.c;
+
+ enable = x86_efi;
+ enable = i386_pc;
+ enable = i386_coreboot;
+ enable = i386_multiboot;
+ };
+
+ module = {
+ name = lsacpi;
+
+ common = commands/lsacpi.c;
+
+ enable = x86_efi;
+ enable = i386_pc;
+ enable = i386_coreboot;
+ enable = i386_multiboot;
+ };
+
+ module = {
+ name = lsefisystab;
+
+ common = commands/efi/lsefisystab.c;
+
+ enable = x86_efi;
+ };
+
+ module = {
+ name = lssal;
+
+ common = commands/efi/lssal.c;
+
+ enable = x86_efi;
+ };
+
+ module = {
+ name = lsefimmap;
+
+ common = commands/efi/lsefimmap.c;
+
+ enable = x86_efi;
+ };
+
+ module = {
+ name = blocklist;
+ common = commands/blocklist.c;
+ };
+
+ module = {
+ name = boot;
+ common = commands/boot.c;
+ i386_pc = lib/i386/pc/biosnum.c;
+ enable = videomodules;
+ };
+
+ module = {
+ name = cat;
+ common = commands/cat.c;
+ };
+
+ module = {
+ name = cmp;
+ common = commands/cmp.c;
+ };
+
+ module = {
+ name = configfile;
+ common = commands/configfile.c;
+ };
+
+ module = {
+ name = cpuid;
+ x86 = commands/i386/cpuid.c;
+ enable = x86;
+ };
+
+ module = {
+ name = date;
+ common = commands/date.c;
+ };
+
+ module = {
+ name = drivemap;
+
+ i386_pc = commands/i386/pc/drivemap.c;
+ i386_pc = commands/i386/pc/drivemap_int13h.S;
+ enable = i386_pc;
+ };
+
+ module = {
+ name = echo;
+ common = commands/echo.c;
+ };
+
+ module = {
+ name = extcmd;
+ common = commands/extcmd.c;
+ common = lib/arg.c;
+ enable = terminfomodule;
+ };
+
+ module = {
+ name = fixvideo;
+ x86_efi = commands/efi/fixvideo.c;
+ enable = x86_efi;
+ };
+
+ module = {
+ name = gptsync;
+ common = commands/gptsync.c;
+ };
+
+ module = {
+ name = halt;
+ nopc = commands/halt.c;
+ i386_pc = commands/i386/pc/halt.c;
+ i386_pc = commands/acpihalt.c;
+ i386_coreboot = commands/acpihalt.c;
+ i386_multiboot = commands/acpihalt.c;
+ x86_efi = commands/acpihalt.c;
+ i386_multiboot = lib/i386/halt.c;
+ i386_coreboot = lib/i386/halt.c;
+ i386_qemu = lib/i386/halt.c;
+ x86_efi = lib/efi/halt.c;
+ ieee1275 = lib/ieee1275/halt.c;
+ emu = lib/emu/halt.c;
+ };
+
+ module = {
+ name = hashsum;
+ common = commands/hashsum.c;
+ };
+
+ module = {
+ name = hdparm;
+ common = commands/hdparm.c;
+ common = lib/hexdump.c;
+ enable = pci;
+ };
+
+ module = {
+ name = help;
+ common = commands/help.c;
+ };
+
+ module = {
+ name = hexdump;
+ common = commands/hexdump.c;
+ common = lib/hexdump.c;
+ };
+
+ module = {
+ name = keystatus;
+ common = commands/keystatus.c;
+ };
+
+ module = {
+ name = loadbios;
+ x86_efi = commands/efi/loadbios.c;
+ enable = x86_efi;
+ };
+
+ module = {
+ name = loadenv;
+ common = commands/loadenv.c;
+ common = lib/envblk.c;
+ };
+
+ module = {
+ name = ls;
+ common = commands/ls.c;
+ };
+
+ module = {
+ name = lsmmap;
+ common = commands/lsmmap.c;
+ };
+
+ module = {
+ name = lspci;
+ common = commands/lspci.c;
+
+ enable = pci;
+ };
+
+ module = {
+ name = memrw;
+ common = commands/memrw.c;
+ };
+
+ module = {
+ name = minicmd;
+ common = commands/minicmd.c;
+ };
+
+ module = {
+ name = parttool;
+ common = commands/parttool.c;
+ };
+
+ module = {
+ name = password;
+ common = commands/password.c;
+ };
+
+ module = {
+ name = password_pbkdf2;
+ common = commands/password_pbkdf2.c;
+ };
+
+ module = {
+ name = play;
+ x86 = commands/i386/pc/play.c;
+ enable = x86;
+ };
+
+ module = {
+ name = probe;
+ common = commands/probe.c;
+ };
+
+ module = {
+ name = pxecmd;
+ i386_pc = commands/i386/pc/pxecmd.c;
+ enable = i386_pc;
+ };
+
+ module = {
+ name = read;
+ common = commands/read.c;
+ };
+
+ module = {
+ name = reboot;
+ common = commands/reboot.c;
+ };
+
+ module = {
+ name = search;
+ common = commands/search_wrap.c;
+ extra_dist = commands/search.c;
+ };
+
+ module = {
+ name = search_fs_file;
+ common = commands/search_file.c;
+ };
+
+ module = {
+ name = search_fs_uuid;
+ common = commands/search_uuid.c;
+ };
+
+ module = {
+ name = search_label;
+ common = commands/search_label.c;
+ };
+
+ module = {
+ name = setpci;
+ common = commands/setpci.c;
+ enable = x86;
+ };
+
+ module = {
+ name = sleep;
+ common = commands/sleep.c;
+ };
+
+ module = {
+ name = suspend;
+ ieee1275 = commands/ieee1275/suspend.c;
+ enable = i386_ieee1275;
+ enable = powerpc_ieee1275;
+ };
+
+ module = {
+ name = terminal;
+ common = commands/terminal.c;
+ };
+
+ module = {
+ name = test;
+ common = commands/test.c;
+ };
+
+ module = {
+ name = true;
+ common = commands/true.c;
+ };
+
+ module = {
+ name = usbtest;
+ common = commands/usbtest.c;
+ enable = usb;
+ enable = emu;
+ emu_condition = COND_GRUB_EMU_USB;
+ };
+
+ module = {
+ name = videoinfo;
+ common = commands/videoinfo.c;
+ };
+
+ module = {
+ name = videotest;
+ common = commands/videotest.c;
+ };
+
+ module = {
+ name = xnu_uuid;
+ common = commands/xnu_uuid.c;
+ };
+
+ module = {
+ name = dm_nv;
+ common = disk/dmraid_nvidia.c;
+ };
+
+ module = {
+ name = loopback;
+ common = disk/loopback.c;
+ };
+
+ module = {
+ name = lvm;
+ common = disk/lvm.c;
+ };
+
+ module = {
+ name = mdraid09;
+ common = disk/mdraid_linux.c;
+ };
+
+ module = {
+ name = mdraid1x;
+ common = disk/mdraid1x_linux.c;
+ };
+
+ module = {
+ name = raid;
+ common = disk/raid.c;
+ };
+
+ module = {
+ name = raid5rec;
+ common = disk/raid5_recover.c;
+ };
+
+ module = {
+ name = raid6rec;
+ common = disk/raid6_recover.c;
+ };
+
+ module = {
+ name = scsi;
+ common = disk/scsi.c;
+ };
+
+ module = {
+ name = memdisk;
+ common = disk/memdisk.c;
+ };
+
+ module = {
+ name = ata;
+ common = disk/ata.c;
+ enable = pci;
+ };
+
+ module = {
++ name = ahci;
++ common = disk/ahci.c;
++ enable = pci;
++};
++
++module = {
++ name = pata;
++ common = disk/pata.c;
+ enable = pci;
+ };
+
+ module = {
+ name = biosdisk;
+ i386_pc = disk/i386/pc/biosdisk.c;
+ enable = i386_pc;
+ };
+
+ module = {
+ name = usbms;
+ common = disk/usbms.c;
+ enable = usb;
+ enable = emu;
+ emu_condition = COND_GRUB_EMU_USB;
+ };
+
+ module = {
+ name = nand;
+ ieee1275 = disk/ieee1275/nand.c;
+ enable = i386_ieee1275;
+ };
+
+ module = {
+ name = efiemu;
+ common = efiemu/main.c;
+ common = efiemu/i386/loadcore32.c;
+ common = efiemu/i386/loadcore64.c;
+ i386_pc = efiemu/i386/pc/cfgtables.c;
+ i386_coreboot = efiemu/i386/pc/cfgtables.c;
+ i386_multiboot = efiemu/i386/pc/cfgtables.c;
+ i386_ieee1275 = efiemu/i386/nocfgtables.c;
+ i386_qemu = efiemu/i386/nocfgtables.c;
+ common = efiemu/mm.c;
+ common = efiemu/loadcore_common.c;
+ common = efiemu/symbols.c;
+ common = efiemu/loadcore32.c;
+ common = efiemu/loadcore64.c;
+ common = efiemu/prepare32.c;
+ common = efiemu/prepare64.c;
+ common = efiemu/pnvram.c;
+ common = efiemu/i386/coredetect.c;
+
+ extra_dist = efiemu/prepare.c;
+ extra_dist = efiemu/loadcore.c;
+ extra_dist = efiemu/runtime/efiemu.S;
+ extra_dist = efiemu/runtime/efiemu.c;
+
+ enable = i386_pc;
+ enable = i386_coreboot;
+ enable = i386_ieee1275;
+ enable = i386_multiboot;
+ enable = i386_qemu;
+ };
+
+ module = {
+ name = font;
+ common = font/font.c;
+ common = font/font_cmd.c;
+ enable = videomodules;
+ };
+
+ module = {
+ name = affs;
+ common = fs/affs.c;
+ };
+
+ module = {
+ name = afs;
+ common = fs/afs.c;
+ };
+
+ module = {
+ name = afs_be;
+ common = fs/afs_be.c;
+ };
+
+ module = {
+ name = befs;
+ common = fs/befs.c;
+ };
+
+ module = {
+ name = befs_be;
+ common = fs/befs_be.c;
+ };
+
+ module = {
+ name = btrfs;
+ common = fs/btrfs.c;
+ };
+
+ module = {
+ name = cpio;
+ common = fs/cpio.c;
+ };
+
+ module = {
+ name = ext2;
+ common = fs/ext2.c;
+ };
+
+ module = {
+ name = fat;
+ common = fs/fat.c;
+ };
+
+ module = {
+ name = fshelp;
+ common = fs/fshelp.c;
+ };
+
+ module = {
+ name = hfs;
+ common = fs/hfs.c;
+ };
+
+ module = {
+ name = hfsplus;
+ common = fs/hfsplus.c;
+ };
+
+ module = {
+ name = iso9660;
+ common = fs/iso9660.c;
+ };
+
+ module = {
+ name = jfs;
+ common = fs/jfs.c;
+ };
+
+ module = {
+ name = minix;
+ common = fs/minix.c;
+ };
+
+ module = {
+ name = minix2;
+ common = fs/minix2.c;
+ };
+
+ module = {
+ name = nilfs2;
+ common = fs/nilfs2.c;
+ };
+
+ module = {
+ name = ntfs;
+ common = fs/ntfs.c;
+ };
+
+ module = {
+ name = ntfscomp;
+ common = fs/ntfscomp.c;
+ };
+
+ module = {
+ name = reiserfs;
+ common = fs/reiserfs.c;
+ };
+
+ module = {
+ name = sfs;
+ common = fs/sfs.c;
+ };
+
+ module = {
+ name = tar;
+ common = fs/tar.c;
+ };
+
+ module = {
+ name = udf;
+ common = fs/udf.c;
+ };
+
+ module = {
+ name = ufs1;
+ common = fs/ufs.c;
+ };
+
+ module = {
+ name = ufs2;
+ common = fs/ufs2.c;
+ };
+
+ module = {
+ name = xfs;
+ common = fs/xfs.c;
+ };
+
+ module = {
+ name = zfs;
+ common = fs/zfs/zfs.c;
+ common = fs/zfs/zfs_lzjb.c;
+ common = fs/zfs/zfs_sha256.c;
+ common = fs/zfs/zfs_fletcher.c;
+ };
+
+ module = {
+ name = zfsinfo;
+ common = fs/zfs/zfsinfo.c;
+ };
+
+ module = {
+ name = pxe;
+ i386_pc = fs/i386/pc/pxe.c;
+ enable = i386_pc;
+ };
+
+ module = {
+ name = gettext;
+ common = gettext/gettext.c;
+ };
+
+ module = {
+ name = gfxmenu;
+ common = gfxmenu/gfxmenu.c;
+ common = gfxmenu/model.c;
+ common = gfxmenu/view.c;
+ common = gfxmenu/font.c;
+ common = gfxmenu/icon_manager.c;
+ common = gfxmenu/theme_loader.c;
+ common = gfxmenu/widget-box.c;
+ common = gfxmenu/gui_canvas.c;
+ common = gfxmenu/gui_circular_progress.c;
+ common = gfxmenu/gui_box.c;
+ common = gfxmenu/gui_label.c;
+ common = gfxmenu/gui_list.c;
+ common = gfxmenu/gui_image.c;
+ common = gfxmenu/gui_progress_bar.c;
+ common = gfxmenu/gui_util.c;
+ common = gfxmenu/gui_string_util.c;
+ common = gfxmenu/named_colors.c;
+ };
+
+ module = {
+ name = hello;
+ common = hello/hello.c;
+ };
+
+ module = {
+ name = gzio;
+ common = io/gzio.c;
+ };
+
+ module = {
+ name = bufio;
+ common = io/bufio.c;
+ enable = videomodules;
+ };
+
+ module = {
+ name = elf;
+ common = kern/elf.c;
+ };
+
+ module = {
+ name = crypto;
+ common = lib/crypto.c;
+
+ extra_dist = lib/libgcrypt-grub/cipher/crypto.lst;
+ };
+
+ module = {
+ name = pbkdf2;
+ common = lib/pbkdf2.c;
+ };
+
+ module = {
+ name = relocator;
+ common = lib/relocator.c;
+ x86 = lib/i386/relocator16.S;
+ x86 = lib/i386/relocator32.S;
+ x86 = lib/i386/relocator64.S;
+ i386 = lib/i386/relocator_asm.S;
+ x86_64 = lib/x86_64/relocator_asm.S;
+ x86 = lib/i386/relocator.c;
+ ieee1275 = lib/ieee1275/relocator.c;
+ x86_efi = lib/efi/relocator.c;
+ mips = lib/mips/relocator_asm.S;
+ mips = lib/mips/relocator.c;
+ powerpc = lib/powerpc/relocator_asm.S;
+ powerpc = lib/powerpc/relocator.c;
+
+ extra_dist = lib/i386/relocator_common.S;
+ extra_dist = kern/powerpc/cache_flush.S;
+
+ enable = mips;
+ enable = powerpc;
+ enable = x86;
+ };
+
+ module = {
+ name = datetime;
+ cmos = lib/cmos_datetime.c;
+ x86_efi = lib/efi/datetime.c;
+ sparc64_ieee1275 = lib/ieee1275/datetime.c;
+ powerpc_ieee1275 = lib/ieee1275/datetime.c;
+ enable = noemu;
+ };
+
+ module = {
+ name = setjmp;
+ common = lib/setjmp.S;
+ extra_dist = lib/i386/setjmp.S;
+ extra_dist = lib/mips/setjmp.S;
+ extra_dist = lib/x86_64/setjmp.S;
+ extra_dist = lib/sparc64/setjmp.S;
+ extra_dist = lib/powerpc/setjmp.S;
+ };
+
+ module = {
+ name = aout;
+ common = loader/aout.c;
+ enable = x86;
+ };
+
+ module = {
+ name = bsd;
+ x86 = loader/i386/bsd.c;
+ x86 = loader/i386/bsd32.c;
+ x86 = loader/i386/bsd64.c;
+
+ extra_dist = loader/i386/bsdXX.c;
+ extra_dist = loader/i386/bsd_pagetable.c;
+
+ enable = x86;
+ };
+
+ module = {
+ name = linux16;
+ i386_pc = loader/i386/pc/linux.c;
+ enable = i386_pc;
+ };
+
+ module = {
+ name = ntldr;
+ i386_pc = loader/i386/pc/ntldr.c;
+ enable = i386_pc;
+ };
+
+ module = {
+ name = multiboot2;
+ cppflags = "-DGRUB_USE_MULTIBOOT2";
+
+ common = loader/multiboot.c;
+ common = loader/multiboot_mbi2.c;
+ enable = x86;
+ enable = mips;
+ };
+
+ module = {
+ name = multiboot;
+ common = loader/multiboot.c;
+ x86 = loader/i386/multiboot_mbi.c;
+ extra_dist = loader/multiboot_elfxx.c;
+ enable = x86;
+ };
+
+ module = {
+ name = linux;
+ x86 = loader/i386/linux.c;
+ i386_pc = lib/i386/pc/vesa_modes_table.c;
+ mips = loader/mips/linux.c;
+ powerpc_ieee1275 = loader/powerpc/ieee1275/linux.c;
+ sparc64_ieee1275 = loader/sparc64/ieee1275/linux.c;
+ enable = noemu;
+ };
+
+ module = {
+ name = xnu;
+ x86 = loader/xnu_resume.c;
+ x86 = loader/i386/xnu.c;
+ x86 = loader/macho32.c;
+ x86 = loader/macho64.c;
+ x86 = loader/macho.c;
+ x86 = loader/xnu.c;
+
+ extra_dist = loader/machoXX.c;
+ enable = x86;
+ };
+
+ module = {
+ name = appleldr;
+ x86_efi = loader/efi/appleloader.c;
+ enable = x86_efi;
+ };
+
+ module = {
+ name = chain;
+ x86_efi = loader/efi/chainloader.c;
+ i386_pc = loader/i386/pc/chainloader.c;
+ enable = i386_pc;
+ enable = x86_efi;
+ };
+
+ module = {
+ name = mmap;
+ common = mmap/mmap.c;
+ x86 = mmap/i386/uppermem.c;
+ x86 = mmap/i386/mmap.c;
+
+ i386_pc = mmap/i386/pc/mmap.c;
+ i386_pc = mmap/i386/pc/mmap_helper.S;
+
+ x86_efi = mmap/efi/mmap.c;
+
+ mips_yeeloong = mmap/mips/yeeloong/uppermem.c;
+
+ enable = x86;
+ enable = mips_yeeloong;
+ };
+
+ module = {
+ name = normal;
+ common = normal/main.c;
+ common = normal/cmdline.c;
+ common = normal/dyncmd.c;
+ common = normal/auth.c;
+ common = normal/autofs.c;
+ common = normal/color.c;
+ common = normal/completion.c;
+ common = normal/datetime.c;
+ common = normal/menu.c;
+ common = normal/menu_entry.c;
+ common = normal/menu_text.c;
+ common = normal/misc.c;
+ common = normal/crypto.c;
+ common = normal/term.c;
+ common = normal/context.c;
+ common = normal/charset.c;
+
+ common = script/main.c;
+ common = script/script.c;
+ common = script/execute.c;
+ common = script/function.c;
+ common = script/lexer.c;
+ common = script/argv.c;
+
+ common = commands/menuentry.c;
+
+ common = unidata.c;
+ common_nodist = grub_script.tab.c;
+ common_nodist = grub_script.yy.c;
+ common_nodist = grub_script.tab.h;
+ common_nodist = grub_script.yy.h;
+
+ extra_dist = script/yylex.l;
+ extra_dist = script/parser.y;
+
+ cflags = '$(CFLAGS_POSIX) -Wno-error';
+ cppflags = '$(CPPFLAGS_POSIX)';
+ };
+
+ module = {
+ name = part_acorn;
+ common = partmap/acorn.c;
+ };
+
+ module = {
+ name = part_amiga;
+ common = partmap/amiga.c;
+ };
+
+ module = {
+ name = part_apple;
+ common = partmap/apple.c;
+ };
+
+ module = {
+ name = part_gpt;
+ common = partmap/gpt.c;
+ };
+
+ module = {
+ name = part_msdos;
+ common = partmap/msdos.c;
+ };
+
+ module = {
+ name = part_sun;
+ common = partmap/sun.c;
+ };
+
+ module = {
+ name = part_bsd;
+ common = partmap/bsdlabel.c;
+ };
+
+ module = {
+ name = part_sunpc;
+ common = partmap/sunpc.c;
+ };
+
+ module = {
+ name = msdospart;
+ common = parttool/msdospart.c;
+ };
+
+ module = {
+ name = at_keyboard;
+ common = term/at_keyboard.c;
+ enable = x86;
+ };
+
+ module = {
+ name = gfxterm;
+ common = term/gfxterm.c;
+ enable = videomodules;
+ };
+
+ module = {
+ name = serial;
+ common = term/serial.c;
+ x86 = term/ns8250.c;
+
+ enable = emu;
+ enable = i386;
+ enable = x86_64_efi;
+ emu_condition = COND_GRUB_EMU_USB;
+ };
+
+ module = {
+ name = sendkey;
+ i386_pc = commands/i386/pc/sendkey.c;
+ enable = i386_pc;
+ };
+
+ module = {
+ name = terminfo;
+ common = term/terminfo.c;
+ common = term/tparm.c;
+ enable = terminfomodule;
+ };
+
+ module = {
+ name = usb_keyboard;
+ common = term/usb_keyboard.c;
+ enable = usb;
+ };
+
+ module = {
+ name = vga;
+ i386_pc = video/i386/pc/vga.c;
+ enable = i386_pc;
+ };
+
+ module = {
+ name = vga_text;
+ common = term/i386/pc/vga_text.c;
+ common = term/i386/vga_common.c;
+ enable = i386_pc;
+ enable = i386_coreboot;
+ enable = i386_multiboot;
+ };
+
+ module = {
+ name = video_cirrus;
+ x86 = video/cirrus.c;
+ enable = x86;
+ };
+
+ module = {
+ name = video_bochs;
+ x86 = video/bochs.c;
+ enable = x86;
+ };
+
+ module = {
+ name = functional_test;
+ common = tests/lib/functional_test.c;
+ common = tests/lib/test.c;
+ };
+
+ module = {
+ name = example_functional_test;
+ common = tests/example_functional_test.c;
+ cflags = -Wno-format;
+ };
+
+ module = {
+ name = bitmap;
+ common = video/bitmap.c;
+ enable = videomodules;
+ };
+
+ module = {
+ name = bitmap_scale;
+ common = video/bitmap_scale.c;
+ enable = videomodules;
+ };
+
+ module = {
+ name = efi_gop;
+ x86_efi = video/efi_gop.c;
+ enable = x86_efi;
+ };
+
+ module = {
+ name = efi_uga;
+ x86_efi = video/efi_uga.c;
+ enable = x86_efi;
+ };
+
+ module = {
+ name = jpeg;
+ common = video/readers/jpeg.c;
+ };
+
+ module = {
+ name = png;
+ common = video/readers/png.c;
+ };
+
+ module = {
+ name = tga;
+ common = video/readers/tga.c;
+ };
+
+ module = {
+ name = vbe;
+ i386_pc = video/i386/pc/vbe.c;
+ enable = i386_pc;
+ };
+
+ module = {
+ name = video_fb;
+ common = video/fb/video_fb.c;
+ common = video/fb/fbblit.c;
+ common = video/fb/fbfill.c;
+ common = video/fb/fbutil.c;
+ enable = videomodules;
+ };
+
+ module = {
+ name = video;
+ common = video/video.c;
+ enable = videomodules;
+ };
+
+ module = {
+ name = ieee1275_fb;
+ ieee1275 = video/ieee1275.c;
+ enable = powerpc;
+ enable = sparc64;
+ };
+
+ module = {
+ name = sdl;
+ emu = video/emu/sdl.c;
+ enable = emu;
+ condition = COND_GRUB_EMU_SDL;
+ };
+
+ module = {
+ name = datehook;
+ common = hook/datehook.c;
+ };
+
+ module = {
+ name = legacycfg;
+ common = commands/legacycfg.c;
+ common = lib/legacy_parse.c;
+ emu = lib/i386/pc/vesa_modes_table.c;
+ enable = i386_pc;
+ enable = emu;
+ };
+
+ module = {
+ name = test_blockarg;
+ common = tests/test_blockarg.c;
+ };
+
+ module = {
+ name = xzio;
+ common = io/xzio.c;
+ common = lib/xzembed/xz_dec_bcj.c;
+ common = lib/xzembed/xz_dec_lzma2.c;
+ common = lib/xzembed/xz_dec_stream.c;
+ cppflags = '-I$(srcdir)/lib/posix_wrap -I$(srcdir)/lib/xzembed';
+ };
+
+ module = {
+ name = testload;
+ common = commands/testload.c;
+ };
+
+ module = {
+ name = lsapm;
+ common = commands/i386/pc/lsapm.c;
+ enable = i386_pc;
+ };
+
+ module = {
+ name = keylayouts;
+ common = commands/keylayouts.c;
+ enable = videomodules;
+ };
--- /dev/null
-grub_hdparm_do_ata_cmd (grub_disk_t disk, grub_uint8_t cmd,
+ /* hdparm.c - command to get/set ATA disk parameters. */
+ /*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2009 Free Software Foundation, Inc.
+ *
+ * GRUB 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB 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 GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+ #include <grub/ata.h>
++#include <grub/scsi.h>
+ #include <grub/disk.h>
+ #include <grub/dl.h>
+ #include <grub/misc.h>
+ #include <grub/mm.h>
+ #include <grub/lib/hexdump.h>
+ #include <grub/extcmd.h>
+ #include <grub/i18n.h>
+
+ static const struct grub_arg_option options[] = {
+ {"apm", 'B', 0, N_("Set Advanced Power Management\n"
+ "(1=low, ..., 254=high, 255=off)."),
+ 0, ARG_TYPE_INT},
+ {"power", 'C', 0, N_("Check power mode."), 0, ARG_TYPE_NONE},
+ {"security-freeze", 'F', 0, N_("Freeze ATA security settings until reset."),
+ 0, ARG_TYPE_NONE},
+ {"health", 'H', 0, N_("Check SMART health status."), 0, ARG_TYPE_NONE},
+ {"aam", 'M', 0, N_("Set Automatic Acoustic Management\n"
+ "(0=off, 128=quiet, ..., 254=fast)."),
+ 0, ARG_TYPE_INT},
+ {"standby-timeout", 'S', 0, N_("Set standby timeout\n"
+ "(0=off, 1=5s, 2=10s, ..., 240=20m, 241=30m, ...)."),
+ 0, ARG_TYPE_INT},
+ {"standby", 'y', 0, N_("Set drive to standby mode."), 0, ARG_TYPE_NONE},
+ {"sleep", 'Y', 0, N_("Set drive to sleep mode."), 0, ARG_TYPE_NONE},
+ {"identify", 'i', 0, N_("Print drive identity and settings."),
+ 0, ARG_TYPE_NONE},
+ {"dumpid", 'I', 0, N_("Dump contents of ATA IDENTIFY sector."),
+ 0, ARG_TYPE_NONE},
+ {"smart", -1, 0, N_("Disable/enable SMART (0/1)."), 0, ARG_TYPE_INT},
+ {"quiet", 'q', 0, N_("Do not print messages."), 0, ARG_TYPE_NONE},
+ {0, 0, 0, 0, 0, 0}
+ };
+
+ enum grub_ata_smart_commands
+ {
+ GRUB_ATA_FEAT_SMART_ENABLE = 0xd8,
+ GRUB_ATA_FEAT_SMART_DISABLE = 0xd9,
+ GRUB_ATA_FEAT_SMART_STATUS = 0xda,
+ };
+
+ static int quiet = 0;
+
+ static grub_err_t
- apt.taskfile[GRUB_ATA_REG_CMD] = cmd;
- apt.taskfile[GRUB_ATA_REG_FEATURES] = features;
- apt.taskfile[GRUB_ATA_REG_SECTORS] = sectors;
++grub_hdparm_do_ata_cmd (grub_ata_t ata, grub_uint8_t cmd,
+ grub_uint8_t features, grub_uint8_t sectors,
+ void * buffer, int size)
+ {
+ struct grub_disk_ata_pass_through_parms apt;
+ grub_memset (&apt, 0, sizeof (apt));
+
- if (grub_disk_ata_pass_through (disk, &apt))
++ apt.taskfile.cmd = cmd;
++ apt.taskfile.features = features;
++ apt.taskfile.sectors = sectors;
+ apt.buffer = buffer;
+ apt.size = size;
+
-grub_hdparm_do_check_powermode_cmd (grub_disk_t disk)
++ if (ata->dev->readwrite (ata, &apt))
+ return grub_errno;
+
+ return GRUB_ERR_NONE;
+ }
+
+ static int
- apt.taskfile[GRUB_ATA_REG_CMD] = GRUB_ATA_CMD_CHECK_POWER_MODE;
++grub_hdparm_do_check_powermode_cmd (grub_ata_t ata)
+ {
+ struct grub_disk_ata_pass_through_parms apt;
+ grub_memset (&apt, 0, sizeof (apt));
+
- if (grub_disk_ata_pass_through (disk, &apt))
++ apt.taskfile.cmd = GRUB_ATA_CMD_CHECK_POWER_MODE;
+
- return apt.taskfile[GRUB_ATA_REG_SECTORS];
++ if (ata->dev->readwrite (ata, &apt))
+ return -1;
+
-grub_hdparm_do_smart_cmd (grub_disk_t disk, grub_uint8_t features)
++ return apt.taskfile.sectors;
+ }
+
+ static int
- apt.taskfile[GRUB_ATA_REG_CMD] = GRUB_ATA_CMD_SMART;
- apt.taskfile[GRUB_ATA_REG_FEATURES] = features;
- apt.taskfile[GRUB_ATA_REG_LBAMID] = 0x4f;
- apt.taskfile[GRUB_ATA_REG_LBAHIGH] = 0xc2;
++grub_hdparm_do_smart_cmd (grub_ata_t ata, grub_uint8_t features)
+ {
+ struct grub_disk_ata_pass_through_parms apt;
+ grub_memset (&apt, 0, sizeof (apt));
+
- if (grub_disk_ata_pass_through (disk, &apt))
++ apt.taskfile.cmd = GRUB_ATA_CMD_SMART;
++ apt.taskfile.features = features;
++ apt.taskfile.lba_mid = 0x4f;
++ apt.taskfile.lba_high = 0xc2;
+
- if ( apt.taskfile[GRUB_ATA_REG_LBAMID] == 0x4f
- && apt.taskfile[GRUB_ATA_REG_LBAHIGH] == 0xc2)
++ if (ata->dev->readwrite (ata, &apt))
+ return -1;
+
+ if (features == GRUB_ATA_FEAT_SMART_STATUS)
+ {
- else if ( apt.taskfile[GRUB_ATA_REG_LBAMID] == 0xf4
- && apt.taskfile[GRUB_ATA_REG_LBAHIGH] == 0x2c)
++ if ( apt.taskfile.lba_mid == 0x4f
++ && apt.taskfile.lba_high == 0xc2)
+ return 0; /* Good SMART status. */
- grub_disk_t disk, grub_uint8_t cmd)
++ else if ( apt.taskfile.lba_mid == 0xf4
++ && apt.taskfile.lba_high == 0x2c)
+ return 1; /* Bad SMART status. */
+ else
+ return -1;
+ }
+ return 0;
+ }
+
+ static grub_err_t
+ grub_hdparm_simple_cmd (const char * msg,
- grub_err_t err = grub_hdparm_do_ata_cmd (disk, cmd, 0, 0, NULL, 0);
++ grub_ata_t ata, grub_uint8_t cmd)
+ {
+ if (! quiet && msg)
+ grub_printf ("%s", msg);
+
- grub_disk_t disk, grub_uint8_t cmd,
++ grub_err_t err = grub_hdparm_do_ata_cmd (ata, cmd, 0, 0, NULL, 0);
+
+ if (! quiet && msg)
+ grub_printf ("%s\n", ! err ? "" : ": not supported");
+ return err;
+ }
+
+ static grub_err_t
+ grub_hdparm_set_val_cmd (const char * msg, int val,
- grub_err_t err = grub_hdparm_do_ata_cmd (disk, cmd, features, sectors,
++ grub_ata_t ata, grub_uint8_t cmd,
+ grub_uint8_t features, grub_uint8_t sectors)
+ {
+ if (! quiet && msg && *msg)
+ {
+ if (val >= 0)
+ grub_printf ("Set %s to %d", msg, val);
+ else
+ grub_printf ("Disable %s", msg);
+ }
+
- if (! grub_disk_ata_pass_through)
- return grub_error (GRUB_ERR_BAD_ARGUMENT, "ATA pass through not available");
-
++ grub_err_t err = grub_hdparm_do_ata_cmd (ata, cmd, features, sectors,
+ NULL, 0);
+
+ if (! quiet && msg)
+ grub_printf ("%s\n", ! err ? "" : ": not supported");
+ return err;
+ }
+
+ static const char *
+ le16_to_char (char *dest, const grub_uint16_t * src16, unsigned bytes)
+ {
+ grub_uint16_t * dest16 = (grub_uint16_t *) dest;
+ unsigned i;
+ for (i = 0; i < bytes / 2; i++)
+ dest16[i] = grub_be_to_cpu16 (src16[i]);
+ return dest;
+ }
+
+ static void
+ grub_hdparm_print_identify (const char * idbuf)
+ {
+ const grub_uint16_t * idw = (const grub_uint16_t *) idbuf;
+
+ /* Print identity strings. */
+ char tmp[40];
+ grub_printf ("Model: \"%.40s\"\n", le16_to_char (tmp, &idw[27], 40));
+ grub_printf ("Firmware: \"%.8s\"\n", le16_to_char (tmp, &idw[23], 8));
+ grub_printf ("Serial: \"%.20s\"\n", le16_to_char (tmp, &idw[10], 20));
+
+ /* Print AAM, APM and SMART settings. */
+ grub_uint16_t features1 = grub_le_to_cpu16 (idw[82]);
+ grub_uint16_t features2 = grub_le_to_cpu16 (idw[83]);
+ grub_uint16_t enabled1 = grub_le_to_cpu16 (idw[85]);
+ grub_uint16_t enabled2 = grub_le_to_cpu16 (idw[86]);
+
+ grub_printf ("Automatic Acoustic Management: ");
+ if (features2 & 0x0200)
+ {
+ if (enabled2 & 0x0200)
+ {
+ grub_uint16_t aam = grub_le_to_cpu16 (idw[94]);
+ grub_printf ("%u (128=quiet, ..., 254=fast, recommended=%u)\n",
+ aam & 0xff, (aam >> 8) & 0xff);
+ }
+ else
+ grub_printf ("disabled\n");
+ }
+ else
+ grub_printf ("not supported\n");
+
+ grub_printf ("Advanced Power Management: ");
+ if (features2 & 0x0008)
+ {
+ if (enabled2 & 0x0008)
+ grub_printf ("%u (1=low, ..., 254=high)\n",
+ grub_le_to_cpu16 (idw[91]) & 0xff);
+ else
+ grub_printf ("disabled\n");
+ }
+ else
+ grub_printf ("not supported\n");
+
+ grub_printf ("SMART Feature Set: ");
+ if (features1 & 0x0001)
+ grub_printf ("%sabled\n", (enabled1 & 0x0001 ? "en" : "dis"));
+ else
+ grub_printf ("not supported\n");
+
+ /* Print security settings. */
+ grub_uint16_t security = grub_le_to_cpu16 (idw[128]);
+
+ grub_printf ("ATA Security: ");
+ if (security & 0x0001)
+ grub_printf ("%s, %s, %s, %s\n",
+ (security & 0x0002 ? "ENABLED" : "disabled"),
+ (security & 0x0004 ? "**LOCKED**" : "not locked"),
+ (security & 0x0008 ? "frozen" : "NOT FROZEN"),
+ (security & 0x0010 ? "COUNT EXPIRED" : "count not expired"));
+ else
+ grub_printf ("not supported\n");
+ }
+
+ static void
+ grub_hdparm_print_standby_tout (int timeout)
+ {
+ if (timeout == 0)
+ grub_printf ("off");
+ else if (timeout <= 252 || timeout == 255)
+ {
+ int h = 0, m = 0 , s = 0;
+ if (timeout == 255)
+ {
+ m = 21;
+ s = 15;
+ }
+ else if (timeout == 252)
+ m = 21;
+ else if (timeout <= 240)
+ {
+ s = timeout * 5;
+ m = s / 60;
+ s %= 60;
+ }
+ else
+ {
+ m = (timeout - 240) * 30;
+ h = m / 60;
+ m %= 60;
+ }
+ grub_printf ("%02d:%02d:%02d", h, m, s);
+ }
+ else
+ grub_printf ("invalid or vendor-specific");
+ }
+
+ static int get_int_arg (const struct grub_arg_list *state)
+ {
+ return (state->set ? (int)grub_strtoul (state->arg, 0, 0) : -1);
+ }
+
+ static grub_err_t
+ grub_cmd_hdparm (grub_extcmd_context_t ctxt, int argc, char **args) // state????
+ {
+ struct grub_arg_list *state = ctxt->state;
++ struct grub_ata *ata;
+
+ /* Check command line. */
+ if (argc != 1)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "missing device name argument");
+
+ grub_size_t len = grub_strlen (args[0]);
+ if (! (args[0][0] == '(' && args[0][len - 1] == ')'))
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "argument is not a device name");
+ args[0][len - 1] = 0;
+
- disk, GRUB_ATA_CMD_SET_FEATURES, (aam ? 0x42 : 0xc2), aam);
+ int i = 0;
+ int apm = get_int_arg (&state[i++]);
+ int power = state[i++].set;
+ int sec_freeze = state[i++].set;
+ int health = state[i++].set;
+ int aam = get_int_arg (&state[i++]);
+ int standby_tout = get_int_arg (&state[i++]);
+ int standby_now = state[i++].set;
+ int sleep_now = state[i++].set;
+ int ident = state[i++].set;
+ int dumpid = state[i++].set;
+ int enable_smart = get_int_arg (&state[i++]);
+ quiet = state[i++].set;
+
+ /* Open disk. */
+ grub_disk_t disk = grub_disk_open (&args[0][1]);
+ if (! disk)
+ return grub_errno;
+
+ if (disk->partition)
+ {
+ grub_disk_close (disk);
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "partition not allowed");
+ }
+
++ switch (disk->dev->id)
++ {
++ case GRUB_DISK_DEVICE_ATA_ID:
++ ata = disk->data;
++ break;
++ case GRUB_DISK_DEVICE_SCSI_ID:
++ if (((disk->id >> GRUB_SCSI_ID_SUBSYSTEM_SHIFT) & 0xFF)
++ == GRUB_SCSI_SUBSYSTEM_PATA
++ || (((disk->id >> GRUB_SCSI_ID_SUBSYSTEM_SHIFT) & 0xFF)
++ == GRUB_SCSI_SUBSYSTEM_AHCI))
++ {
++ ata = ((struct grub_scsi *) disk->data)->data;
++ break;
++ }
++ default:
++ return grub_error (GRUB_ERR_IO, "not an ATA device");
++ }
++
++
+ /* Change settings. */
+ if (aam >= 0)
+ grub_hdparm_set_val_cmd ("Automatic Acoustic Management", (aam ? aam : -1),
- (apm != 255 ? apm : -1), disk, GRUB_ATA_CMD_SET_FEATURES,
- (apm != 255 ? 0x05 : 0x85), (apm != 255 ? apm : 0));
++ ata, GRUB_ATA_CMD_SET_FEATURES,
++ (aam ? 0x42 : 0xc2), aam);
+
+ if (apm >= 0)
+ grub_hdparm_set_val_cmd ("Advanced Power Management",
- grub_hdparm_set_val_cmd ("", -1, disk, GRUB_ATA_CMD_IDLE, 0, standby_tout);
++ (apm != 255 ? apm : -1), ata,
++ GRUB_ATA_CMD_SET_FEATURES,
++ (apm != 255 ? 0x05 : 0x85),
++ (apm != 255 ? apm : 0));
+
+ if (standby_tout >= 0)
+ {
+ if (! quiet)
+ {
+ grub_printf ("Set standby timeout to %d (", standby_tout);
+ grub_hdparm_print_standby_tout (standby_tout);
+ grub_printf (")");
+ }
+ /* The IDLE cmd sets disk to idle mode and configures standby timer. */
- int err = grub_hdparm_do_smart_cmd (disk, (enable_smart ?
++ grub_hdparm_set_val_cmd ("", -1, ata, GRUB_ATA_CMD_IDLE, 0, standby_tout);
+ }
+
+ if (enable_smart >= 0)
+ {
+ if (! quiet)
+ grub_printf ("%sable SMART operations", (enable_smart ? "En" : "Dis"));
- grub_hdparm_simple_cmd ("Freeze security settings", disk,
++ int err = grub_hdparm_do_smart_cmd (ata, (enable_smart ?
+ GRUB_ATA_FEAT_SMART_ENABLE : GRUB_ATA_FEAT_SMART_DISABLE));
+ if (! quiet)
+ grub_printf ("%s\n", err ? ": not supported" : "");
+ }
+
+ if (sec_freeze)
- if (grub_hdparm_do_ata_cmd (disk, GRUB_ATA_CMD_IDENTIFY_DEVICE,
++ grub_hdparm_simple_cmd ("Freeze security settings", ata,
+ GRUB_ATA_CMD_SECURITY_FREEZE_LOCK);
+
+ /* Print/dump IDENTIFY. */
+ if (ident || dumpid)
+ {
+ char buf[GRUB_DISK_SECTOR_SIZE];
- int mode = grub_hdparm_do_check_powermode_cmd (disk);
++ if (grub_hdparm_do_ata_cmd (ata, GRUB_ATA_CMD_IDENTIFY_DEVICE,
+ 0, 0, buf, sizeof (buf)))
+ grub_printf ("Cannot read ATA IDENTIFY data\n");
+ else
+ {
+ if (ident)
+ grub_hdparm_print_identify (buf);
+ if (dumpid)
+ hexdump (0, buf, sizeof (buf));
+ }
+ }
+
+ /* Check power mode. */
+ if (power)
+ {
+ grub_printf ("Disk power mode is: ");
- int err = grub_hdparm_do_smart_cmd (disk, GRUB_ATA_FEAT_SMART_STATUS);
++ int mode = grub_hdparm_do_check_powermode_cmd (ata);
+ if (mode < 0)
+ grub_printf ("unknown\n");
+ else
+ grub_printf ("%s (0x%02x)\n",
+ (mode == 0xff ? "active/idle" :
+ mode == 0x80 ? "idle" :
+ mode == 0x00 ? "standby" : "unknown"), mode);
+ }
+
+ /* Check health. */
+ int status = 0;
+ if (health)
+ {
+ if (! quiet)
+ grub_printf ("SMART status is: ");
- grub_hdparm_simple_cmd ("Set disk to standby mode", disk,
++ int err = grub_hdparm_do_smart_cmd (ata, GRUB_ATA_FEAT_SMART_STATUS);
+ if (! quiet)
+ grub_printf ("%s\n", (err < 0 ? "unknown" :
+ err == 0 ? "OK" : "*BAD*"));
+ status = (err > 0);
+ }
+
+ /* Change power mode. */
+ if (standby_now)
- grub_hdparm_simple_cmd ("Set disk to sleep mode", disk,
++ grub_hdparm_simple_cmd ("Set disk to standby mode", ata,
+ GRUB_ATA_CMD_STANDBY_IMMEDIATE);
+
+ if (sleep_now)
++ grub_hdparm_simple_cmd ("Set disk to sleep mode", ata,
+ GRUB_ATA_CMD_SLEEP);
+
+ grub_disk_close (disk);
+
+ grub_errno = GRUB_ERR_NONE;
+ return status;
+ }
+
+ static grub_extcmd_t cmd;
+
+ GRUB_MOD_INIT(hdparm)
+ {
+ cmd = grub_register_extcmd ("hdparm", grub_cmd_hdparm, 0,
+ N_("[OPTIONS] DISK"),
+ N_("Get/set ATA disk parameters."), options);
+ }
+
+ GRUB_MOD_FINI(hdparm)
+ {
+ grub_unregister_extcmd (cmd);
+ }
--- /dev/null
-#include <grub/time.h>
-#include <grub/pci.h>
+ /* ata.c - ATA disk access. */
+ /*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2007, 2008, 2009 Free Software Foundation, Inc.
+ *
+ * GRUB 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB 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 GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+ #include <grub/ata.h>
+ #include <grub/dl.h>
+ #include <grub/disk.h>
+ #include <grub/mm.h>
-#include <grub/cs5536.h>
+ #include <grub/scsi.h>
-/* At the moment, only two IDE ports are supported. */
-static const grub_port_t grub_ata_ioaddress[] = { GRUB_ATA_CH0_PORT1,
- GRUB_ATA_CH1_PORT1 };
-static const grub_port_t grub_ata_ioaddress2[] = { GRUB_ATA_CH0_PORT2,
- GRUB_ATA_CH1_PORT2 };
-
-static struct grub_ata_device *grub_ata_devices;
-
-/* Wait for !BSY. */
-grub_err_t
-grub_ata_wait_not_busy (struct grub_ata_device *dev, int milliseconds)
-{
- /* ATA requires 400ns (after a write to CMD register) or
- 1 PIO cycle (after a DRQ block transfer) before
- first check of BSY. */
- grub_millisleep (1);
-
- int i = 1;
- grub_uint8_t sts;
- while ((sts = grub_ata_regget (dev, GRUB_ATA_REG_STATUS))
- & GRUB_ATA_STATUS_BUSY)
- {
- if (i >= milliseconds)
- {
- grub_dprintf ("ata", "timeout: %dms, status=0x%x\n",
- milliseconds, sts);
- return grub_error (GRUB_ERR_TIMEOUT, "ATA timeout");
- }
-
- grub_millisleep (1);
- i++;
- }
-
- return GRUB_ERR_NONE;
-}
-
-static inline void
-grub_ata_wait (void)
-{
- grub_millisleep (50);
-}
-
-/* Wait for !BSY, DRQ. */
-grub_err_t
-grub_ata_wait_drq (struct grub_ata_device *dev, int rw,
- int milliseconds)
-{
- if (grub_ata_wait_not_busy (dev, milliseconds))
- return grub_errno;
-
- /* !DRQ implies error condition. */
- grub_uint8_t sts = grub_ata_regget (dev, GRUB_ATA_REG_STATUS);
- if ((sts & (GRUB_ATA_STATUS_DRQ | GRUB_ATA_STATUS_ERR))
- != GRUB_ATA_STATUS_DRQ)
- {
- grub_dprintf ("ata", "ata error: status=0x%x, error=0x%x\n",
- sts, grub_ata_regget (dev, GRUB_ATA_REG_ERROR));
- if (! rw)
- return grub_error (GRUB_ERR_READ_ERROR, "ATA read error");
- else
- return grub_error (GRUB_ERR_WRITE_ERROR, "ATA write error");
- }
-
- return GRUB_ERR_NONE;
-}
+
-void
-grub_ata_pio_read (struct grub_ata_device *dev, char *buf, grub_size_t size)
-{
- grub_uint16_t *buf16 = (grub_uint16_t *) buf;
- unsigned int i;
-
- /* Read in the data, word by word. */
- for (i = 0; i < size / 2; i++)
- buf16[i] = grub_le_to_cpu16 (grub_inw(dev->ioaddress + GRUB_ATA_REG_DATA));
-}
-
-static void
-grub_ata_pio_write (struct grub_ata_device *dev, char *buf, grub_size_t size)
-{
- grub_uint16_t *buf16 = (grub_uint16_t *) buf;
- unsigned int i;
-
- /* Write the data, word by word. */
- for (i = 0; i < size / 2; i++)
- grub_outw(grub_cpu_to_le16 (buf16[i]), dev->ioaddress + GRUB_ATA_REG_DATA);
-}
-
++static grub_ata_dev_t grub_ata_dev_list;
+
+ /* Byteorder has to be changed before strings can be read. */
+ static void
+ grub_ata_strncpy (char *dst, char *src, grub_size_t len)
+ {
+ grub_uint16_t *src16 = (grub_uint16_t *) src;
+ grub_uint16_t *dst16 = (grub_uint16_t *) dst;
+ unsigned int i;
+
+ for (i = 0; i < len / 2; i++)
+ *(dst16++) = grub_be_to_cpu16 (*(src16++));
+ dst[len] = '\0';
+ }
+
-grub_ata_dumpinfo (struct grub_ata_device *dev, char *info)
+ static void
-grub_atapi_identify (struct grub_ata_device *dev)
++grub_ata_dumpinfo (struct grub_ata *dev, char *info)
+ {
+ char text[41];
+
+ /* The device information was read, dump it for debugging. */
+ grub_ata_strncpy (text, info + 20, 20);
+ grub_dprintf ("ata", "Serial: %s\n", text);
+ grub_ata_strncpy (text, info + 46, 8);
+ grub_dprintf ("ata", "Firmware: %s\n", text);
+ grub_ata_strncpy (text, info + 54, 40);
+ grub_dprintf ("ata", "Model: %s\n", text);
+
+ if (! dev->atapi)
+ {
+ grub_dprintf ("ata", "Addressing: %d\n", dev->addr);
+ grub_dprintf ("ata", "Sectors: %lld\n", (unsigned long long) dev->size);
+ }
+ }
+
+ static grub_err_t
- grub_ata_regset (dev, GRUB_ATA_REG_DISK, 0xE0 | dev->device << 4);
- grub_ata_wait ();
- if (grub_ata_check_ready (dev))
- {
- grub_free (info);
- return grub_errno;
- }
++grub_atapi_identify (struct grub_ata *dev)
+ {
++ struct grub_disk_ata_pass_through_parms parms;
+ char *info;
++ grub_err_t err;
+
+ info = grub_malloc (GRUB_DISK_SECTOR_SIZE);
+ if (! info)
+ return grub_errno;
+
- grub_ata_regset (dev, GRUB_ATA_REG_CMD, GRUB_ATA_CMD_IDENTIFY_PACKET_DEVICE);
- grub_ata_wait ();
++ grub_memset (&parms, 0, sizeof (parms));
++ parms.taskfile.disk = 0;
++ parms.taskfile.cmd = GRUB_ATA_CMD_IDENTIFY_PACKET_DEVICE;
+
- if (grub_ata_wait_drq (dev, 0, GRUB_ATA_TOUT_STD))
- {
- grub_free (info);
- return grub_errno;
- }
- grub_ata_pio_read (dev, info, GRUB_DISK_SECTOR_SIZE);
++ err = dev->dev->readwrite (dev, &parms);
++ if (err)
++ return err;
+
-grub_atapi_wait_drq (struct grub_ata_device *dev,
- grub_uint8_t ireason,
- int milliseconds)
-{
- /* Wait for !BSY, DRQ, ireason */
- if (grub_ata_wait_not_busy (dev, milliseconds))
- return grub_errno;
-
- grub_uint8_t sts = grub_ata_regget (dev, GRUB_ATA_REG_STATUS);
- grub_uint8_t irs = grub_ata_regget (dev, GRUB_ATAPI_REG_IREASON);
-
- /* OK if DRQ is asserted and interrupt reason is as expected. */
- if ((sts & GRUB_ATA_STATUS_DRQ)
- && (irs & GRUB_ATAPI_IREASON_MASK) == ireason)
- return GRUB_ERR_NONE;
-
- /* !DRQ implies error condition. */
- grub_dprintf ("ata", "atapi error: status=0x%x, ireason=0x%x, error=0x%x\n",
- sts, irs, grub_ata_regget (dev, GRUB_ATA_REG_ERROR));
-
- if (! (sts & GRUB_ATA_STATUS_DRQ)
- && (irs & GRUB_ATAPI_IREASON_MASK) == GRUB_ATAPI_IREASON_ERROR)
- {
- if (ireason == GRUB_ATAPI_IREASON_CMD_OUT)
- return grub_error (GRUB_ERR_READ_ERROR, "ATA PACKET command error");
- else
- return grub_error (GRUB_ERR_READ_ERROR, "ATAPI read error");
- }
-
- return grub_error (GRUB_ERR_READ_ERROR, "ATAPI protocol error");
-}
-
-static grub_err_t
-grub_atapi_packet (struct grub_ata_device *dev, char *packet,
- grub_size_t size)
-{
- grub_ata_regset (dev, GRUB_ATA_REG_DISK, dev->device << 4);
- if (grub_ata_check_ready (dev))
- return grub_errno;
-
- /* Send ATA PACKET command. */
- grub_ata_regset (dev, GRUB_ATA_REG_FEATURES, 0);
- grub_ata_regset (dev, GRUB_ATAPI_REG_IREASON, 0);
- grub_ata_regset (dev, GRUB_ATAPI_REG_CNTHIGH, size >> 8);
- grub_ata_regset (dev, GRUB_ATAPI_REG_CNTLOW, size & 0xFF);
-
- grub_ata_regset (dev, GRUB_ATA_REG_CMD, GRUB_ATA_CMD_PACKET);
-
- /* Wait for !BSY, DRQ, !I/O, C/D. */
- if (grub_atapi_wait_drq (dev, GRUB_ATAPI_IREASON_CMD_OUT, GRUB_ATA_TOUT_STD))
- return grub_errno;
-
- /* Write the packet. */
- grub_ata_pio_write (dev, packet, 12);
-
- return GRUB_ERR_NONE;
-}
-
-static grub_err_t
-grub_ata_identify (struct grub_ata_device *dev)
++ if (parms.size != GRUB_DISK_SECTOR_SIZE)
++ return grub_error (GRUB_ERR_UNKNOWN_DEVICE,
++ "device cannot be identified");
+
+ dev->atapi = 1;
+
+ grub_ata_dumpinfo (dev, info);
+
+ grub_free (info);
+
+ return GRUB_ERR_NONE;
+ }
+
+ static grub_err_t
- grub_ata_regset (dev, GRUB_ATA_REG_DISK, 0xE0 | dev->device << 4);
- grub_ata_wait ();
- if (grub_ata_check_ready (dev))
- {
- grub_free (info);
- return grub_errno;
- }
++grub_ata_identify (struct grub_ata *dev)
+ {
++ struct grub_disk_ata_pass_through_parms parms;
+ char *info;
+ grub_uint16_t *info16;
++ grub_err_t err;
+
+ info = grub_malloc (GRUB_DISK_SECTOR_SIZE);
+ if (! info)
+ return grub_errno;
+
+ info16 = (grub_uint16_t *) info;
++ grub_memset (&parms, 0, sizeof (parms));
++ parms.buffer = info;
++ parms.taskfile.disk = 0;
+
- grub_ata_regset (dev, GRUB_ATA_REG_CMD, GRUB_ATA_CMD_IDENTIFY_DEVICE);
- grub_ata_wait ();
++ parms.taskfile.cmd = GRUB_ATA_CMD_IDENTIFY_DEVICE;
+
- if (grub_ata_wait_drq (dev, 0, GRUB_ATA_TOUT_STD))
++ err = dev->dev->readwrite (dev, &parms);
++ if (err)
++ return err;
+
- grub_errno = GRUB_ERR_NONE;
- grub_uint8_t sts = grub_ata_regget (dev, GRUB_ATA_REG_STATUS);
-
++ if (parms.size != GRUB_DISK_SECTOR_SIZE)
+ {
++ grub_uint8_t sts = parms.taskfile.status;
+ grub_free (info);
- && (grub_ata_regget (dev, GRUB_ATA_REG_ERROR) & 0x04 /* ABRT */))
+ if ((sts & (GRUB_ATA_STATUS_BUSY | GRUB_ATA_STATUS_DRQ
+ | GRUB_ATA_STATUS_ERR)) == GRUB_ATA_STATUS_ERR
- grub_ata_pio_read (dev, info, GRUB_DISK_SECTOR_SIZE);
-
- /* Re-check status to avoid bogus identify data due to stuck DRQ. */
- grub_uint8_t sts = grub_ata_regget (dev, GRUB_ATA_REG_STATUS);
- if (sts & (GRUB_ATA_STATUS_BUSY | GRUB_ATA_STATUS_DRQ | GRUB_ATA_STATUS_ERR))
- {
- grub_dprintf ("ata", "bad status=0x%x\n", sts);
- grub_free (info);
- /* No device, return error but don't print message. */
- grub_errno = GRUB_ERR_NONE;
- return GRUB_ERR_UNKNOWN_DEVICE;
- }
-
++ && (parms.taskfile.error & 0x04 /* ABRT */))
+ /* Device without ATA IDENTIFY, try ATAPI. */
+ return grub_atapi_identify (dev);
+
+ else if (sts == 0x00)
+ /* No device, return error but don't print message. */
+ return GRUB_ERR_UNKNOWN_DEVICE;
+
+ else
+ /* Other Error. */
+ return grub_error (GRUB_ERR_UNKNOWN_DEVICE,
+ "device cannot be identified");
+ }
+
-check_device (struct grub_ata_device *dev)
-{
- grub_ata_regset (dev, GRUB_ATA_REG_DISK, dev->device << 4);
- grub_ata_wait ();
-
- /* Try to detect if the port is in use by writing to it,
- waiting for a while and reading it again. If the value
- was preserved, there is a device connected. */
- grub_ata_regset (dev, GRUB_ATA_REG_SECTORS, 0x5A);
- grub_ata_wait ();
- grub_uint8_t sec = grub_ata_regget (dev, GRUB_ATA_REG_SECTORS);
- grub_dprintf ("ata", "sectors=0x%x\n", sec);
- if (sec != 0x5A)
- return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no device connected");
-
- /* The above test may detect a second (slave) device
- connected to a SATA controller which supports only one
- (master) device. It is not safe to use the status register
- READY bit to check for controller channel existence. Some
- ATAPI commands (RESET, DIAGNOSTIC) may clear this bit. */
-
- /* Use the IDENTIFY DEVICE command to query the device. */
- return grub_ata_identify (dev);
-}
-
-static grub_err_t
-grub_ata_device_initialize (int port, int device, int addr, int addr2)
-{
- struct grub_ata_device *dev;
- struct grub_ata_device **devp;
- grub_err_t err;
-
- grub_dprintf ("ata", "detecting device %d,%d (0x%x, 0x%x)\n",
- port, device, addr, addr2);
-
- dev = grub_malloc (sizeof(*dev));
- if (! dev)
- return grub_errno;
-
- /* Setup the device information. */
- dev->port = port;
- dev->device = device;
- dev->ioaddress = addr + GRUB_MACHINE_PCI_IO_BASE;
- dev->ioaddress2 = addr2 + GRUB_MACHINE_PCI_IO_BASE;
- dev->next = NULL;
-
- /* Register the device. */
- for (devp = &grub_ata_devices; *devp; devp = &(*devp)->next);
- *devp = dev;
-
- err = check_device (dev);
- if (err)
- grub_print_error ();
-
- return 0;
-}
-
-static int NESTED_FUNC_ATTR
-grub_ata_pciinit (grub_pci_device_t dev,
- grub_pci_id_t pciid)
-{
- static int compat_use[2] = { 0 };
- grub_pci_address_t addr;
- grub_uint32_t class;
- grub_uint32_t bar1;
- grub_uint32_t bar2;
- int rega;
- int regb;
- int i;
- static int controller = 0;
- int cs5536 = 0;
- int nports = 2;
-
- /* Read class. */
- addr = grub_pci_make_address (dev, GRUB_PCI_REG_CLASS);
- class = grub_pci_read (addr);
-
- /* AMD CS5536 Southbridge. */
- if (pciid == GRUB_CS5536_PCIID)
- {
- cs5536 = 1;
- nports = 1;
- }
-
- /* Check if this class ID matches that of a PCI IDE Controller. */
- if (!cs5536 && (class >> 16 != 0x0101))
- return 0;
-
- for (i = 0; i < nports; i++)
- {
- /* Set to 0 when the channel operated in compatibility mode. */
- int compat;
-
- /* We don't support non-compatibility mode for CS5536. */
- if (cs5536)
- compat = 0;
- else
- compat = (class >> (8 + 2 * i)) & 1;
-
- rega = 0;
- regb = 0;
-
- /* If the channel is in compatibility mode, just assign the
- default registers. */
- if (compat == 0 && !compat_use[i])
- {
- rega = grub_ata_ioaddress[i];
- regb = grub_ata_ioaddress2[i];
- compat_use[i] = 1;
- }
- else if (compat)
- {
- /* Read the BARs, which either contain a mmapped IO address
- or the IO port address. */
- addr = grub_pci_make_address (dev, GRUB_PCI_REG_ADDRESSES
- + sizeof (grub_uint64_t) * i);
- bar1 = grub_pci_read (addr);
- addr = grub_pci_make_address (dev, GRUB_PCI_REG_ADDRESSES
- + sizeof (grub_uint64_t) * i
- + sizeof (grub_uint32_t));
- bar2 = grub_pci_read (addr);
-
- /* Check if the BARs describe an IO region. */
- if ((bar1 & 1) && (bar2 & 1))
- {
- rega = bar1 & ~3;
- regb = bar2 & ~3;
- }
- }
-
- grub_dprintf ("ata",
- "PCI dev (%d,%d,%d) compat=%d rega=0x%x regb=0x%x\n",
- grub_pci_get_bus (dev), grub_pci_get_device (dev),
- grub_pci_get_function (dev), compat, rega, regb);
-
- if (rega && regb)
- {
- grub_errno = GRUB_ERR_NONE;
- grub_ata_device_initialize (controller * 2 + i, 0, rega, regb);
-
- /* Most errors raised by grub_ata_device_initialize() are harmless.
- They just indicate this particular drive is not responding, most
- likely because it doesn't exist. We might want to ignore specific
- error types here, instead of printing them. */
- if (grub_errno)
- {
- grub_print_error ();
- grub_errno = GRUB_ERR_NONE;
- }
-
- grub_ata_device_initialize (controller * 2 + i, 1, rega, regb);
-
- /* Likewise. */
- if (grub_errno)
- {
- grub_print_error ();
- grub_errno = GRUB_ERR_NONE;
- }
- }
- }
-
- controller++;
-
- return 0;
-}
-
-static grub_err_t
-grub_ata_initialize (void)
-{
- grub_pci_iterate (grub_ata_pciinit);
- return 0;
-}
-
-static void
-grub_ata_setlba (struct grub_ata_device *dev, grub_disk_addr_t sector,
- grub_size_t size)
-{
- grub_ata_regset (dev, GRUB_ATA_REG_SECTORS, size);
- grub_ata_regset (dev, GRUB_ATA_REG_LBALOW, sector & 0xFF);
- grub_ata_regset (dev, GRUB_ATA_REG_LBAMID, (sector >> 8) & 0xFF);
- grub_ata_regset (dev, GRUB_ATA_REG_LBAHIGH, (sector >> 16) & 0xFF);
-}
-
-static grub_err_t
-grub_ata_setaddress (struct grub_ata_device *dev,
- grub_ata_addressing_t addressing,
+ /* Now it is certain that this is not an ATAPI device. */
+ dev->atapi = 0;
+
+ /* CHS is always supported. */
+ dev->addr = GRUB_ATA_CHS;
+
+ /* Check if LBA is supported. */
+ if (info16[49] & (1 << 9))
+ {
+ /* Check if LBA48 is supported. */
+ if (info16[83] & (1 << 10))
+ dev->addr = GRUB_ATA_LBA48;
+ else
+ dev->addr = GRUB_ATA_LBA;
+ }
+
+ /* Determine the amount of sectors. */
+ if (dev->addr != GRUB_ATA_LBA48)
+ dev->size = grub_le_to_cpu32(*((grub_uint32_t *) &info16[60]));
+ else
+ dev->size = grub_le_to_cpu64(*((grub_uint64_t *) &info16[100]));
+
+ /* Read CHS information. */
+ dev->cylinders = info16[1];
+ dev->heads = info16[3];
+ dev->sectors_per_track = info16[6];
+
+ grub_ata_dumpinfo (dev, info);
+
+ grub_free(info);
+
+ return 0;
+ }
+
+ static grub_err_t
- switch (addressing)
++grub_ata_setaddress (struct grub_ata *dev,
++ struct grub_disk_ata_pass_through_parms *parms,
+ grub_disk_addr_t sector,
+ grub_size_t size)
+ {
-
- grub_ata_regset (dev, GRUB_ATA_REG_DISK, (dev->device << 4) | head);
- if (grub_ata_check_ready (dev))
- return grub_errno;
-
- grub_ata_regset (dev, GRUB_ATA_REG_SECTNUM, sect);
- grub_ata_regset (dev, GRUB_ATA_REG_CYLLSB, cylinder & 0xFF);
- grub_ata_regset (dev, GRUB_ATA_REG_CYLMSB, cylinder >> 8);
++ switch (dev->addr)
+ {
+ case GRUB_ATA_CHS:
+ {
+ unsigned int cylinder;
+ unsigned int head;
+ unsigned int sect;
+
+ /* Calculate the sector, cylinder and head to use. */
+ sect = ((grub_uint32_t) sector % dev->sectors_per_track) + 1;
+ cylinder = (((grub_uint32_t) sector / dev->sectors_per_track)
+ / dev->heads);
+ head = ((grub_uint32_t) sector / dev->sectors_per_track) % dev->heads;
+
+ if (sect > dev->sectors_per_track
+ || cylinder > dev->cylinders
+ || head > dev->heads)
+ return grub_error (GRUB_ERR_OUT_OF_RANGE,
+ "sector %d cannot be addressed "
+ "using CHS addressing", sector);
- grub_ata_regset (dev, GRUB_ATA_REG_DISK,
- 0xE0 | (dev->device << 4) | ((sector >> 24) & 0x0F));
- if (grub_ata_check_ready (dev))
- return grub_errno;
++
++ parms->taskfile.disk = head;
++ parms->taskfile.sectnum = sect;
++ parms->taskfile.cyllsb = cylinder & 0xFF;
++ parms->taskfile.cylmsb = cylinder >> 8;
+
+ break;
+ }
+
+ case GRUB_ATA_LBA:
+ if (size == 256)
+ size = 0;
- grub_ata_setlba (dev, sector, size);
++ parms->taskfile.disk = ((sector >> 24) & 0x0F);
+
- grub_ata_regset (dev, GRUB_ATA_REG_DISK, 0xE0 | (dev->device << 4));
- if (grub_ata_check_ready (dev))
- return grub_errno;
++ parms->taskfile.sectors = size;
++ parms->taskfile.lba_low = sector & 0xFF;
++ parms->taskfile.lba_mid = (sector >> 8) & 0xFF;
++ parms->taskfile.lba_high = (sector >> 16) & 0xFF;
+ break;
+
+ case GRUB_ATA_LBA48:
+ if (size == 65536)
+ size = 0;
+
- grub_ata_setlba (dev, sector >> 24, size >> 8);
++ parms->taskfile.disk = 0;
+
+ /* Set "Previous". */
- grub_ata_setlba (dev, sector, size);
++ parms->taskfile.sectors = size & 0xFF;
++ parms->taskfile.lba_low = sector & 0xFF;
++ parms->taskfile.lba_mid = (sector >> 8) & 0xFF;
++ parms->taskfile.lba_high = (sector >> 16) & 0xFF;
++
+ /* Set "Current". */
- struct grub_ata_device *dev = (struct grub_ata_device *) disk->data;
-
- grub_dprintf("ata", "grub_ata_readwrite (size=%llu, rw=%d)\n", (unsigned long long) size, rw);
++ parms->taskfile.sectors48 = (size >> 8) & 0xFF;
++ parms->taskfile.lba48_low = (sector >> 24) & 0xFF;
++ parms->taskfile.lba48_mid = (sector >> 32) & 0xFF;
++ parms->taskfile.lba48_high = (sector >> 40) & 0xFF;
+
+ break;
+ }
+
+ return GRUB_ERR_NONE;
+ }
+
+ static grub_err_t
+ grub_ata_readwrite (grub_disk_t disk, grub_disk_addr_t sector,
+ grub_size_t size, char *buf, int rw)
+ {
- grub_ata_addressing_t addressing = dev->addr;
++ struct grub_ata *ata = disk->data;
+
- batch = 256;
++ grub_ata_addressing_t addressing = ata->addr;
+ grub_size_t batch;
+ int cmd, cmd_write;
+
++ grub_dprintf("ata", "grub_ata_readwrite (size=%llu, rw=%d)\n",
++ (unsigned long long) size, rw);
++
+ if (addressing == GRUB_ATA_LBA48 && ((sector + size) >> 28) != 0)
+ {
+ batch = 65536;
+ cmd = GRUB_ATA_CMD_READ_SECTORS_EXT;
+ cmd_write = GRUB_ATA_CMD_WRITE_SECTORS_EXT;
+ }
+ else
+ {
+ if (addressing == GRUB_ATA_LBA48)
+ addressing = GRUB_ATA_LBA;
-
- /* Send read/write command. */
- if (grub_ata_setaddress (dev, addressing, sector, batch))
- return grub_errno;
-
- grub_ata_regset (dev, GRUB_ATA_REG_CMD, (! rw ? cmd : cmd_write));
-
- unsigned sect;
- for (sect = 0; sect < batch; sect++)
- {
- /* Wait for !BSY, DRQ. */
- if (grub_ata_wait_drq (dev, rw, GRUB_ATA_TOUT_DATA))
- return grub_errno;
-
- /* Transfer data. */
- if (! rw)
- grub_ata_pio_read (dev, buf, GRUB_DISK_SECTOR_SIZE);
- else
- grub_ata_pio_write (dev, buf, GRUB_DISK_SECTOR_SIZE);
-
- buf += GRUB_DISK_SECTOR_SIZE;
- }
-
- if (rw)
- {
- /* Check for write error. */
- if (grub_ata_wait_not_busy (dev, GRUB_ATA_TOUT_DATA))
- return grub_errno;
-
- if (grub_ata_regget (dev, GRUB_ATA_REG_STATUS)
- & (GRUB_ATA_STATUS_DRQ | GRUB_ATA_STATUS_ERR))
- return grub_error (GRUB_ERR_WRITE_ERROR, "ATA write error");
- }
-
++ if (addressing != GRUB_ATA_CHS)
++ batch = 256;
++ else
++ batch = 1;
+ cmd = GRUB_ATA_CMD_READ_SECTORS;
+ cmd_write = GRUB_ATA_CMD_WRITE_SECTORS;
+ }
+
+ grub_size_t nsectors = 0;
+ while (nsectors < size)
+ {
++ struct grub_disk_ata_pass_through_parms parms;
++ grub_err_t err;
++
+ if (size - nsectors < batch)
+ batch = size - nsectors;
+
+ grub_dprintf("ata", "rw=%d, sector=%llu, batch=%llu\n", rw, (unsigned long long) sector, (unsigned long long) batch);
-static int
-grub_ata_iterate (int (*hook) (const char *name))
++ grub_memset (&parms, 0, sizeof (parms));
++ grub_ata_setaddress (ata, &parms, sector, batch);
++ parms.taskfile.cmd = (! rw ? cmd : cmd_write);
++ parms.buffer = buf;
++ parms.size = batch * GRUB_DISK_SECTOR_SIZE;
++
++ err = ata->dev->readwrite (ata, &parms);
++ if (err)
++ return err;
++ if (parms.size != batch * GRUB_DISK_SECTOR_SIZE)
++ return grub_error (GRUB_ERR_READ_ERROR, "incomplete read");
++ buf += GRUB_DISK_SECTOR_SIZE * batch;
+ sector += batch;
+ nsectors += batch;
+ }
+
+ return GRUB_ERR_NONE;
+ }
+
+ \f
+
- struct grub_ata_device *dev;
++static inline void
++grub_ata_real_close (struct grub_ata *ata)
+ {
- for (dev = grub_ata_devices; dev; dev = dev->next)
++ if (ata->dev->close)
++ ata->dev->close (ata);
++}
++
++static struct grub_ata *
++grub_ata_real_open (int id, int bus)
++{
++ struct grub_ata *ata;
++ grub_ata_dev_t p;
+
- char devname[10];
++ ata = grub_malloc (sizeof (*ata));
++ if (!ata)
++ return NULL;
++ for (p = grub_ata_dev_list; p; p = p->next)
+ {
-
- err = check_device (dev);
- if (err)
+ grub_err_t err;
- if (dev->atapi)
- continue;
-
- grub_snprintf (devname, sizeof (devname),
- "ata%d", dev->port * 2 + dev->device);
++ if (p->open (id, bus, ata))
+ {
+ grub_errno = GRUB_ERR_NONE;
+ continue;
+ }
++ ata->dev = p;
++ /* Use the IDENTIFY DEVICE command to query the device. */
++ err = grub_ata_identify (ata);
++ if (err)
++ {
++ grub_free (ata);
++ return NULL;
++ }
++ return ata;
++ }
++ grub_free (ata);
++ grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no such ATA device");
++ return NULL;
++}
+
- if (hook (devname))
- return 1;
- }
++static int
++grub_ata_iterate (int (*hook_in) (const char *name))
++{
++ auto int hook (int id, int bus);
++ int hook (int id, int bus)
++ {
++ struct grub_ata *ata;
++ int ret;
++ char devname[40];
+
- struct grub_ata_device *dev;
- grub_err_t err;
-
- for (dev = grub_ata_devices; dev; dev = dev->next)
- {
- char devname[10];
- grub_snprintf (devname, sizeof (devname),
- "ata%d", dev->port * 2 + dev->device);
- if (grub_strcmp (name, devname) == 0)
- break;
- }
-
- if (! dev)
- return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "can't open device");
++ ata = grub_ata_real_open (id, bus);
+
++ if (!ata)
++ {
++ grub_errno = GRUB_ERR_NONE;
++ return 0;
++ }
++ if (ata->atapi)
++ {
++ grub_ata_real_close (ata);
++ return 0;
++ }
++ grub_snprintf (devname, sizeof (devname),
++ "%s%d", grub_scsi_names[id], bus);
++ ret = hook_in (devname);
++ grub_ata_real_close (ata);
++ return ret;
++ }
++
++ grub_ata_dev_t p;
++
++ for (p = grub_ata_dev_list; p; p = p->next)
++ if (p->iterate && p->iterate (hook))
++ return 1;
+ return 0;
+ }
+
+ static grub_err_t
+ grub_ata_open (const char *name, grub_disk_t disk)
+ {
- if (dev->atapi)
++ unsigned id, bus;
++ struct grub_ata *ata;
+
- err = check_device (dev);
-
- if (err)
- return err;
++ for (id = 0; id < GRUB_SCSI_NUM_SUBSYSTEMS; id++)
++ if (grub_strncmp (grub_scsi_names[id], name,
++ grub_strlen (grub_scsi_names[id])) == 0
++ && grub_isdigit (name[grub_strlen (grub_scsi_names[id])]))
++ break;
++ if (id == GRUB_SCSI_NUM_SUBSYSTEMS)
+ return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not an ATA harddisk");
++ bus = grub_strtoul (name + grub_strlen (grub_scsi_names[id]), 0, 0);
++ ata = grub_ata_real_open (id, bus);
++ if (!ata)
++ return grub_errno;
+
- disk->total_sectors = dev->size;
++ if (ata->atapi)
++ return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not an ATA harddisk");
+
- disk->id = (unsigned long) dev;
++ disk->total_sectors = ata->size;
+
- disk->data = dev;
++ disk->id = grub_make_scsi_id (id, bus, 0);
+
-grub_ata_close (grub_disk_t disk __attribute__((unused)))
++ disk->data = ata;
+
+ return 0;
+ }
+
+ static void
-
++grub_ata_close (grub_disk_t disk)
+ {
-static int
-grub_atapi_iterate (int (*hook) (int bus, int luns))
-{
- struct grub_ata_device *dev;
-
- for (dev = grub_ata_devices; dev; dev = dev->next)
- {
- grub_err_t err;
-
- err = check_device (dev);
- if (err)
- {
- grub_errno = GRUB_ERR_NONE;
- continue;
- }
-
- if (! dev->atapi)
- continue;
-
- if (hook (dev->port * 2 + dev->device, 1))
- return 1;
- }
-
- return 0;
-
-}
-
++ struct grub_ata *ata = disk->data;
++ grub_ata_real_close (ata);
+ }
+
+ static grub_err_t
+ grub_ata_read (grub_disk_t disk, grub_disk_addr_t sector,
+ grub_size_t size, char *buf)
+ {
+ return grub_ata_readwrite (disk, sector, size, buf, 0);
+ }
+
+ static grub_err_t
+ grub_ata_write (grub_disk_t disk,
+ grub_disk_addr_t sector,
+ grub_size_t size,
+ const char *buf)
+ {
+ return grub_ata_readwrite (disk, sector, size, (char *) buf, 1);
+ }
+
+ static struct grub_disk_dev grub_atadisk_dev =
+ {
+ .name = "ATA",
+ .id = GRUB_DISK_DEVICE_ATA_ID,
+ .iterate = grub_ata_iterate,
+ .open = grub_ata_open,
+ .close = grub_ata_close,
+ .read = grub_ata_read,
+ .write = grub_ata_write,
+ .next = 0
+ };
+
+
+ \f
+ /* ATAPI code. */
+
-grub_atapi_read (struct grub_scsi *scsi,
- grub_size_t cmdsize __attribute__((unused)),
- char *cmd, grub_size_t size, char *buf)
+ static grub_err_t
- struct grub_ata_device *dev = (struct grub_ata_device *) scsi->data;
++grub_atapi_read (struct grub_scsi *scsi, grub_size_t cmdsize, char *cmd,
++ grub_size_t size, char *buf)
+ {
- if (grub_atapi_packet (dev, cmd, size))
- return grub_errno;
-
- grub_size_t nread = 0;
- while (nread < size)
- {
- /* Wait for !BSY, DRQ, I/O, !C/D. */
- if (grub_atapi_wait_drq (dev, GRUB_ATAPI_IREASON_DATA_IN, GRUB_ATA_TOUT_DATA))
- return grub_errno;
-
- /* Get byte count for this DRQ assertion. */
- unsigned cnt = grub_ata_regget (dev, GRUB_ATAPI_REG_CNTHIGH) << 8
- | grub_ata_regget (dev, GRUB_ATAPI_REG_CNTLOW);
- grub_dprintf("ata", "DRQ count=%u\n", cnt);
-
- /* Count of last transfer may be uneven. */
- if (! (0 < cnt && cnt <= size - nread && (! (cnt & 1) || cnt == size - nread)))
- return grub_error (GRUB_ERR_READ_ERROR, "invalid ATAPI transfer count");
-
- /* Read the data. */
- grub_ata_pio_read (dev, buf + nread, cnt);
-
- if (cnt & 1)
- buf[nread + cnt - 1] = (char) grub_le_to_cpu16 (grub_inw (dev->ioaddress + GRUB_ATA_REG_DATA));
-
- nread += cnt;
- }
-
++ struct grub_ata *dev = scsi->data;
++ struct grub_disk_ata_pass_through_parms parms;
++ grub_err_t err;
+
+ grub_dprintf("ata", "grub_atapi_read (size=%llu)\n", (unsigned long long) size);
++ grub_memset (&parms, 0, sizeof (parms));
++
++ parms.taskfile.disk = 0;
++ parms.taskfile.features = 0;
++ parms.taskfile.atapi_ireason = 0;
++ parms.taskfile.atapi_cnthigh = size >> 8;
++ parms.taskfile.atapi_cntlow = size & 0xff;
++ parms.taskfile.cmd = GRUB_ATA_CMD_PACKET;
++ parms.cmd = cmd;
++ parms.cmdsize = cmdsize;
++
++ parms.size = size;
++ parms.buffer = buf;
++
++ err = dev->dev->readwrite (dev, &parms);
++ if (err)
++ return err;
+
-grub_atapi_open (int devnum, struct grub_scsi *scsi)
++ if (parms.size != size)
++ return grub_error (GRUB_ERR_READ_ERROR, "incomplete ATAPI read");
+ return GRUB_ERR_NONE;
+ }
+
+ static grub_err_t
+ grub_atapi_write (struct grub_scsi *scsi __attribute__((unused)),
+ grub_size_t cmdsize __attribute__((unused)),
+ char *cmd __attribute__((unused)),
+ grub_size_t size __attribute__((unused)),
+ char *buf __attribute__((unused)))
+ {
+ // XXX: scsi.mod does not use write yet.
+ return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "ATAPI write not implemented");
+ }
+
+ static grub_err_t
- struct grub_ata_device *dev;
- struct grub_ata_device *devfnd = 0;
- grub_err_t err;
++grub_atapi_open (int id, int bus, struct grub_scsi *scsi)
+ {
- for (dev = grub_ata_devices; dev; dev = dev->next)
- {
- if (dev->port * 2 + dev->device == devnum)
- {
- devfnd = dev;
- break;
- }
- }
++ struct grub_ata *ata;
+
- grub_dprintf ("ata", "opening ATAPI dev `ata%d'\n", devnum);
++ ata = grub_ata_real_open (id, bus);
++ if (!ata)
++ return grub_errno;
++
++ if (! ata->atapi)
++ return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no such ATAPI device");
+
- if (! devfnd)
- return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no such ATAPI device");
++ scsi->data = ata;
+
- err = check_device (devfnd);
- if (err)
- return err;
++ return GRUB_ERR_NONE;
++}
+
- if (! devfnd->atapi)
- return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no such ATAPI device");
++static int
++grub_atapi_iterate (int (*hook_in) (int id, int bus, int luns))
++{
++ auto int hook (int id, int bus);
++ int hook (int id, int bus)
++ {
++ struct grub_ata *ata;
++ int ret;
+
- scsi->data = devfnd;
++ ata = grub_ata_real_open (id, bus);
+
- return GRUB_ERR_NONE;
++ if (!ata)
++ {
++ grub_errno = GRUB_ERR_NONE;
++ return 0;
++ }
++ if (!ata->atapi)
++ {
++ grub_ata_real_close (ata);
++ return 0;
++ }
++ ret = hook_in (id, bus, 1);
++ grub_ata_real_close (ata);
++ return ret;
++ }
++
++ grub_ata_dev_t p;
++
++ for (p = grub_ata_dev_list; p; p = p->next)
++ if (p->iterate && p->iterate (hook))
++ return 1;
++ return 0;
++}
+
- .name = "ata",
- .id = GRUB_SCSI_SUBSYSTEM_ATAPI,
++static void
++grub_atapi_close (grub_scsi_t disk)
++{
++ struct grub_ata *ata = disk->data;
++ grub_ata_real_close (ata);
++}
++
++
++void
++grub_ata_dev_register (grub_ata_dev_t dev)
++{
++ dev->next = grub_ata_dev_list;
++ grub_ata_dev_list = dev;
+ }
+
++void
++grub_ata_dev_unregister (grub_ata_dev_t dev)
++{
++ grub_ata_dev_t *p, q;
++
++ for (p = &grub_ata_dev_list, q = *p; q; p = &(q->next), q = q->next)
++ if (q == dev)
++ {
++ *p = q->next;
++ break;
++ }
++}
+
+ static struct grub_scsi_dev grub_atapi_dev =
+ {
- .write = grub_atapi_write
+ .iterate = grub_atapi_iterate,
+ .open = grub_atapi_open,
++ .close = grub_atapi_close,
+ .read = grub_atapi_read,
- /* To prevent two drivers operating on the same disks. */
- grub_disk_firmware_is_tainted = 1;
- if (grub_disk_firmware_fini)
- {
- grub_disk_firmware_fini ();
- grub_disk_firmware_fini = NULL;
- }
-
- /* ATA initialization. */
- grub_ata_initialize ();
-
++ .write = grub_atapi_write,
++ .next = 0
+ };
+
+ \f
+
+ GRUB_MOD_INIT(ata)
+ {
+ grub_disk_dev_register (&grub_atadisk_dev);
+
+ /* ATAPI devices are handled by scsi.mod. */
+ grub_scsi_dev_register (&grub_atapi_dev);
+ }
+
+ GRUB_MOD_FINI(ata)
+ {
+ grub_scsi_dev_unregister (&grub_atapi_dev);
+ grub_disk_dev_unregister (&grub_atadisk_dev);
+ }
--- /dev/null
- auto int scsi_iterate (int bus, int luns);
+ /* scsi.c - scsi support. */
+ /*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2008,2009 Free Software Foundation, Inc.
+ *
+ * GRUB 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB 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 GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+ #include <grub/disk.h>
+ #include <grub/dl.h>
+ #include <grub/kernel.h>
+ #include <grub/misc.h>
+ #include <grub/mm.h>
+ #include <grub/types.h>
+ #include <grub/scsi.h>
+ #include <grub/scsicmd.h>
+ #include <grub/time.h>
+
+ \f
+ static grub_scsi_dev_t grub_scsi_dev_list;
+
++char grub_scsi_names[GRUB_SCSI_NUM_SUBSYSTEMS][5] = {
++ [GRUB_SCSI_SUBSYSTEM_USBMS] = "usb",
++ [GRUB_SCSI_SUBSYSTEM_PATA] = "ata",
++ [GRUB_SCSI_SUBSYSTEM_AHCI] = "ahci"
++};
++
+ void
+ grub_scsi_dev_register (grub_scsi_dev_t dev)
+ {
+ dev->next = grub_scsi_dev_list;
+ grub_scsi_dev_list = dev;
+ }
+
+ void
+ grub_scsi_dev_unregister (grub_scsi_dev_t dev)
+ {
+ grub_scsi_dev_t *p, q;
+
+ for (p = &grub_scsi_dev_list, q = *p; q; p = &(q->next), q = q->next)
+ if (q == dev)
+ {
+ *p = q->next;
+ break;
+ }
+ }
+
+ \f
+ /* Check result of previous operation. */
+ static grub_err_t
+ grub_scsi_request_sense (grub_scsi_t scsi)
+ {
+ struct grub_scsi_request_sense rs;
+ struct grub_scsi_request_sense_data rsd;
+ grub_err_t err;
+
+ rs.opcode = grub_scsi_cmd_request_sense;
+ rs.lun = scsi->lun << GRUB_SCSI_LUN_SHIFT;
+ rs.reserved1 = 0;
+ rs.reserved2 = 0;
+ rs.alloc_length = 0x12; /* XXX: Hardcoded for now */
+ rs.control = 0;
+ grub_memset (rs.pad, 0, sizeof(rs.pad));
+
+ err = scsi->dev->read (scsi, sizeof (rs), (char *) &rs,
+ sizeof (rsd), (char *) &rsd);
+ if (err)
+ return err;
+
+ return GRUB_ERR_NONE;
+ }
+ /* Self commenting... */
+ static grub_err_t
+ grub_scsi_test_unit_ready (grub_scsi_t scsi)
+ {
+ struct grub_scsi_test_unit_ready tur;
+ grub_err_t err;
+ grub_err_t err_sense;
+
+ tur.opcode = grub_scsi_cmd_test_unit_ready;
+ tur.lun = scsi->lun << GRUB_SCSI_LUN_SHIFT;
+ tur.reserved1 = 0;
+ tur.reserved2 = 0;
+ tur.reserved3 = 0;
+ tur.control = 0;
+ grub_memset (tur.pad, 0, sizeof(tur.pad));
+
+ err = scsi->dev->read (scsi, sizeof (tur), (char *) &tur,
+ 0, NULL);
+
+ /* Each SCSI command should be followed by Request Sense.
+ If not so, many devices STALLs or definitely freezes. */
+ err_sense = grub_scsi_request_sense (scsi);
+ if (err_sense != GRUB_ERR_NONE)
+ grub_errno = err;
+ /* err_sense is ignored for now and Request Sense Data also... */
+
+ if (err)
+ return err;
+
+ return GRUB_ERR_NONE;
+ }
+
+ /* Determine if the device is removable and the type of the device
+ SCSI. */
+ static grub_err_t
+ grub_scsi_inquiry (grub_scsi_t scsi)
+ {
+ struct grub_scsi_inquiry iq;
+ struct grub_scsi_inquiry_data iqd;
+ grub_err_t err;
+ grub_err_t err_sense;
+
+ iq.opcode = grub_scsi_cmd_inquiry;
+ iq.lun = scsi->lun << GRUB_SCSI_LUN_SHIFT;
+ iq.page = 0;
+ iq.reserved = 0;
+ iq.alloc_length = 0x24; /* XXX: Hardcoded for now */
+ iq.control = 0;
+ grub_memset (iq.pad, 0, sizeof(iq.pad));
+
+ err = scsi->dev->read (scsi, sizeof (iq), (char *) &iq,
+ sizeof (iqd), (char *) &iqd);
+
+ /* Each SCSI command should be followed by Request Sense.
+ If not so, many devices STALLs or definitely freezes. */
+ err_sense = grub_scsi_request_sense (scsi);
+ if (err_sense != GRUB_ERR_NONE)
+ grub_errno = err;
+ /* err_sense is ignored for now and Request Sense Data also... */
+
+ if (err)
+ return err;
+
+ scsi->devtype = iqd.devtype & GRUB_SCSI_DEVTYPE_MASK;
+ scsi->removable = iqd.rmb >> GRUB_SCSI_REMOVABLE_BIT;
+
+ return GRUB_ERR_NONE;
+ }
+
+ /* Read the capacity and block size of SCSI. */
+ static grub_err_t
+ grub_scsi_read_capacity (grub_scsi_t scsi)
+ {
+ struct grub_scsi_read_capacity rc;
+ struct grub_scsi_read_capacity_data rcd;
+ grub_err_t err;
+ grub_err_t err_sense;
+
+ rc.opcode = grub_scsi_cmd_read_capacity;
+ rc.lun = scsi->lun << GRUB_SCSI_LUN_SHIFT;
+ rc.logical_block_addr = 0;
+ rc.reserved1 = 0;
+ rc.reserved2 = 0;
+ rc.PMI = 0;
+ rc.control = 0;
+ rc.pad = 0;
+
+ err = scsi->dev->read (scsi, sizeof (rc), (char *) &rc,
+ sizeof (rcd), (char *) &rcd);
+
+ /* Each SCSI command should be followed by Request Sense.
+ If not so, many devices STALLs or definitely freezes. */
+ err_sense = grub_scsi_request_sense (scsi);
+ if (err_sense != GRUB_ERR_NONE)
+ grub_errno = err;
+ /* err_sense is ignored for now and Request Sense Data also... */
+
+ if (err)
+ return err;
+
+ scsi->size = grub_be_to_cpu32 (rcd.size);
+ scsi->blocksize = grub_be_to_cpu32 (rcd.blocksize);
+
+ return GRUB_ERR_NONE;
+ }
+
+ /* Send a SCSI request for DISK: read SIZE sectors starting with
+ sector SECTOR to BUF. */
+ static grub_err_t
+ grub_scsi_read10 (grub_disk_t disk, grub_disk_addr_t sector,
+ grub_size_t size, char *buf)
+ {
+ grub_scsi_t scsi;
+ struct grub_scsi_read10 rd;
+ grub_err_t err;
+ grub_err_t err_sense;
+
+ scsi = disk->data;
+
+ rd.opcode = grub_scsi_cmd_read10;
+ rd.lun = scsi->lun << GRUB_SCSI_LUN_SHIFT;
+ rd.lba = grub_cpu_to_be32 (sector);
+ rd.reserved = 0;
+ rd.size = grub_cpu_to_be16 (size);
+ rd.reserved2 = 0;
+ rd.pad = 0;
+
+ err = scsi->dev->read (scsi, sizeof (rd), (char *) &rd, size * scsi->blocksize, buf);
+
+ /* Each SCSI command should be followed by Request Sense.
+ If not so, many devices STALLs or definitely freezes. */
+ err_sense = grub_scsi_request_sense (scsi);
+ if (err_sense != GRUB_ERR_NONE)
+ grub_errno = err;
+ /* err_sense is ignored for now and Request Sense Data also... */
+
+ return err;
+ }
+
+ /* Send a SCSI request for DISK: read SIZE sectors starting with
+ sector SECTOR to BUF. */
+ static grub_err_t
+ grub_scsi_read12 (grub_disk_t disk, grub_disk_addr_t sector,
+ grub_size_t size, char *buf)
+ {
+ grub_scsi_t scsi;
+ struct grub_scsi_read12 rd;
+ grub_err_t err;
+ grub_err_t err_sense;
+
+ scsi = disk->data;
+
+ rd.opcode = grub_scsi_cmd_read12;
+ rd.lun = scsi->lun << GRUB_SCSI_LUN_SHIFT;
+ rd.lba = grub_cpu_to_be32 (sector);
+ rd.size = grub_cpu_to_be32 (size);
+ rd.reserved = 0;
+ rd.control = 0;
+
+ err = scsi->dev->read (scsi, sizeof (rd), (char *) &rd, size * scsi->blocksize, buf);
+
+ /* Each SCSI command should be followed by Request Sense.
+ If not so, many devices STALLs or definitely freezes. */
+ err_sense = grub_scsi_request_sense (scsi);
+ if (err_sense != GRUB_ERR_NONE)
+ grub_errno = err;
+ /* err_sense is ignored for now and Request Sense Data also... */
+
+ return err;
+ }
+
+ #if 0
+ /* Send a SCSI request for DISK: write the data stored in BUF to SIZE
+ sectors starting with SECTOR. */
+ static grub_err_t
+ grub_scsi_write10 (grub_disk_t disk, grub_disk_addr_t sector,
+ grub_size_t size, char *buf)
+ {
+ grub_scsi_t scsi;
+ struct grub_scsi_write10 wr;
+ grub_err_t err;
+ grub_err_t err_sense;
+
+ scsi = disk->data;
+
+ wr.opcode = grub_scsi_cmd_write10;
+ wr.lun = scsi->lun << GRUB_SCSI_LUN_SHIFT;
+ wr.lba = grub_cpu_to_be32 (sector);
+ wr.reserved = 0;
+ wr.size = grub_cpu_to_be16 (size);
+ wr.reserved2 = 0;
+ wr.pad = 0;
+
+ err = scsi->dev->write (scsi, sizeof (wr), (char *) &wr, size * scsi->blocksize, buf);
+
+ /* Each SCSI command should be followed by Request Sense.
+ If not so, many devices STALLs or definitely freezes. */
+ err_sense = grub_scsi_request_sense (scsi);
+ if (err_sense != GRUB_ERR_NONE)
+ grub_errno = err;
+ /* err_sense is ignored for now and Request Sense Data also... */
+
+ return err;
+ }
+
+ /* Send a SCSI request for DISK: write the data stored in BUF to SIZE
+ sectors starting with SECTOR. */
+ static grub_err_t
+ grub_scsi_write12 (grub_disk_t disk, grub_disk_addr_t sector,
+ grub_size_t size, char *buf)
+ {
+ grub_scsi_t scsi;
+ struct grub_scsi_write12 wr;
+ grub_err_t err;
+ grub_err_t err_sense;
+
+ scsi = disk->data;
+
+ wr.opcode = grub_scsi_cmd_write12;
+ wr.lun = scsi->lun << GRUB_SCSI_LUN_SHIFT;
+ wr.lba = grub_cpu_to_be32 (sector);
+ wr.size = grub_cpu_to_be32 (size);
+ wr.reserved = 0;
+ wr.control = 0;
+
+ err = scsi->dev->write (scsi, sizeof (wr), (char *) &wr, size * scsi->blocksize, buf);
+
+ /* Each SCSI command should be followed by Request Sense.
+ If not so, many devices STALLs or definitely freezes. */
+ err_sense = grub_scsi_request_sense (scsi);
+ if (err_sense != GRUB_ERR_NONE)
+ grub_errno = err;
+ /* err_sense is ignored for now and Request Sense Data also... */
+
+ return err;
+ }
+ #endif
+
+ \f
+ static int
+ grub_scsi_iterate (int (*hook) (const char *name))
+ {
+ grub_scsi_dev_t p;
+
- int scsi_iterate (int bus, int luns)
++ auto int scsi_iterate (int id, int bus, int luns);
+
- sname = grub_xasprintf ("%s%d", p->name, bus);
++ int scsi_iterate (int id, int bus, int luns)
+ {
+ int i;
+
+ /* In case of a single LUN, just return `usbX'. */
+ if (luns == 1)
+ {
+ char *sname;
+ int ret;
- sname = grub_xasprintf ("%s%d%c", p->name, bus, 'a' + i);
++ sname = grub_xasprintf ("%s%d", grub_scsi_names[id], bus);
+ if (!sname)
+ return 1;
+ ret = hook (sname);
+ grub_free (sname);
+ return ret;
+ }
+
+ /* In case of multiple LUNs, every LUN will get a prefix to
+ distinguish it. */
+ for (i = 0; i < luns; i++)
+ {
+ char *sname;
+ int ret;
- for (p = grub_scsi_dev_list; p; p = p->next)
++ sname = grub_xasprintf ("%s%d%c", grub_scsi_names[id], bus, 'a' + i);
+ if (!sname)
+ return 1;
+ ret = hook (sname);
+ grub_free (sname);
+ if (ret)
+ return 1;
+ }
+ return 0;
+ }
+
+ for (p = grub_scsi_dev_list; p; p = p->next)
+ if (p->iterate && (p->iterate) (scsi_iterate))
+ return 1;
+
+ return 0;
+ }
+
+ static grub_err_t
+ grub_scsi_open (const char *name, grub_disk_t disk)
+ {
+ grub_scsi_dev_t p;
+ grub_scsi_t scsi;
+ grub_err_t err;
+ int lun, bus;
+ grub_uint64_t maxtime;
+ const char *nameend;
++ unsigned id;
+
+ nameend = name + grub_strlen (name) - 1;
+ /* Try to detect a LUN ('a'-'z'), otherwise just use the first
+ LUN. */
+ if (nameend >= name && *nameend >= 'a' && *nameend <= 'z')
+ {
+ lun = *nameend - 'a';
+ nameend--;
+ }
+ else
+ lun = 0;
+
+ while (nameend >= name && grub_isdigit (*nameend))
+ nameend--;
+
+ if (!nameend[1] || !grub_isdigit (nameend[1]))
+ return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not a SCSI disk");
+
+ bus = grub_strtoul (nameend + 1, 0, 0);
+
+ scsi = grub_malloc (sizeof (*scsi));
+ if (! scsi)
+ return grub_errno;
+
- if (grub_strncmp (p->name, name, nameend - name) != 0)
- continue;
++ for (id = 0; id < ARRAY_SIZE (grub_scsi_names); id++)
++ if (grub_strncmp (grub_scsi_names[id], name, nameend - name) == 0)
++ break;
++
++ if (id == ARRAY_SIZE (grub_scsi_names))
+ {
- if (p->open (bus, scsi))
- continue;
++ grub_free (scsi);
++ return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not a SCSI disk");
++ }
+
- disk->id = grub_make_scsi_id (p->id, bus, lun);
++ for (p = grub_scsi_dev_list; p; p = p->next)
++ {
++ if (p->open (id, bus, scsi))
++ {
++ grub_errno = GRUB_ERR_NONE;
++ continue;
++ }
+
-
++ disk->id = grub_make_scsi_id (id, bus, lun);
+ disk->data = scsi;
+ scsi->dev = p;
+ scsi->lun = lun;
+ scsi->bus = bus;
+
+ grub_dprintf ("scsi", "dev opened\n");
+
+ err = grub_scsi_inquiry (scsi);
+ if (err)
+ {
+ grub_free (scsi);
+ grub_dprintf ("scsi", "inquiry failed\n");
+ return err;
+ }
+
+ grub_dprintf ("scsi", "inquiry: devtype=0x%02x removable=%d\n",
+ scsi->devtype, scsi->removable);
+
+ /* Try to be conservative about the device types
+ supported. */
+ if (scsi->devtype != grub_scsi_devtype_direct
+ && scsi->devtype != grub_scsi_devtype_cdrom)
+ {
+ grub_free (scsi);
+ return grub_error (GRUB_ERR_UNKNOWN_DEVICE,
+ "unknown SCSI device");
+ }
+
+ /* According to USB MS tests specification, issue Test Unit Ready
+ * until OK */
+ maxtime = grub_get_time_ms () + 5000; /* It is safer value */
+ do
+ {
+ /* Timeout is necessary - for example in case when we have
+ * universal card reader with more LUNs and we have only
+ * one card inserted (or none), so only one LUN (or none)
+ * will be ready - and we want not to hang... */
+ if (grub_get_time_ms () > maxtime)
+ {
+ err = GRUB_ERR_READ_ERROR;
+ grub_free (scsi);
+ grub_dprintf ("scsi", "LUN is not ready - timeout\n");
+ return err;
+ }
+ err = grub_scsi_test_unit_ready (scsi);
+ }
+ while (err == GRUB_ERR_READ_ERROR);
+ /* Reset grub_errno !
+ * It is set to some error code in loop before... */
+ grub_errno = GRUB_ERR_NONE;
+
+ /* Read capacity of media */
+ err = grub_scsi_read_capacity (scsi);
+ if (err)
+ {
+ grub_free (scsi);
+ grub_dprintf ("scsi", "READ CAPACITY failed\n");
+ return err;
+ }
+
+ /* SCSI blocks can be something else than 512, although GRUB
+ wants 512 byte blocks. */
+ disk->total_sectors = ((grub_uint64_t)scsi->size
+ * (grub_uint64_t)scsi->blocksize)
+ >> GRUB_DISK_SECTOR_BITS;
+
+ grub_dprintf ("scsi", "blocks=%u, blocksize=%u\n",
+ scsi->size, scsi->blocksize);
+ grub_dprintf ("scsi", "Disk total 512 sectors = %llu\n",
+ (unsigned long long) disk->total_sectors);
+
+ return GRUB_ERR_NONE;
+ }
+
+ grub_free (scsi);
+ return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not a SCSI disk");
+ }
+
+ static void
+ grub_scsi_close (grub_disk_t disk)
+ {
+ grub_scsi_t scsi;
+
+ scsi = disk->data;
+ if (scsi->dev->close)
+ scsi->dev->close (scsi);
+ grub_free (scsi);
+ }
+
+ static grub_err_t
+ grub_scsi_read (grub_disk_t disk, grub_disk_addr_t sector,
+ grub_size_t size, char *buf)
+ {
+ grub_scsi_t scsi;
+
+ scsi = disk->data;
+
+ /* SCSI sectors are variable in size. GRUB uses 512 byte
+ sectors. */
+ if (scsi->blocksize != GRUB_DISK_SECTOR_SIZE)
+ {
+ unsigned spb = scsi->blocksize >> GRUB_DISK_SECTOR_BITS;
+ if (! (spb != 0 && (scsi->blocksize & GRUB_DISK_SECTOR_SIZE) == 0))
+ return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
+ "unsupported SCSI block size");
+
+ grub_uint32_t sector_mod = 0;
+ sector = grub_divmod64 (sector, spb, §or_mod);
+
+ if (! (sector_mod == 0 && size % spb == 0))
+ return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
+ "unaligned SCSI read not supported");
+
+ size /= spb;
+ }
+
+ /* Depending on the type, select a read function. */
+ switch (scsi->devtype)
+ {
+ case grub_scsi_devtype_direct:
+ return grub_scsi_read10 (disk, sector, size, buf);
+
+ case grub_scsi_devtype_cdrom:
+ return grub_scsi_read12 (disk, sector, size, buf);
+ }
+
+ /* XXX: Never reached. */
+ return GRUB_ERR_NONE;
+
+ #if 0 /* Workaround - it works - but very slowly, from some reason
+ * unknown to me (specially on OHCI). Do not use it. */
+ /* Split transfer requests to device sector size because */
+ /* some devices are not able to transfer more than 512-1024 bytes */
+ grub_err_t err = GRUB_ERR_NONE;
+
+ for ( ; size; size--)
+ {
+ /* Depending on the type, select a read function. */
+ switch (scsi->devtype)
+ {
+ case grub_scsi_devtype_direct:
+ err = grub_scsi_read10 (disk, sector, 1, buf);
+ break;
+
+ case grub_scsi_devtype_cdrom:
+ err = grub_scsi_read12 (disk, sector, 1, buf);
+ break;
+
+ default: /* This should not happen */
+ return GRUB_ERR_READ_ERROR;
+ }
+ if (err)
+ return err;
+ sector++;
+ buf += scsi->blocksize;
+ }
+
+ return err;
+ #endif
+ }
+
+ static grub_err_t
+ grub_scsi_write (grub_disk_t disk __attribute((unused)),
+ grub_disk_addr_t sector __attribute((unused)),
+ grub_size_t size __attribute((unused)),
+ const char *buf __attribute((unused)))
+ {
+ #if 0
+ /* XXX: Not tested yet! */
+
+ /* XXX: This should depend on the device type? */
+ return grub_scsi_write10 (disk, sector, size, buf);
+ #endif
+ return GRUB_ERR_NOT_IMPLEMENTED_YET;
+ }
+
+
+ static struct grub_disk_dev grub_scsi_dev =
+ {
+ .name = "scsi",
+ .id = GRUB_DISK_DEVICE_SCSI_ID,
+ .iterate = grub_scsi_iterate,
+ .open = grub_scsi_open,
+ .close = grub_scsi_close,
+ .read = grub_scsi_read,
+ .write = grub_scsi_write,
+ .next = 0
+ };
+
+ GRUB_MOD_INIT(scsi)
+ {
+ grub_disk_dev_register (&grub_scsi_dev);
+ }
+
+ GRUB_MOD_FINI(scsi)
+ {
+ grub_disk_dev_unregister (&grub_scsi_dev);
+ }
--- /dev/null
-grub_usbms_iterate (int (*hook) (int bus, int luns))
+ /* usbms.c - USB Mass Storage Support. */
+ /*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2008 Free Software Foundation, Inc.
+ *
+ * GRUB 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB 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 GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+ #include <grub/dl.h>
+ #include <grub/mm.h>
+ #include <grub/usb.h>
+ #include <grub/scsi.h>
+ #include <grub/scsicmd.h>
+ #include <grub/misc.h>
+
+ #define GRUB_USBMS_DIRECTION_BIT 7
+
+ /* The USB Mass Storage Command Block Wrapper. */
+ struct grub_usbms_cbw
+ {
+ grub_uint32_t signature;
+ grub_uint32_t tag;
+ grub_uint32_t transfer_length;
+ grub_uint8_t flags;
+ grub_uint8_t lun;
+ grub_uint8_t length;
+ grub_uint8_t cbwcb[16];
+ } __attribute__ ((packed));
+
+ struct grub_usbms_csw
+ {
+ grub_uint32_t signature;
+ grub_uint32_t tag;
+ grub_uint32_t residue;
+ grub_uint8_t status;
+ } __attribute__ ((packed));
+
+ struct grub_usbms_dev
+ {
+ struct grub_usb_device *dev;
+
+ int luns;
+
+ int config;
+ int interface;
+ struct grub_usb_desc_endp *in;
+ struct grub_usb_desc_endp *out;
+
+ int in_maxsz;
+ int out_maxsz;
+ };
+ typedef struct grub_usbms_dev *grub_usbms_dev_t;
+
+ /* FIXME: remove limit. */
+ #define MAX_USBMS_DEVICES 128
+ static grub_usbms_dev_t grub_usbms_devices[MAX_USBMS_DEVICES];
+ static int first_available_slot = 0;
+
+ static grub_err_t
+ grub_usbms_reset (grub_usb_device_t dev, int interface)
+ {
+ return grub_usb_control_msg (dev, 0x21, 255, 0, interface, 0, 0);
+ }
+
+ static void
+ grub_usbms_detach (grub_usb_device_t usbdev, int config, int interface)
+ {
+ unsigned i;
+ for (i = 0; i < ARRAY_SIZE (grub_usbms_devices); i++)
+ if (grub_usbms_devices[i] && grub_usbms_devices[i]->dev == usbdev
+ && grub_usbms_devices[i]->interface == interface
+ && grub_usbms_devices[i]->config == config)
+ {
+ grub_free (grub_usbms_devices[i]);
+ grub_usbms_devices[i] = 0;
+ }
+ }
+
+ static int
+ grub_usbms_attach (grub_usb_device_t usbdev, int configno, int interfno)
+ {
+ struct grub_usb_desc_if *interf
+ = usbdev->config[configno].interf[interfno].descif;
+ int j;
+ grub_uint8_t luns = 0;
+ unsigned curnum;
+ grub_usb_err_t err;
+
+ if (first_available_slot == ARRAY_SIZE (grub_usbms_devices))
+ return 0;
+
+ curnum = first_available_slot;
+ first_available_slot++;
+
+ interf = usbdev->config[configno].interf[interfno].descif;
+
+ if ((interf->subclass != GRUB_USBMS_SUBCLASS_BULK
+ /* Experimental support of RBC, MMC-2, UFI, SFF-8070i devices */
+ && interf->subclass != GRUB_USBMS_SUBCLASS_RBC
+ && interf->subclass != GRUB_USBMS_SUBCLASS_MMC2
+ && interf->subclass != GRUB_USBMS_SUBCLASS_UFI
+ && interf->subclass != GRUB_USBMS_SUBCLASS_SFF8070 )
+ || interf->protocol != GRUB_USBMS_PROTOCOL_BULK)
+ return 0;
+
+ grub_usbms_devices[curnum] = grub_zalloc (sizeof (struct grub_usbms_dev));
+ if (! grub_usbms_devices[curnum])
+ return 0;
+
+ grub_usbms_devices[curnum]->dev = usbdev;
+ grub_usbms_devices[curnum]->interface = interfno;
+
+ grub_dprintf ("usbms", "alive\n");
+
+ /* Iterate over all endpoints of this interface, at least a
+ IN and OUT bulk endpoint are required. */
+ for (j = 0; j < interf->endpointcnt; j++)
+ {
+ struct grub_usb_desc_endp *endp;
+ endp = &usbdev->config[0].interf[interfno].descendp[j];
+
+ if ((endp->endp_addr & 128) && (endp->attrib & 3) == 2)
+ {
+ /* Bulk IN endpoint. */
+ grub_usbms_devices[curnum]->in = endp;
+ /* Clear Halt is not possible yet! */
+ /* grub_usb_clear_halt (usbdev, endp->endp_addr); */
+ grub_usbms_devices[curnum]->in_maxsz = endp->maxpacket;
+ }
+ else if (!(endp->endp_addr & 128) && (endp->attrib & 3) == 2)
+ {
+ /* Bulk OUT endpoint. */
+ grub_usbms_devices[curnum]->out = endp;
+ /* Clear Halt is not possible yet! */
+ /* grub_usb_clear_halt (usbdev, endp->endp_addr); */
+ grub_usbms_devices[curnum]->out_maxsz = endp->maxpacket;
+ }
+ }
+
+ if (!grub_usbms_devices[curnum]->in || !grub_usbms_devices[curnum]->out)
+ {
+ grub_free (grub_usbms_devices[curnum]);
+ grub_usbms_devices[curnum] = 0;
+ return 0;
+ }
+
+ grub_dprintf ("usbms", "alive\n");
+
+ /* XXX: Activate the first configuration. */
+ grub_usb_set_configuration (usbdev, 1);
+
+ /* Query the amount of LUNs. */
+ err = grub_usb_control_msg (usbdev, 0xA1, 254, 0, interfno, 1, (char *) &luns);
+
+ if (err)
+ {
+ /* In case of a stall, clear the stall. */
+ if (err == GRUB_USB_ERR_STALL)
+ {
+ grub_usb_clear_halt (usbdev, grub_usbms_devices[curnum]->in->endp_addr);
+ grub_usb_clear_halt (usbdev, grub_usbms_devices[curnum]->out->endp_addr);
+ }
+ /* Just set the amount of LUNs to one. */
+ grub_errno = GRUB_ERR_NONE;
+ grub_usbms_devices[curnum]->luns = 1;
+ }
+ else
+ /* luns = 0 means one LUN with ID 0 present ! */
+ /* We get from device not number of LUNs but highest
+ * LUN number. LUNs are numbered from 0,
+ * i.e. number of LUNs is luns+1 ! */
+ grub_usbms_devices[curnum]->luns = luns + 1;
+
+ grub_dprintf ("usbms", "alive\n");
+
+ usbdev->config[configno].interf[interfno].detach_hook = grub_usbms_detach;
+
+ #if 0 /* All this part should be probably deleted.
+ * This make trouble on some devices if they are not in
+ * Phase Error state - and there they should be not in such state...
+ * Bulk only mass storage reset procedure should be used only
+ * on place and in time when it is really necessary. */
+ /* Reset recovery procedure */
+ /* Bulk-Only Mass Storage Reset, after the reset commands
+ will be accepted. */
+ grub_usbms_reset (usbdev, i);
+ grub_usb_clear_halt (usbdev, usbms->in->endp_addr);
+ grub_usb_clear_halt (usbdev, usbms->out->endp_addr);
+ #endif
+
+ return 1;
+ }
+
+ \f
+
+ static int
- if (hook (i, grub_usbms_devices[i]->luns))
++grub_usbms_iterate (int (*hook) (int id, int bus, int luns))
+ {
+ unsigned i;
+
+ grub_usb_poll_devices ();
+
+ for (i = 0; i < ARRAY_SIZE (grub_usbms_devices); i++)
+ if (grub_usbms_devices[i])
+ {
-grub_usbms_open (int devnum, struct grub_scsi *scsi)
++ if (hook (GRUB_SCSI_SUBSYSTEM_USBMS, i, grub_usbms_devices[i]->luns))
+ return 1;
+ }
+
+ return 0;
+ }
+
+ static grub_err_t
+ grub_usbms_transfer (struct grub_scsi *scsi, grub_size_t cmdsize, char *cmd,
+ grub_size_t size, char *buf, int read_write)
+ {
+ struct grub_usbms_cbw cbw;
+ grub_usbms_dev_t dev = (grub_usbms_dev_t) scsi->data;
+ struct grub_usbms_csw status;
+ static grub_uint32_t tag = 0;
+ grub_usb_err_t err = GRUB_USB_ERR_NONE;
+ grub_usb_err_t errCSW = GRUB_USB_ERR_NONE;
+ int retrycnt = 3 + 1;
+
+ retry:
+ retrycnt--;
+ if (retrycnt == 0)
+ return grub_error (GRUB_ERR_IO, "USB Mass Storage stalled");
+
+ /* Setup the request. */
+ grub_memset (&cbw, 0, sizeof (cbw));
+ cbw.signature = grub_cpu_to_le32 (0x43425355);
+ cbw.tag = tag++;
+ cbw.transfer_length = grub_cpu_to_le32 (size);
+ cbw.flags = (!read_write) << GRUB_USBMS_DIRECTION_BIT;
+ cbw.lun = scsi->lun; /* In USB MS CBW are LUN bits on another place than in SCSI CDB, both should be set correctly. */
+ cbw.length = cmdsize;
+ grub_memcpy (cbw.cbwcb, cmd, cmdsize);
+
+ /* Debug print of CBW content. */
+ grub_dprintf ("usb", "CBW: sign=0x%08x tag=0x%08x len=0x%08x\n",
+ cbw.signature, cbw.tag, cbw.transfer_length);
+ grub_dprintf ("usb", "CBW: flags=0x%02x lun=0x%02x CB_len=0x%02x\n",
+ cbw.flags, cbw.lun, cbw.length);
+ grub_dprintf ("usb", "CBW: cmd:\n %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
+ cbw.cbwcb[ 0], cbw.cbwcb[ 1], cbw.cbwcb[ 2], cbw.cbwcb[ 3],
+ cbw.cbwcb[ 4], cbw.cbwcb[ 5], cbw.cbwcb[ 6], cbw.cbwcb[ 7],
+ cbw.cbwcb[ 8], cbw.cbwcb[ 9], cbw.cbwcb[10], cbw.cbwcb[11],
+ cbw.cbwcb[12], cbw.cbwcb[13], cbw.cbwcb[14], cbw.cbwcb[15]);
+
+ /* Write the request.
+ * XXX: Error recovery is maybe still not fully correct. */
+ err = grub_usb_bulk_write (dev->dev, dev->out->endp_addr,
+ sizeof (cbw), (char *) &cbw);
+ if (err)
+ {
+ if (err == GRUB_USB_ERR_STALL)
+ {
+ grub_usb_clear_halt (dev->dev, dev->out->endp_addr);
+ goto CheckCSW;
+ }
+ return grub_error (GRUB_ERR_IO, "USB Mass Storage request failed");
+ }
+
+ /* Read/write the data, (maybe) according to specification. */
+ if (size && (read_write == 0))
+ {
+ err = grub_usb_bulk_read (dev->dev, dev->in->endp_addr, size, buf);
+ grub_dprintf ("usb", "read: %d %d\n", err, GRUB_USB_ERR_STALL);
+ if (err)
+ {
+ if (err == GRUB_USB_ERR_STALL)
+ grub_usb_clear_halt (dev->dev, dev->in->endp_addr);
+ goto CheckCSW;
+ }
+ /* Debug print of received data. */
+ grub_dprintf ("usb", "buf:\n");
+ if (size <= 64)
+ {
+ unsigned i;
+ for (i = 0; i < size; i++)
+ grub_dprintf ("usb", "0x%02x: 0x%02x\n", i, buf[i]);
+ }
+ else
+ grub_dprintf ("usb", "Too much data for debug print...\n");
+ }
+ else if (size)
+ {
+ err = grub_usb_bulk_write (dev->dev, dev->out->endp_addr, size, buf);
+ grub_dprintf ("usb", "write: %d %d\n", err, GRUB_USB_ERR_STALL);
+ grub_dprintf ("usb", "First 16 bytes of sent data:\n %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
+ buf[ 0], buf[ 1], buf[ 2], buf[ 3],
+ buf[ 4], buf[ 5], buf[ 6], buf[ 7],
+ buf[ 8], buf[ 9], buf[10], buf[11],
+ buf[12], buf[13], buf[14], buf[15]);
+ if (err)
+ {
+ if (err == GRUB_USB_ERR_STALL)
+ grub_usb_clear_halt (dev->dev, dev->out->endp_addr);
+ goto CheckCSW;
+ }
+ /* Debug print of sent data. */
+ if (size <= 256)
+ {
+ unsigned i;
+ for (i=0; i<size; i++)
+ grub_dprintf ("usb", "0x%02x: 0x%02x\n", i, buf[i]);
+ }
+ else
+ grub_dprintf ("usb", "Too much data for debug print...\n");
+ }
+
+ /* Read the status - (maybe) according to specification. */
+ CheckCSW:
+ errCSW = grub_usb_bulk_read (dev->dev, dev->in->endp_addr,
+ sizeof (status), (char *) &status);
+ if (errCSW)
+ {
+ grub_usb_clear_halt (dev->dev, dev->in->endp_addr);
+ errCSW = grub_usb_bulk_read (dev->dev, dev->in->endp_addr,
+ sizeof (status), (char *) &status);
+ if (errCSW)
+ { /* Bulk-only reset device. */
+ grub_dprintf ("usb", "Bulk-only reset device - errCSW\n");
+ grub_usbms_reset (dev->dev, dev->interface);
+ grub_usb_clear_halt (dev->dev, dev->in->endp_addr);
+ grub_usb_clear_halt (dev->dev, dev->out->endp_addr);
+ goto retry;
+ }
+ }
+
+ /* Debug print of CSW content. */
+ grub_dprintf ("usb", "CSW: sign=0x%08x tag=0x%08x resid=0x%08x\n",
+ status.signature, status.tag, status.residue);
+ grub_dprintf ("usb", "CSW: status=0x%02x\n", status.status);
+
+ /* If phase error or not valid signature, do bulk-only reset device. */
+ if ((status.status == 2) ||
+ (status.signature != grub_cpu_to_le32(0x53425355)))
+ { /* Bulk-only reset device. */
+ grub_dprintf ("usb", "Bulk-only reset device - bad status\n");
+ grub_usbms_reset (dev->dev, dev->interface);
+ grub_usb_clear_halt (dev->dev, dev->in->endp_addr);
+ grub_usb_clear_halt (dev->dev, dev->out->endp_addr);
+
+ goto retry;
+ }
+
+ /* If "command failed" status or data transfer failed -> error */
+ if ((status.status || err) && !read_write)
+ return grub_error (GRUB_ERR_READ_ERROR,
+ "error communication with USB Mass Storage device");
+ else if ((status.status || err) && read_write)
+ return grub_error (GRUB_ERR_WRITE_ERROR,
+ "error communication with USB Mass Storage device");
+
+ return GRUB_ERR_NONE;
+ }
+
+
+ static grub_err_t
+ grub_usbms_read (struct grub_scsi *scsi, grub_size_t cmdsize, char *cmd,
+ grub_size_t size, char *buf)
+ {
+ return grub_usbms_transfer (scsi, cmdsize, cmd, size, buf, 0);
+ }
+
+ static grub_err_t
+ grub_usbms_write (struct grub_scsi *scsi, grub_size_t cmdsize, char *cmd,
+ grub_size_t size, char *buf)
+ {
+ return grub_usbms_transfer (scsi, cmdsize, cmd, size, buf, 1);
+ }
+
+ static grub_err_t
- .name = "usb",
- .id = GRUB_SCSI_SUBSYSTEM_USBMS,
++grub_usbms_open (int id, int devnum, struct grub_scsi *scsi)
+ {
++ if (id != GRUB_SCSI_SUBSYSTEM_USBMS)
++ return grub_error (GRUB_ERR_UNKNOWN_DEVICE,
++ "not USB Mass Storage device");
++
+ grub_usb_poll_devices ();
+
+ if (!grub_usbms_devices[devnum])
+ return grub_error (GRUB_ERR_UNKNOWN_DEVICE,
+ "unknown USB Mass Storage device");
+
+ scsi->data = grub_usbms_devices[devnum];
+ scsi->luns = grub_usbms_devices[devnum]->luns;
+
+ return GRUB_ERR_NONE;
+ }
+
+ static struct grub_scsi_dev grub_usbms_dev =
+ {
+ .iterate = grub_usbms_iterate,
+ .open = grub_usbms_open,
+ .read = grub_usbms_read,
+ .write = grub_usbms_write
+ };
+
+ struct grub_usb_attach_desc attach_hook =
+ {
+ .class = GRUB_USB_CLASS_MASS_STORAGE,
+ .hook = grub_usbms_attach
+ };
+
+ GRUB_MOD_INIT(usbms)
+ {
+ grub_usb_register_attach_hook_class (&attach_hook);
+ grub_scsi_dev_register (&grub_usbms_dev);
+ }
+
+ GRUB_MOD_FINI(usbms)
+ {
+ unsigned i;
+ for (i = 0; i < ARRAY_SIZE (grub_usbms_devices); i++)
+ {
+ grub_usbms_devices[i]->dev->config[grub_usbms_devices[i]->config]
+ .interf[grub_usbms_devices[i]->interface].detach_hook = 0;
+ grub_usbms_devices[i]->dev->config[grub_usbms_devices[i]->config]
+ .interf[grub_usbms_devices[i]->interface].attached = 0;
+ }
+ grub_usb_unregister_attach_hook_class (&attach_hook);
+ grub_scsi_dev_unregister (&grub_usbms_dev);
+ }
--- /dev/null
-grub_err_t (* grub_disk_ata_pass_through) (grub_disk_t,
- struct grub_disk_ata_pass_through_parms *);
-
-
+ /*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2002,2003,2004,2006,2007,2008,2009,2010 Free Software Foundation, Inc.
+ *
+ * GRUB 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB 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 GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+ #include <grub/disk.h>
+ #include <grub/err.h>
+ #include <grub/mm.h>
+ #include <grub/types.h>
+ #include <grub/partition.h>
+ #include <grub/misc.h>
+ #include <grub/time.h>
+ #include <grub/file.h>
+
+ #define GRUB_CACHE_TIMEOUT 2
+
+ /* The last time the disk was used. */
+ static grub_uint64_t grub_last_time = 0;
+
+
+ /* Disk cache. */
+ struct grub_disk_cache
+ {
+ enum grub_disk_dev_id dev_id;
+ unsigned long disk_id;
+ grub_disk_addr_t sector;
+ char *data;
+ int lock;
+ };
+
+ static struct grub_disk_cache grub_disk_cache_table[GRUB_DISK_CACHE_NUM];
+
+ void (*grub_disk_firmware_fini) (void);
+ int grub_disk_firmware_is_tainted;
+
+ #if 0
+ static unsigned long grub_disk_cache_hits;
+ static unsigned long grub_disk_cache_misses;
+
+ void
+ grub_disk_cache_get_performance (unsigned long *hits, unsigned long *misses)
+ {
+ *hits = grub_disk_cache_hits;
+ *misses = grub_disk_cache_misses;
+ }
+ #endif
+
+ static unsigned
+ grub_disk_cache_get_index (unsigned long dev_id, unsigned long disk_id,
+ grub_disk_addr_t sector)
+ {
+ return ((dev_id * 524287UL + disk_id * 2606459UL
+ + ((unsigned) (sector >> GRUB_DISK_CACHE_BITS)))
+ % GRUB_DISK_CACHE_NUM);
+ }
+
+ static void
+ grub_disk_cache_invalidate (unsigned long dev_id, unsigned long disk_id,
+ grub_disk_addr_t sector)
+ {
+ unsigned index;
+ struct grub_disk_cache *cache;
+
+ sector &= ~(GRUB_DISK_CACHE_SIZE - 1);
+ index = grub_disk_cache_get_index (dev_id, disk_id, sector);
+ cache = grub_disk_cache_table + index;
+
+ if (cache->dev_id == dev_id && cache->disk_id == disk_id
+ && cache->sector == sector && cache->data)
+ {
+ cache->lock = 1;
+ grub_free (cache->data);
+ cache->data = 0;
+ cache->lock = 0;
+ }
+ }
+
+ void
+ grub_disk_cache_invalidate_all (void)
+ {
+ unsigned i;
+
+ for (i = 0; i < GRUB_DISK_CACHE_NUM; i++)
+ {
+ struct grub_disk_cache *cache = grub_disk_cache_table + i;
+
+ if (cache->data && ! cache->lock)
+ {
+ grub_free (cache->data);
+ cache->data = 0;
+ }
+ }
+ }
+
+ static char *
+ grub_disk_cache_fetch (unsigned long dev_id, unsigned long disk_id,
+ grub_disk_addr_t sector)
+ {
+ struct grub_disk_cache *cache;
+ unsigned index;
+
+ index = grub_disk_cache_get_index (dev_id, disk_id, sector);
+ cache = grub_disk_cache_table + index;
+
+ if (cache->dev_id == dev_id && cache->disk_id == disk_id
+ && cache->sector == sector)
+ {
+ cache->lock = 1;
+ #if 0
+ grub_disk_cache_hits++;
+ #endif
+ return cache->data;
+ }
+
+ #if 0
+ grub_disk_cache_misses++;
+ #endif
+
+ return 0;
+ }
+
+ static void
+ grub_disk_cache_unlock (unsigned long dev_id, unsigned long disk_id,
+ grub_disk_addr_t sector)
+ {
+ struct grub_disk_cache *cache;
+ unsigned index;
+
+ index = grub_disk_cache_get_index (dev_id, disk_id, sector);
+ cache = grub_disk_cache_table + index;
+
+ if (cache->dev_id == dev_id && cache->disk_id == disk_id
+ && cache->sector == sector)
+ cache->lock = 0;
+ }
+
+ static grub_err_t
+ grub_disk_cache_store (unsigned long dev_id, unsigned long disk_id,
+ grub_disk_addr_t sector, const char *data)
+ {
+ unsigned index;
+ struct grub_disk_cache *cache;
+
+ index = grub_disk_cache_get_index (dev_id, disk_id, sector);
+ cache = grub_disk_cache_table + index;
+
+ cache->lock = 1;
+ grub_free (cache->data);
+ cache->data = 0;
+ cache->lock = 0;
+
+ cache->data = grub_malloc (GRUB_DISK_SECTOR_SIZE << GRUB_DISK_CACHE_BITS);
+ if (! cache->data)
+ return grub_errno;
+
+ grub_memcpy (cache->data, data,
+ GRUB_DISK_SECTOR_SIZE << GRUB_DISK_CACHE_BITS);
+ cache->dev_id = dev_id;
+ cache->disk_id = disk_id;
+ cache->sector = sector;
+
+ return GRUB_ERR_NONE;
+ }
+
+ \f
+
+ static grub_disk_dev_t grub_disk_dev_list;
+
+ void
+ grub_disk_dev_register (grub_disk_dev_t dev)
+ {
+ dev->next = grub_disk_dev_list;
+ grub_disk_dev_list = dev;
+ }
+
+ void
+ grub_disk_dev_unregister (grub_disk_dev_t dev)
+ {
+ grub_disk_dev_t *p, q;
+
+ for (p = &grub_disk_dev_list, q = *p; q; p = &(q->next), q = q->next)
+ if (q == dev)
+ {
+ *p = q->next;
+ break;
+ }
+ }
+
+ int
+ grub_disk_dev_iterate (int (*hook) (const char *name))
+ {
+ grub_disk_dev_t p;
+
+ for (p = grub_disk_dev_list; p; p = p->next)
+ if (p->iterate && (p->iterate) (hook))
+ return 1;
+
+ return 0;
+ }
+
+ /* Return the location of the first ',', if any, which is not
+ escaped by a '\'. */
+ static const char *
+ find_part_sep (const char *name)
+ {
+ const char *p = name;
+ char c;
+
+ while ((c = *p++) != '\0')
+ {
+ if (c == '\\' && *p == ',')
+ p++;
+ else if (c == ',')
+ return p - 1;
+ }
+ return NULL;
+ }
+
+ grub_disk_t
+ grub_disk_open (const char *name)
+ {
+ const char *p;
+ grub_disk_t disk;
+ grub_disk_dev_t dev;
+ char *raw = (char *) name;
+ grub_uint64_t current_time;
+
+ grub_dprintf ("disk", "Opening `%s'...\n", name);
+
+ disk = (grub_disk_t) grub_zalloc (sizeof (*disk));
+ if (! disk)
+ return 0;
+
+ p = find_part_sep (name);
+ if (p)
+ {
+ grub_size_t len = p - name;
+
+ raw = grub_malloc (len + 1);
+ if (! raw)
+ goto fail;
+
+ grub_memcpy (raw, name, len);
+ raw[len] = '\0';
+ disk->name = grub_strdup (raw);
+ }
+ else
+ disk->name = grub_strdup (name);
+ if (! disk->name)
+ goto fail;
+
+
+ for (dev = grub_disk_dev_list; dev; dev = dev->next)
+ {
+ if ((dev->open) (raw, disk) == GRUB_ERR_NONE)
+ break;
+ else if (grub_errno == GRUB_ERR_UNKNOWN_DEVICE)
+ grub_errno = GRUB_ERR_NONE;
+ else
+ goto fail;
+ }
+
+ if (! dev)
+ {
+ grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no such disk");
+ goto fail;
+ }
+
+ disk->dev = dev;
+
+ if (p)
+ {
+ disk->partition = grub_partition_probe (disk, p + 1);
+ if (! disk->partition)
+ {
+ grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no such partition");
+ goto fail;
+ }
+ }
+
+ /* The cache will be invalidated about 2 seconds after a device was
+ closed. */
+ current_time = grub_get_time_ms ();
+
+ if (current_time > (grub_last_time
+ + GRUB_CACHE_TIMEOUT * 1000))
+ grub_disk_cache_invalidate_all ();
+
+ grub_last_time = current_time;
+
+ fail:
+
+ if (raw && raw != name)
+ grub_free (raw);
+
+ if (grub_errno != GRUB_ERR_NONE)
+ {
+ grub_error_push ();
+ grub_dprintf ("disk", "Opening `%s' failed.\n", name);
+ grub_error_pop ();
+
+ grub_disk_close (disk);
+ return 0;
+ }
+
+ return disk;
+ }
+
+ void
+ grub_disk_close (grub_disk_t disk)
+ {
+ grub_partition_t part;
+ grub_dprintf ("disk", "Closing `%s'.\n", disk->name);
+
+ if (disk->dev && disk->dev->close)
+ (disk->dev->close) (disk);
+
+ /* Reset the timer. */
+ grub_last_time = grub_get_time_ms ();
+
+ while (disk->partition)
+ {
+ part = disk->partition->parent;
+ grub_free (disk->partition);
+ disk->partition = part;
+ }
+ grub_free ((void *) disk->name);
+ grub_free (disk);
+ }
+
+ /* This function performs three tasks:
+ - Make sectors disk relative from partition relative.
+ - Normalize offset to be less than the sector size.
+ - Verify that the range is inside the partition. */
+ static grub_err_t
+ grub_disk_adjust_range (grub_disk_t disk, grub_disk_addr_t *sector,
+ grub_off_t *offset, grub_size_t size)
+ {
+ grub_partition_t part;
+ *sector += *offset >> GRUB_DISK_SECTOR_BITS;
+ *offset &= GRUB_DISK_SECTOR_SIZE - 1;
+
+ for (part = disk->partition; part; part = part->parent)
+ {
+ grub_disk_addr_t start;
+ grub_uint64_t len;
+
+ start = part->start;
+ len = part->len;
+
+ if (*sector >= len
+ || len - *sector < ((*offset + size + GRUB_DISK_SECTOR_SIZE - 1)
+ >> GRUB_DISK_SECTOR_BITS))
+ return grub_error (GRUB_ERR_OUT_OF_RANGE, "out of partition");
+
+ *sector += start;
+ }
+
+ if (disk->total_sectors <= *sector
+ || ((*offset + size + GRUB_DISK_SECTOR_SIZE - 1)
+ >> GRUB_DISK_SECTOR_BITS) > disk->total_sectors - *sector)
+ return grub_error (GRUB_ERR_OUT_OF_RANGE, "out of disk");
+
+ return GRUB_ERR_NONE;
+ }
+
+ /* Read data from the disk. */
+ grub_err_t
+ grub_disk_read (grub_disk_t disk, grub_disk_addr_t sector,
+ grub_off_t offset, grub_size_t size, void *buf)
+ {
+ char *tmp_buf;
+ unsigned real_offset;
+
+ /* First of all, check if the region is within the disk. */
+ if (grub_disk_adjust_range (disk, §or, &offset, size) != GRUB_ERR_NONE)
+ {
+ grub_error_push ();
+ grub_dprintf ("disk", "Read out of range: sector 0x%llx (%s).\n",
+ (unsigned long long) sector, grub_errmsg);
+ grub_error_pop ();
+ return grub_errno;
+ }
+
+ real_offset = offset;
+
+ /* Allocate a temporary buffer. */
+ tmp_buf = grub_malloc (GRUB_DISK_SECTOR_SIZE << GRUB_DISK_CACHE_BITS);
+ if (! tmp_buf)
+ return grub_errno;
+
+ /* Until SIZE is zero... */
+ while (size)
+ {
+ char *data;
+ grub_disk_addr_t start_sector;
+ grub_size_t len;
+ grub_size_t pos;
+
+ /* For reading bulk data. */
+ start_sector = sector & ~(GRUB_DISK_CACHE_SIZE - 1);
+ pos = (sector - start_sector) << GRUB_DISK_SECTOR_BITS;
+ len = ((GRUB_DISK_SECTOR_SIZE << GRUB_DISK_CACHE_BITS)
+ - pos - real_offset);
+ if (len > size)
+ len = size;
+
+ /* Fetch the cache. */
+ data = grub_disk_cache_fetch (disk->dev->id, disk->id, start_sector);
+ if (data)
+ {
+ /* Just copy it! */
+ grub_memcpy (buf, data + pos + real_offset, len);
+ grub_disk_cache_unlock (disk->dev->id, disk->id, start_sector);
+ }
+ else
+ {
+ /* Otherwise read data from the disk actually. */
+ if (start_sector + GRUB_DISK_CACHE_SIZE > disk->total_sectors
+ || (disk->dev->read) (disk, start_sector,
+ GRUB_DISK_CACHE_SIZE, tmp_buf)
+ != GRUB_ERR_NONE)
+ {
+ /* Uggh... Failed. Instead, just read necessary data. */
+ unsigned num;
+ char *p;
+
+ grub_errno = GRUB_ERR_NONE;
+
+ num = ((size + real_offset + GRUB_DISK_SECTOR_SIZE - 1)
+ >> GRUB_DISK_SECTOR_BITS);
+
+ p = grub_realloc (tmp_buf, num << GRUB_DISK_SECTOR_BITS);
+ if (!p)
+ goto finish;
+
+ tmp_buf = p;
+
+ if ((disk->dev->read) (disk, sector, num, tmp_buf))
+ {
+ grub_error_push ();
+ grub_dprintf ("disk", "%s read failed\n", disk->name);
+ grub_error_pop ();
+ goto finish;
+ }
+
+ grub_memcpy (buf, tmp_buf + real_offset, size);
+
+ /* Call the read hook, if any. */
+ if (disk->read_hook)
+ while (size)
+ {
+ grub_size_t to_read = (size > GRUB_DISK_SECTOR_SIZE) ? GRUB_DISK_SECTOR_SIZE : size;
+ (disk->read_hook) (sector, real_offset,
+ to_read);
+ if (grub_errno != GRUB_ERR_NONE)
+ goto finish;
+
+ sector++;
+ size -= to_read - real_offset;
+ real_offset = 0;
+ }
+
+ /* This must be the end. */
+ goto finish;
+ }
+
+ /* Copy it and store it in the disk cache. */
+ grub_memcpy (buf, tmp_buf + pos + real_offset, len);
+ grub_disk_cache_store (disk->dev->id, disk->id,
+ start_sector, tmp_buf);
+ }
+
+ /* Call the read hook, if any. */
+ if (disk->read_hook)
+ {
+ grub_disk_addr_t s = sector;
+ grub_size_t l = len;
+
+ while (l)
+ {
+ (disk->read_hook) (s, real_offset,
+ ((l > GRUB_DISK_SECTOR_SIZE)
+ ? GRUB_DISK_SECTOR_SIZE
+ : l));
+
+ if (l < GRUB_DISK_SECTOR_SIZE - real_offset)
+ break;
+
+ s++;
+ l -= GRUB_DISK_SECTOR_SIZE - real_offset;
+ real_offset = 0;
+ }
+ }
+
+ sector = start_sector + GRUB_DISK_CACHE_SIZE;
+ buf = (char *) buf + len;
+ size -= len;
+ real_offset = 0;
+ }
+
+ finish:
+
+ grub_free (tmp_buf);
+
+ return grub_errno;
+ }
+
+ grub_err_t
+ grub_disk_write (grub_disk_t disk, grub_disk_addr_t sector,
+ grub_off_t offset, grub_size_t size, const void *buf)
+ {
+ unsigned real_offset;
+
+ grub_dprintf ("disk", "Writing `%s'...\n", disk->name);
+
+ if (grub_disk_adjust_range (disk, §or, &offset, size) != GRUB_ERR_NONE)
+ return -1;
+
+ real_offset = offset;
+
+ while (size)
+ {
+ if (real_offset != 0 || (size < GRUB_DISK_SECTOR_SIZE && size != 0))
+ {
+ char tmp_buf[GRUB_DISK_SECTOR_SIZE];
+ grub_size_t len;
+ grub_partition_t part;
+
+ part = disk->partition;
+ disk->partition = 0;
+ if (grub_disk_read (disk, sector, 0, GRUB_DISK_SECTOR_SIZE, tmp_buf)
+ != GRUB_ERR_NONE)
+ {
+ disk->partition = part;
+ goto finish;
+ }
+ disk->partition = part;
+
+ len = GRUB_DISK_SECTOR_SIZE - real_offset;
+ if (len > size)
+ len = size;
+
+ grub_memcpy (tmp_buf + real_offset, buf, len);
+
+ grub_disk_cache_invalidate (disk->dev->id, disk->id, sector);
+
+ if ((disk->dev->write) (disk, sector, 1, tmp_buf) != GRUB_ERR_NONE)
+ goto finish;
+
+ sector++;
+ buf = (char *) buf + len;
+ size -= len;
+ real_offset = 0;
+ }
+ else
+ {
+ grub_size_t len;
+ grub_size_t n;
+
+ len = size & ~(GRUB_DISK_SECTOR_SIZE - 1);
+ n = size >> GRUB_DISK_SECTOR_BITS;
+
+ if ((disk->dev->write) (disk, sector, n, buf) != GRUB_ERR_NONE)
+ goto finish;
+
+ while (n--)
+ grub_disk_cache_invalidate (disk->dev->id, disk->id, sector++);
+
+ buf = (char *) buf + len;
+ size -= len;
+ }
+ }
+
+ finish:
+
+ return grub_errno;
+ }
+
+ grub_uint64_t
+ grub_disk_get_size (grub_disk_t disk)
+ {
+ if (disk->partition)
+ return grub_partition_get_len (disk->partition);
+ else
+ return disk->total_sectors;
+ }
extern void (* EXPORT_VAR(grub_disk_firmware_fini)) (void);
extern int EXPORT_VAR(grub_disk_firmware_is_tainted);
-
+
-/* ATA pass through parameters and function. */
-struct grub_disk_ata_pass_through_parms
-{
- grub_uint8_t taskfile[8];
- void * buffer;
- int size;
-};
-
-extern grub_err_t (* EXPORT_VAR(grub_disk_ata_pass_through)) (grub_disk_t,
- struct grub_disk_ata_pass_through_parms *);
-
+ #if defined (GRUB_UTIL) || defined (GRUB_MACHINE_EMU)
+ void grub_lvm_init (void);
+ void grub_mdraid09_init (void);
+ void grub_mdraid1x_init (void);
+ void grub_raid_init (void);
+ void grub_lvm_fini (void);
+ void grub_mdraid09_fini (void);
+ void grub_mdraid1x_fini (void);
+ void grub_raid_fini (void);
+ #endif
+
#endif /* ! GRUB_DISK_HEADER */