Long time no see

I have been away for a while as I attended a Permaculture Design Course (PDC). For those among you that do not know, Permaculture is basically the art of hacking natural ecosystems in order to make them run without our constant intervention while still being productive.

Although many talks where related to gardening and agriculture, there was substantial amount of time devotes to sustainable construction: talks about alternative energy, eco-construction, water treatment and similar topics. If I ever get the time, I will post some of the things I saw/tinkered with.

For now, check out Hack a Day’s latest feature run, sustainable hacks!

The battle againt the BMC – Part 2

Update 4/11/2011: I managed to find out some more info about the packaging scheme Dell uses for their BMC firmware files. I deciphered most of the container format. I am in the process of testing modifications right now, but for the moment I updated the version of the tool below with a new version. You can also download the program directly here: dell-extract-bmc-firmware.tar.gz.

Firmware header

Deciphering the firmware header.

As mentioned earlier, I started to look into hacking the BMC firmware in order to solve my problem of the hard-coded failure thresholds of my PowerEdge 2800.

I had a look into the firmware flash file, and noticed that it seems to consist of several files (as usual for BIOS/firmwares). As this might increase my chances not to brick my BMC, I decided to I separate the individual files for starters. I couldn’t find a program that does that (the firmware tools of the Dell linux community are closed-source, unfortunately), so I grabbed a hex-editor and deciphered (more or less) the firmware’s header. Here’s the corresponding C program:

// vim: ts=4 ai noexpandtab nopaste
/**
 * This program can extract and check the different files contained in a firmware file
 * for a Dell PowerEdge BMC.
 */

#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>

typedef struct
{
    uint8_t     hex02;
    uint8_t     numBlocks;  // number of subfiles in system
    uint32_t    filesize;
    uint16_t    zero;
    char        dellHeaderStr[9];
} header_t;

typedef struct
{
    uint8_t     zero1;
    uint8_t     type;       // 0x000b -> SD_${system}.FLC
    uint8_t     zero2;
    uint8_t     system;     // 0, 1, 2
    uint8_t     zeros[3];
    uint16_t    unknownFixedData;
    uint16_t    crc16;
    uint32_t    length;
    uint32_t    offset;
    char        filename[32];
} flc_block_t;
// 4x1+3x1+2+2+4+4+32=51

uint16_t endian_swap16(uint16_t x)
{
    return (x>>8) |
           (x<<8);
}

uint32_t endian_swap32(uint32_t x)
{
    return (x>>24) |
            ((x<<8) & 0x00FF0000) |
            ((x>>8) & 0x0000FF00) |
            (x<<24);
}

/** CRC table for the CRC-16. The poly is 0x8005 (x^16 + x^15 + x^2 + 1) */
uint16_t const crc16_table[256] = {
        0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
        0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
        0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
        0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
        0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
        0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
        0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
        0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
        0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
        0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
        0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
        0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
        0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
        0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
        0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
        0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
        0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
        0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
        0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
        0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
        0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
        0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
        0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
        0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
        0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
        0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
        0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
        0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
        0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
        0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
        0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
        0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
};

static inline uint16_t crc16_byte(uint16_t crc, const uint8_t data)
{
    return (crc >> 8) ^ crc16_table[(crc ^ data) & 0xff];
}

uint16_t calccrc16(uint8_t const *buffer, size_t len)
{
    uint16_t crc = 0x0000;

    while (len--)
        crc = crc16_byte(crc, *buffer++);
    return crc;
}

