Tuesday, January 05, 2021

Ethernet on the BananaPi M2 Zero

Even though it does not look like it does, the BPI-M2 Zero also has a wired ethernet interface. Unfortunately, it is disabled by default in its device tree blob.

But enabling it is easy:

# copy into /root
cp /boot/dtb/sun8i-h2-plus-bananapi-m2-zero.dtb .
# decompile
dtc -I dtb sun8i-h2-plus-bananapi-m2-zero.dtb \
    -O dts -o sun8i-h2-plus-bananapi-m2-zero.dts
# edit
vi sun8i-h2-plus-bananapi-m2-zero.dts # :-)
# compile
dtc -i dts sun8i-h2-plus-bananapi-m2-zero.dts \
    -O dtb -o /boot/custom.dtb
How do you need to edit the DTB file?

In the "ethernet@1c30000" block, you need to apply this "diff":

-       status = "disabled";
+       status = "okay";
+       phy-handle = <0x4d>;
+       phy-mode = "mii";
        phandle = <0x4b>;

The "phy-handle" value is taken from the "phandle" of the "ethernet-phy@1" block a few lines down. Then another change is adding an alias for ethernet0 to the "aliases" block:

       aliases { 

              serial0 = "/soc/serial@1c28000";
              serial1 = "/soc/serial@1c28400";
+             ethernet0 = "/soc/ethernet@1c30000";
       };

Ethernet will work without that, but we'll need this for setting the MAC address later.

Now reboot and try it out in a temporary way. Either by:

  • interrupting u-boot and doing setenv fdtfile custom.dtb (no "saveenv" yet!), then "boot"
  • editing the GRUB menu, adding an additional line after "initrd..." that reads devicetree /boot/custom.dtb
Check if the ethernet device eth0 appears after boot. If it does, the u-boot method can be persisted by issuing a saveenv command after the setenv.

Persisting the MAC address:
At my first tries I noticed that the MAC address was randomly assigned on every boot, in later experiments I could not reproduce this anymore but it looked like the MAC was at least reassigned on every deployment. I have no idea if this has to do with saving the environment in u-boot or if there is something in the userspace (a systemd service maybe?) that makes the MAC address semi-persistent. I decided to fix the MAC address once and for all, since I'm running a static DHCP setup, this is pretty important for my use case.

Because of the "ethernet0" alias in the device tree, persisting the MAC address is easy. All you need to do is setenv ethaddr 22:33:44:55:66:77 in u-boot and then persist this with saveenv and you are done. Note that u-boot has some precautions to disallow changing the MAC address later by accident so you are not able to easily undo this later. You can always remove "/boot/efi/uboot.env" in your booted system or by inserting the SD card into another machine and start from scratch.

Sunday, January 03, 2021

GRUB, u-boot, kernels and DTB loading (on the BPi M2 Zero and others)

While I was experimenting with the BananaPi M2 Zero board, I soon needed to adopt its device tree file (dtb).

Fortunately, the friendly members of the openSUSE:Factory:ARM community quickly hinted me at the grub2 "devicetree" command which can be specified similar to "linux" or "initrd" to name a file that's loaded as device tree.

Unfortunately, there is no way to make this really persistent, short of editing the grub generator scripts which will get lost on every grub2 update.

The other option would be to decompile the board's DTB file ("/boot/dtb/sun8i-h2-plus-bananapi-m2-zero.dtb" in my case), change and then recompile it, replacing the original file. This has two downsides: first, it will get overwritten with every update of the "dtb-sun8i" package (no idea how often this will be the case) and second, you might want to have the original file as fallback ready. In general, editing package managed files is not a good idea in my book, if it can be avoided it should be.

So I looked into the "who loads which device tree file" and found out that actually the dtb is loaded by u-boot, even before grub starts. U-boot has the name of the board built-in and thus the file name it is looking for. Additionally it has a search list of directories that it searches to find the dtb file. So the simplest way to apply your own dtb file would probably be to put it, with the original file name into the search path after the original file. I tried this approach at first, but then went for explicitly specifying a different filename, which is just not as subtle in case you need to debug this years later ;-)