int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        fprintf(stderr, "Usage: %s <firmware>\n", argv[0]);
        exit(1);
    }
    FILE* flashFile = fopen(argv[1], "r");

    // get filesize
    fseek(flashFile, 0, SEEK_END);
    uint32_t filesize = ftell(flashFile);
    fseek(flashFile, 0, SEEK_SET);

    // read the header
    header_t header;
    if (fread(&header, sizeof(header_t), 1, flashFile) == 0)
    {
        fprintf(stderr, "Error: Can't read header.\n");
        exit(1);
    }

    // check that it's a valid header as far as we know
    if (header.hex02 != 0x02 ||
        header.zero != 0 ||
        filesize != header.filesize ||
        strncmp(header.dellHeaderStr, "DELL_INC", 8) != 0)
    {
        fprintf(stderr, "Error: Header not valid.\n");
        exit(1);
    }

    // calculate header crc
    fseek(flashFile, 0, 0);
    uint16_t totalHeaderSize = sizeof(flc_block_t) * header.numBlocks + sizeof(header_t);
    uint8_t headerBuf[totalHeaderSize];
    fread(&headerBuf, totalHeaderSize, 1, flashFile);
    uint16_t headerCRC16 = calccrc16(headerBuf, totalHeaderSize);

    // calculate total file crc
    fseek(flashFile, 0, 0);
    uint8_t fileBuf[header.filesize-2];
    fread(&fileBuf, header.filesize-2, 1, flashFile);
    uint16_t fileCRC16 = calccrc16(fileBuf, header.filesize-2);
    uint16_t fileCRC16Dell;
    fread(&fileCRC16Dell, 2, 1, flashFile);
    printf("\n\n");
    printf("Valid Dell PowerEdge BMC firmware header found:\n\n");
    printf("  - number of blocks : %d\n",   header.numBlocks);
    printf("  - oemstr (fixed)   : %s\n",   header.dellHeaderStr);
    printf("  - total file size  : %d\n",   header.filesize);
    printf("  - total header size: %d\n",   totalHeaderSize);
    printf("  - header CRC16     : 0x%04x\n",   headerCRC16);
    printf("  - total file CRC16 : 0x%04x\n\n", fileCRC16);
    if (fileCRC16 == fileCRC16Dell)
       printf("  * CRC16 check OK\n");
    else
       printf("  * CRC16 check FAILED, actual CRC16 is 0x%04x instead of 0x%04x\n", fileCRC16, fileCRC16Dell);

    printf("\n\n");

    // read all blocks
    fseek(flashFile, sizeof(header_t), 0);
    flc_block_t flcBlock[header.numBlocks];
    fread(&flcBlock, sizeof(flc_block_t), header.numBlocks, flashFile);

    uint8_t i;
    for (i = 0; i < header.numBlocks; i++)
    {
        // check if our understanding of format is correct
        if (flcBlock[i].zero1 != 0 || flcBlock[i].zero2 != 0 || flcBlock[i].zeros[0] != 0 ||
            flcBlock[i].zeros[1] != 0 || flcBlock[i].zeros[2] != 0)
        {
            fprintf(stderr, "Error: Block %d not valid.\n", i);
            exit(1);
        }

        printf("Block %d:\n\n", i);
        printf("  - type     : %d/0x%02x (defines block type, 0x0b is sensor data table)\n", flcBlock[i].type, flcBlock[i].type);
        printf("  - system # : %d/0x%02x (running number for systems in this firmware file)\n", flcBlock[i].system, flcBlock[i].system);
        printf("  - unknown  : %d/0x%04x (always same for all blocks in a single firmware file)\n", flcBlock[i].unknownFixedData, flcBlock[i].unknownFixedData);
        printf("  - offset   : %d\n", flcBlock[i].offset);
        printf("  - length   : %d\n", flcBlock[i].length);
        printf("  - filename : %s\n\n", flcBlock[i].filename);

        // extract the block according to the offset and length given in the block desc.
        printf("  * extracting block...");
        char* blockData = (char*) malloc(flcBlock[i].length);

        fseek(flashFile, flcBlock[i].offset, 0);
        fread(blockData, flcBlock[i].length, 1, flashFile);

        FILE* blockFile = fopen(flcBlock[i].filename, "w");
        fwrite(blockData, flcBlock[i].length, 1, blockFile);
        uint16_t blockCRC16 = calccrc16(blockData, flcBlock[i].length);
        fclose(blockFile);
        free(blockData);
        printf("done.\n");

        if (blockCRC16 == flcBlock[i].crc16)
          printf("  * CRC16 check OK\n");
        else
          printf("  * CRC16 check FAILED, actual CRC16 is 0x%04x instead of 0x%04x\n", blockCRC16, flcBlock[i].crc16);

        printf("\n\n");
    }

    fclose(flashFile);
    exit(0);
}

The names of the individual files are listed below. They are organized in blocks (that’s what I call them), and apparently by function. Get the latest BMC firmware (30/6/2009, v1.83, A10) and apply my program to retrieve the individual files.

  • block 0 (code, big files):
    • BB.FLC
    • OB.FLC
    • ID.FLC
    • OEM_DEF.FLC
  • block 1 (*_BB files):
    • SD_BB.FLC
    • FI_BB.FLC
    • TOC_BB.FLC
    • IO_BB.FLC
    • IS_BB.FLC
    • OEM_BB.FLC
  • block 2 (*_K_C files):
    • SD_K_C.FLC
    • FI_K_C.FLC
    • TOC_K_C.FLC
    • IO_K_C.FLC
    • IS_K_C.FLC
    • OEM_K_C.FLC

The BMC seems to be little-endian (makes only sense I guess). I’ve scanned the different files for appearances of the threshold values (900 and 2025/0x07e9 and 0×0384 in int and 0×6144000 in float). No avail. Darn. Either I am doing something wrong or the thesholds are not hard-coded in the firmware (I had my hopes up when I saw the OEM_DEF.FLC file, which actually contains the default BMC password and the like). Maybe the thresholds are stored in the configuration flash after all – only how can we access it?

Update

I finally managed to adjust the critical fan thresholds by patching the BMC firmware! Here’s the howto. Additionally, I created a project page for my server.

The battle againt the BMC – Part 1

Earlier, I wrote about the problem of the noisy fans in my Dell PowerEdge 2800. Since then, I investigated a bit more. Just as a reminder: I can’t run silent fans because they have a lower RPM than a hardcoded panic-threshold of the PowerEdge. *grrr*

Brainstorm:

  1. make the fans faster/buy faster fans
  2. make the system hotter
  3. hack the fans into reporting more RPM than they actually do
    1. hack the fans themselves
    2. alter their tacho signal
  4. hack the BMC
  5. find out how the OEM sets these thresholds

Well, as I mentioned earlier 1. and 2. are for obvious reasons dissatisfactory.

Couple of fans taken apart

A couple of fans taken apart. Notice the blob of brown paint on the ring magnet of the fan on the right.

Concerning 3A, I took a couple of fans apart, looking at how they create the tacho signal. Almost all fans I opened (luckily I have a whole stack of noisy, throw-away fans lying around) have a sensor sitting just under the ring magnet, which is part of the rotor as can be seen in the photo on the right. I had no idea what this sensor might be, but I noticed on all of the fans one or more blows of brownish-red paint. I figured that this paint might be used to create a signal for the sensor – and I did some tests with other paint in order to replicate the effect (left fan on the photo with magnetic paint applied). Well, nice idea, but total bullshit as it turns out. The sensor is a hall-sensor that senses the change in the magnetic field of the ring-magnet, and thus changes inevitable 2 times per revolution. I figure that the paint applied on the rotor is used for calibrating the fans… Well, it was a nice idea.

3B might be an option, but it would require either a microcontroller or some analogue circuit – not really what I want to fiddle into the fan trays of 6 fans.

Concerning option 5, I thought that there may be hidden ipmi OEM commands for configuring the thresholds. I dug around the Dell OEM extensions for ipmitool (can be retrieved from the Dell Linux Community Repositories). This code officially earned worst code of the year – I completely understand why the ipmitool maintianers flatout refuse to integrate that piece of crap. It’s a hacked-up collection of extensions, seemingly done on the fly to fix customer problems. Horrible. Even more so as it does not seem to be able to set the thresholds either. After a few hours of digging in the code I managed to query the BMC sensors with Dell’s OEM commands, and the returned capability flags do indicate that the thesholds cannot be changed. Darn.

Now I am back to hacking the BMC firmware – but that’s for another post…

Update

I finally managed to adjust the critical fan thresholds by patching the BMC firmware! Here’s the howto. Additionally, I created a project page for my server.

Latex+Beamer+PDF+embedded movies

Finally I found a way to embed videos into Latex-generated PDFs in a platform-independent way!

Download and install flashmovie.sty:

wget http://mirror.ctan.org/macros/latex/contrib/flashmovie.zip
unzip flashmovie.zip
cp flashmovie/flashmovie.sty $YOUR_TEX_DOCUMENT_DIR

Additionally, you need a flash-based video player. Free option:

cp flashmovie/flashmovie/player_flv_maxi.swf $YOUR_TEX_DOCUMENT_DIR

I preferred the Longtail Video Player which is free for personal use:

wget http://www.longtailvideo.com/jw/upload/mediaplayer.zip
unzip mediaplayer.zip
cp mediaplayer-5.7/player.swf $YOUR_TEX_DOCUMENT_DIR

This is the mencoder command I use for converting my videos:

mencoder -nosound -forceidx -of lavf -ovc lavc -lavcopts vcodec=flv:vbitrate=2500:mbd=2:mv0:trell:v4mv:cbp:last_pred=3 -o video.flv video.avi

And finally, a bare example showing how to create an embedded, full-screen movie in a presentation using the beamer package:

\RequirePackage{flashmovie}
\documentclass[utf8x]{beamer}
\usepackage[absolute,overlay]{textpos}
\setlength{\TPHorizModule}{1mm}
\setlength{\TPVertModule}{1mm}

\begin{document}
  \begin{frame}[plain]
    \begin{textblock}{12.8}(0,0)
      \flashmovie[auto=1,loop=1,controlbar=0,engine=jw-player,width=12.8cm,height=9.6cm]{taros_talk.flv}
    \end{textblock}
  \end{frame}
\end{document
}

The options are pretty much self-explanatory. Ah yes, the whole thing needs an Adobe Reader >=9.0.

Update: The latest version of Adobe Reader for Linux (9.4-2) gives a “3D parsing error” upon opening a page with an embedded flash video. Downgrade to 9.4-1 (Ubuntu package name is acroread_9.4-1, you can get it here) and everything’s fine

Minecraft on Linux

Minecraft Logo
I struggled to get Minecraft up and running on my laptop (Ubuntu 10.04). I copied an older user folder from a windows machine, and nothing worked – I only got a black screen after starting the game. This seems to be quite common, and seems to be cause by library mismatches.

There are a million complicated howtos out there how to fix this, but for me it was sufficient to let Minecraft re-download all its libraries:

$ rm -rf ~/.minecraft/bin

Then, start the game and wait for the download to finish. Et voila!

The folder on windows is %APPDATA%\Roaming\.minecraft\bin\. An alternative route is to select “force update” in the Minecraft option screen.

Dell DRAC/Remote Console discoveries

1. Logout else lockout

The system has usually a limited number of users, and if you don’t logout properly multiple times you find yourself in the position that all slots have been taken. In this case, you have to wait for a timeout…

2. Firefox & Java

On Linux, the only supported browser is Firefox. On standard Ubunut, this does not work in combination with the DRAC as Ubuntu installs the Icetea Java plugin by default. Switch to the Sun Java plugin:

sudo update-alternatives --set mozilla-javaplugin.so /usr/lib/jvm/java-6-sun/jre/lib/i386/libnpjp2.so

3. Firewalls

On many systems, you will have problems to access the DRAC (or at least the remote console) because of firewalls in your way. You can forward the whole thing by using a host inside the network as an proxy. For this, you have to tunnel the connections through SSH as follows:

sudo ssh -L 443:<DRAC_IP>:443 -L 5900:<DRAC_IP>:5900 -L 5901:<DRAC_IP>:5901 -l <LOGIN> -N <SSH_PROXY_SERVER> -o ExitOnForwardFailure=yes

Update: I created a project page for my server.

Those darn fans!

As I explained before, I changed all the fans of my PowerEdge 2800 to low-noise, low-RPM models.

Fans of a PowerEdge 2800

The fans of my PowerEdge 2800. Front the cpu fans (stock Delta left, replacement everflow right); at the back the 120mm case fans (left the Artic, right the stock Nidec)

This was nice and shiny, and the system was quiet and quite cool. Too cool unfortunately, because the BMC throttles the fans too much so that their RPM values go below the configured thresholds. Then, the system goes into panic mode, spins up all fans at 100%, and lowers them successively below the threshold again. Repeat. :)

I ended up putting the Delta’s back in, because you cannot configure the lower failure threshold of the fans. So, lots of work for nothing, and the system is still way too loud. Very unsastifactory.