So the method is relatively easy:

  1. put your modified dtb file into /boot, I named it custom.dtb.
  2. boot into u-boot, interrupt booting on the serial console
  3. in u-boot console, enter setenv fdtfile custom.dtb
  4. in u-boot console, enter saveenv
That's it. Now boot and verify that your dtb file is used.

Note that the u-boot environment is saved on the EFI partition of the SD card (first partition, FAT format) as file "uboot.env". If you need to reset the environment to the built-in defaults, then you can always mount the SD card in another machine and move away or delete uboot.env.


Saturday, January 02, 2021

openSUSE Tumbleweed on the Banana Pi BPI-M2 ZERO

This is the first post of a small series about openSUSE on the Banana Pi BPI-M2 ZERO.

Preface

I recently got myself a Banana Pi M2 Zero board while ordering other stuff at an electronics distributor. The M2 zero is the same form factor and feature set as the Raspberry Pi Zero W (the GPIO pin headers are said to be compatible, it has WiFi and Bluetooth built in and an USB OTG port). The CPU is an Allwinner H2+, a quad-core ARM processor running a 1GHz clock speed, RAM size is 512MB. Processing power is probably comparable to a Raspberry Pi 2 board.

I bought the M2 Zero to use it with an RTLSDR stick to receive the signal of my outside RF temperature sensor. This worked with the Raspberry Pi Zero W, but was a bit too much for the slower CPU which has other more important things to do anyway (playing internet radio ;-), so the M2 Zero was a cheap, more powerful alternative. The box will be running headless and thus I do not care about support for graphics and multimedia anyway.

In the end, I switched the RF receiver to a RaspyRFM board whih is using less energy and simpler to use than an RTLSDR stick just to receive some sensors and now the M2 Zero board is free for tinkering...


openSUSE on the M2 Zero

There was already an image available for the Banana Pi M2 Plus (called "sinovoipbpim2plus"), which is the "bigger brother" of the M2 zero, but that image did not boot. Experimenting with the u-boot image from armbian lead to success in "openSUSE Tumbleweed boots with armbian u-boot". Thanks to the friendly openSUSE ARM community, a matching u-boot version for the M2 Zero was built quickly and I could submit the updated image in OBS to get an image ready for the board (called "sinovoipbpim2zero").

Some small things are still to be sorted out, this is why I would suggest you use the image from the home:seife:bananapi repository for now. Since the board has only WiFi networking (more on that in a later post...), you'll need a serial console wired up for initial setup and I strongly suggest to use at least the "openSUSE-Tumbleweed-ARM-X11-..." image and not the JeOS image, since JeOS does not contain NetworkManager and using WiFi with wicked (actually using anything with wicked) is not fun.

So put the image on the SD card, connect the serial console, boot the box up. Log in as root. WiFi connection is easily established then:

nmcli dev wifi connect YOUR_SSID password YOUR_PASSWORD

That's it, have fun! ;-)



Addon note: When I started to write this post, my home:seife:bananapi repo was necessary for actually getting WiFi to work (contained a fixed kernel-firmware package). This has all been submitted to upstream or openSUSE:Factory:ARM now. All that's "special" in my repo now is a slightly extended package selection in the image (the "dtc" package is included) and a fixed config.sh script that makes NetworkManager actually work correctly, including name resolution, see boo#1180234 for details), so the image from openSUSE:Factory:ARM should be "good enough" for most uses already and in the near future I'll probably retire the home:seife:bananapi project or use it just for development stuff).

Tuesday, June 23, 2020

Brother MFC-L2710DW Printer / Scanner and Linux

I needed a new scanner, my old HP PSC-1510 finally broke..
I wanted a multi-function device with ethernet, non-color laser printer with duplex printing and a scanner with ADF. For ease of use, I wanted a "scan to network drive" and "scan to email" capable device, so that my users at home can easily help themselves without me having to scan every document for them.