Thus, I started thinking how to get around this problem. Possible ways I see:

  1. make the fans faster/buy faster fans
  2. make the system hotter
  3. hack the fans into reporting more RPM than they actually do
  4. hack the BMC
  5. find out how the OEM sets these thresholds

Well, 1. and 2. are for obvious reasons dissatisfactory.

Regarding 3: I thought about getting the sensor in the fan to report a higher value. Most fans actually consist of a ring-magnet. The sensor lies just below it, with the rotating magnet passing over it. On 1-4 places on the magnet, the manufacturers apply some paint. I guess it’s some sort of EMI shield and the sensor detects the change in the field – but I couldn’t find any paint that would reproduce the effect. This would be a very neat and nice solution.

Regarding 4: The BMC is implemented in some microcontroller on the motherboard of the PowerEdge. I haven’t found out yet where it is. I am not even sure what type of architecture it is, so reverse engineering the BMC firmware wasn’t possible. Damn, I don’t even know if this is little-endian or not.

Regarding 5: The manual states that these values are read-only and are to be configured by the OEM. But how? I doubt that they create a new firmware for each combination of fan manufacturers that they use. So my guess is that there are some hidden OEM IPMI commands that allow to set the threshold. I asked the guys over at FreeIPMI if they’ve got a clue, but they don’t know about any such functionality.

Anyone out there with some hints?

UpdateI continued my search for a solution

Update 2

I finally managed to adjust the critical fan thresholds by patching the BMC firmware! Here’s the howto. Additionally, I created a project page for my server.

Mute sound on screen lock

My coworkers got annoyed that my music continued playing when I was away from my desk. As I am anyways locking the screen automatically after 5 minutes (if I forget to do it by keyboard shortcut), I thought I might use this event for muting as well.

Below is the script I came up with. It needs the inotify-tools (sudo apt-get install inotify-tools) to work. Thanks to Vermind on the ubuntuforums for figuring out the mute stuff!

The advantage of this script is that it works with the auto-lock of the screensaver as well as the pre-configured shortcuts for screen locking.

#!/bin/bash
################################################################################
# mute-on-lock.sh
# Mutes sound and pauses amarok when the screen gets locked
# Version 1.0
#
# written by Arnuschky, mute stuff by Vermind (ubuntu forums)
#
# http://ubuntuforums.org/showthread.php?t=1364597
################################################################################

########################################
# Settings
########################################

mute=1            # Mute the sound while locked. 0=do not mute.
amarok=1          # Pause/unpause amarok on lock
card=0            # Sound card. 0 == default, first card.
channel="Master"  # Which volume to control. Examples: Master, PCM, Headphone
step=3            # Fade step: The volume increment/decrement amount
interval=0.2      # Seconds between increments/decrements when fading


########################################
# Functions
########################################

# get current volume
function getvol {
    vol=$( ${m} sget ${channel} | awk '
$0 ~ "%" {
    if ($4 ~ "%") {
        print $3;
    } else if ($5 ~ "%") {
    print $4;
    exit 0;
    }
}'
)
}

# fades volume up or down
function fade {
    # get current volume
    getvol
    if [ "$1" == "down" ]; then
        # fade down:
        while [ ${vol} -gt 0 ]; do
            ${m} set ${channel} ${step}- >/dev/null
            let vol-=${step}
        sleep ${interval}
        done
        ${m} set ${channel} mute >/dev/null
   else
       # first unmute, then fade up
        ${m} set ${channel} unmute >/dev/null
        while [ ${orig} -gt ${vol} ]; do
            let vol+=${step}
            if [ ${vol} -gt ${orig} ]; then vol=${orig}; fi
            ${m} set ${channel} ${step}+ >/dev/null
            sleep ${interval}
        done
        ${m} set ${channel} ${orig} >/dev/null
   fi
}

########################################
# Startup
########################################

if [ "${mute}" == "1" ]; then
    # short mixer command with card
    m="amixer -c ${card}"
    # record original volume value
    getvol
    orig=$vol
fi

########################################
# Loop                                 #
########################################

# start dbus monitor
monitorfile=`mktemp`
dbus-monitor --session "type='signal',interface='org.gnome.ScreenSaver',member='ActiveChanged'" &> ${monitorfile} &
pid=$!

# loop on changes on the monitorfile
while inotifywait -e modify ${monitorfile} &> /dev/null; do
  # on file change, grab the last line and filter it
  lastline=`tail -n1 ${monitorfile}`
  echo ${lastline} | grep -e "boolean true" -e "boolean false" &> /dev/null
  if [ $? -ne 0 ]; then
    continue
  fi

  # grab the lock state and act on it
  lockstate=`echo ${lastline} | sed 's/^.*boolean \(.*\)/\1/'`
  if [ ${lockstate} == "true" ]; then
    if [ "${mute}" == "1" ]; then
      fade down
    fi
    if [ "${amarok}" == "1" ]; then
      amarok --pause
    fi
  elif [ ${lockstate} == "false" ]; then
    if [ "${amarok}" == "1" ]; then
      amarok --play
    fi
    if [ "${mute}" == "1" ]; then
      fade up
    fi
  fi
done

# kill monitor & cleanup
kill $pid
rm -f ${monitorfile}

exit 0

How to install this? Put it into e.g. /home/youruser/bin/mute-on-lock.sh. Then, go to System -> Preferences -> Startup Applications and add your script. Log in& out and you’re done!

Replacing the fans on a Poweredge 2800

Fans of a PowerEdge 2800

The fans of my PowerEdge 2800. Front the cpu fans (stock Delta left, replacement everflow right); at the back the 120mm case fans (left the Artic, right the stock Nidec)

My “new” PowerEdge was way too loud. Like, jumbo-loud. I’ve chosen to replace all the fans with quieter models, but oh boy, this turned out to be a major pain! As always, I didn’t follow the most important rule when tinkering: do stuff incrementally, and test after each step. Well, maybe I’ll learn someday.

For reference, here the fan models:

Funtion Dell Replacement
4x Memory/Disk, 120x120x32mm, PWM Nidec Beta V TA350DC, M34789-35 Arctic F9 PWM
2x PSU, 60x60x25mm, Tacho Nidec Beta V TA225DC, B34605-33 Akasa AK-192BKT-B
2x CPU, 60x60x35mm PWM Delta AFB0612EHE Everflow F126025BU

I’ve changed all the fans in one go and ended up with a system that didn’t boot anymore. It didn’t even get to the end of the BIOS initialization, it shut down directly. I gathered that it must be the power supply’s fans (else I would have had a warning message on the POST). I’ve checked and I realized that I bought some fans with a build-in thermal control; a sensor that slows down the fan rotation. Well, as I had them already I hacked them up to ignore the sensor (cracked open sensor casing, soldered two pins together; no resistance acts as if the sensor measures a very high temperature).

Connector for PowerEdge 2800 fans

The connector with the soldered cables of the everflow fan. Here, the yellow and blue cable on the connector has been switched.

Next problem was that all fans spun at full speed. Impressively noisy, even for a seasoned cluster admin as me (I could hear the vibration 2 floors below). The reason were swapped PWM and Tacho pins (as I’ve found out after trying for a night to install Dell OpenManage 6.4 on Ubuntu 11.04 64bit). I don’t know why, but I needed different PIN configurations that every other source I’ve found on the Internet. Here’s what I’ve used in the end (This is looking on the bottom of the connector):

+---+---+
| 2 | 1 |-+
+---+---+ |
| 4 | 3 |-+
+---+---+
Pin Funtion Dell Everflow Arctic
1 VCC red yellow red
2 Control/PWM blue blue blue
3 Ground black black black
4 Sense/Tacho yellow green yellow

So everything is exactly as in the datasheets, except the swapped Control and Sense pins. After I’ve swapped them, the server became quite quiet and I quite happy. :D Actually, my desktop is now more noisy. Argh! BTW, thanks a lot to Brent Ozar for his blog entry on making a power edge quieter.

Update

Now I seem to have another problem: as reported by Brent Ozar and others

One problem shown above is that sometimes fans spin slow enough that they trigger Dell’s thresholds for slow-moving fans. Gotta figure out how to fix that for good one of these days.

Damn. Now I either have to find a way to make the fans a little bit faster or to change the threshold. See the follow-up post for more info on the threshold problem.

Update 2

I finally managed to adjust the critical fan thresholds by patching the BMC firmware! Here’s the howto. Additionally, I created a project page for my server.