The Brother MFC-L2710DW seemed to fit the bill pretty well.
Only after having it all set up, I found out that the "Scan to email" only works with a Windows PC, and apparently only with the device connected via usb, by somehow firing up Outlook to send the mail, and the "scan to network drive" also seems to work the same way.

The next thing I found out is, that the printer works with CUPS, but you need a binary only driver from Brother (at least if you follow all the HOWTOs on the internet) and the scanner unit also seemed to need a binary only sane backend. Not much more and I would have almost immediately put up the device on ebay just to get rid of it as fast as possible.

But then I noticed that the thing is AirPrint and AirScan capable and I found out that no MacOS drivers were included...

Long story short: AirScan is some http based protocol (named eSCL) for basic scanning. With some curl magic you can scan (from standard glass or ADF) to either (at least) JPEG or PDF. When scanning from ADF, you even get a multi-page PDF directly. There is an "escl" backend in latest SANE (but not in Leap 15.2). However, this did not work well for me. Then I found the excellent "sane-airscan" project on github which works fine, and which serves both as a working SANE backend and as a good documentation on the protocol, which I used to write a standalone tool "simple-airscan" in python, which I'll probably put into a small simple webfrontend, so that my users can help theirselves with their scanning needs.

Ok, scanning works. What about printing?
Airprint has some "driverless" mode, which I was unable to configure with YaST, but it was easy to configure after I enabled the CUPS web frontend. This works without any ugly brother binary only drivers and prints just fine.

So now both the scanner and the printer work just fine without any brother software ;-)

Links:
https://github.com/seife/airscan-simple - my simple python scanning tool.
https://github.com/alexpevzner/sane-airscan - the excellent sane-airscan backend for SANE.
https://wiki.debian.org/CUPSDriverlessPrinting - the debian wiki has extensive information on driverless printing

Thursday, March 26, 2020

Windows 10 update error 0x800f0922

First: sorry for the OT ;-)

A Thinkpad of mine that has Windows 10 co-installed was refusing all cumulative Windows updates since about 6 months, always performing everything, rebooting, counting up to 99%, then failing with error 0x800f0922 and rolling back.
Now this Windows instance is not really used and thus not booted on a regular base, but I'd still rather keep it up to date in case I somewhen really need it for something.

So I searched the internet for error 0x800f0922... and tried almost everything that was mentioned as a possible fix:

  • resetting windows update
  • uninstalling various pieces of software
  • in general, random changing of different settings ;-)
Nothing helped. Until I found a short comment under some blog post hidden in the vast voids of the internet, that mentioned that the problem could be solved by not booting via grub but instead directly activating the windows boot partition.

Could it be that easy? Yes. Rebooted into Linux, deactivated /dev/sda3 and activated /dev/sda1 with fdisk, rebooted and Windows is now updating happily ever after...

Sunday, March 22, 2020

Leap 15.2 Beta: mariadb upgrade woes

I'm running a server at home with openSUSE Leap, and since Leap 15.2 is now in beta, I thought it was a good idea to update and take part in the beta testing effort.
This machine is running an Owncloud instance, serving some internal NFS shares and used as a development machine for (cross-)compiling stuff, packaging etc.

The update went pretty smooth, only the mariadb instance used by Owncloud was hosed afterwards. There was no login possible and generally database users were gone.
Fortunately, I always have recent backups available, both a mysqldump and a complete file system backup.

So I tried to just restore the mysqldump on the updated database. This did not work, Bug#1166786.
Then I did just restore the filesystem backup of /var/lib/mysql and the database worked again.
Unfortunately, as I found out reproducing and investigating the issue, it would just get killed again by the next update, Bug#1166781. (Extra kudos to openSUSE Product Management which decided that this is not a bug, but instead regarded a feature!).

Finally I found the upstream bug in mariadb JIRA bugtracker, (which also does not look like there is much interest in fixing this), but with the information given there, I was able to fix this for me.

So all of you who are stuck with
ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: YES)
after updating a mariadb instance to 10.4, this might help:

  1. restart mysqld with option --skip-grant-tables, to disable user authentication
  2. in the mysql database, execute
    • ALTER TABLE user CHANGE COLUMN `auth_string` `authentication_string` text;
    • DROP TABLE global_priv;
  3. now run the mariadb-upgrade command
  4. restart mariadb.service with default options
This fixed my instance and owncloud is working again.

Note that I am by no means a database expert. Take backups before performing these steps.

Tuesday, January 21, 2020

Fun with grub2-install "not a directory"

These days, I came across spontaneous kiwi image build failures in a private OBS instance.
The images were SLES15-SP1, they had not been touched for quite some time, rebuilds were only triggered due to new packages in the update channel.
The error was grub2-install failing with the error message "not a directory".
Looking at the recent changes in the update repo showed no obvious reason (some python packages that had nothing to do with grub2-install), so I started to investigate...

... 3 days later, after following some detours, I finally found the issue.

grub2-install scans the installation device for filesystems, and probes all known (to grub2) fs types. The probe of "minix_be" fails fatally. Sometimes.

After building my own grub2 package with lots of debug-printf's, I finally found out, that the minix fs detection of grub2 is a little "fragile". It does the following (pseudo code):
  • grub_mount_minix(device) || return "not minix fs"
  • grub_minix_find_file("/") || fatal_error()
The problem is, that grub_mount_minix() only does pretty simple magic numbers checks, which can lead to false positives.

Comparing the superblock structures of ext[234] and minix filesystems (from the grub2 source code) side by side, you see this:

struct grub_minix_sblock         |struct grub_ext2_sblock
{                                |{
  grub_uint16_t inode_cnt;       |  grub_uint32_t total_inodes;
  grub_uint16_t zone_cnt;        |
  grub_uint16_t inode_bmap_size; |  grub_uint32_t total_blocks;
  grub_uint16_t zone_bmap_size;  |
  grub_uint16_t first_data_zone; |  grub_uint32_t reserved_blocks;
  grub_uint16_t log2_zone_size;  |
  grub_uint32_t max_file_size;   |  grub_uint32_t free_blocks;
  grub_uint16_t magic;           |  grub_uint32_t free_inodes;
};

This already hints at the issue: at the same disk location where ext2 stores the free inodes number, minix stores its magic number, which is used by grub to detect if it is a minix file system.

Now if you happen to have an ext3 file system with a free_inodes number whose lower 16 bits resemble one of the GRUB_MINIX_MAGIC numbers, chances are grub_mount_minix() will succeed, but then the attempt to acces the root directory will fail with a fatal error.

This is a plain grub2 bug, which I will probably report upstream and try to get fixed.
However, I need a fix to have my images build again, and the chances of getting a fix into SLES15-SP1 are ... low (and it is a daunting task, even if you are reporting this bug as a big SLES customer), so I built a workaround in my (locally built, lucky me...) python-kiwi package.

It basically does the following, before calling the "chroot grub2-install ...".

  • statvfs() to get the free_inodes number
  • check if the lower 16 bits resemble one of the MINIX_MAGIC numbers
    • if it does, touch a temporary file in
    • unmount and mount again to update the superblock (I missed this at first and wondered why it did not work)
    • unlink the temporary file
  • continue as before
This workaround is ugly as hell, but it does work for me.

P.S.: the detours included first noticing that almost every change I made to the image, like wrapping grub2-install into a wrapper script for debugging) made the issue go away (because of a different free_inodes number), so I always needed to check after every change that the issue was still present, then finding that copying the locales in grub2-install actually triggers an ENOTDIR - "Not a directory", because it misses special handling the /usr/share/locale/locale.alias file. Of course I thought "this is the issue" and patched it out of grub2, just to find that the original problem still persisted... then overnight package updates in SLES15-SP1 making this problem go away and reappear seemingly random... you guess it 😄