libpayload: New AHCI, ATA and ATAPI drivers

This adds a new interface for storage devices. A driver for ATA and
ATAPI drives on AHCI host controllers comes along.

The interface is very simple and was designed to match FILO's needs.
It consists of three functions:

  void storage_initialize(void);
  Initializes controllers. Should be called once at startup.

  storage_poll_t storage_probe(size_t dev_num);
     with typedef enum {
            POLL_NO_DEVICE      = -2,
            POLL_ERROR          = -1,
            POLL_NO_MEDIUM      =  0,
            POLL_MEDIUM_PRESENT =  1,
          } storage_poll_t;
  Looks for a drive with number dev_num (drives are counted from
  zero) and polls for a medium in the drive if appropriate.

  int storage_read_blocks512(size_t dev_num,
                             u64 start, size_t count,
                             unsigned char *buf);
  Reads count blocks of 512 bytes from block start of drive dev_num
  into buf.

Change-Id: I1c85796b7f8e379ff3817a61b1837636b57e182b
Signed-off-by: Nico Huber <nico.huber@secunet.com>
Reviewed-on: http://review.coreboot.org/1622
Tested-by: build bot (Jenkins)
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
Reviewed-by: Peter Stuge <peter@stuge.se>
diff --git a/payloads/libpayload/drivers/storage/storage.c b/payloads/libpayload/drivers/storage/storage.c
new file mode 100644
index 0000000..3e9c375
--- /dev/null
+++ b/payloads/libpayload/drivers/storage/storage.c
@@ -0,0 +1,111 @@
+/*
+ * This file is part of the libpayload project.
+ *
+ * Copyright (C) 2012 secunet Security Networks AG
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <libpayload.h>
+#ifdef CONFIG_STORAGE_AHCI
+# include <storage/ahci.h>
+#endif
+#include <storage/storage.h>
+
+
+static storage_dev_t **devices = NULL;
+static size_t devices_length = 0;
+static size_t dev_count = 0;
+
+int storage_attach_device(storage_dev_t *const dev)
+{
+	if (dev_count == devices_length) {
+		const size_t new_len =
+			(0 == devices_length) ? 4 : devices_length << 1;
+		storage_dev_t **const new_devices =
+			realloc(devices, new_len * sizeof(storage_dev_t *));
+		if (!new_devices)
+			return -1;
+		devices = new_devices;
+		memset(devices + devices_length, '\0',
+			(new_len - devices_length) * sizeof(storage_dev_t *));
+		devices_length = new_len;
+	}
+	devices[dev_count++] = dev;
+
+	return 0;
+}
+
+/**
+ * Probe for drive with given number
+ *
+ * Looks for a drive with number dev_num and polls for a medium
+ * in the drive if appropriate.
+ *
+ * @dev_num device number counted from 0
+ */
+storage_poll_t storage_probe(const size_t dev_num)
+{
+	if (dev_num >= dev_count)
+		return POLL_NO_DEVICE;
+	else if (devices[dev_num]->poll)
+		return devices[dev_num]->poll(devices[dev_num]);
+	else
+		return POLL_MEDIUM_PRESENT;
+}
+
+/**
+ * Read 512-byte blocks
+ *
+ * Reads count blocks of 512 bytes from block start of drive dev_num
+ * into buf.
+ *
+ * @dev_num device number counted from 0
+ * @start number of first block to read from
+ * @count number of blocks to read
+ * @buf buffer where the read data should be written
+ */
+ssize_t storage_read_blocks512(const size_t dev_num,
+			       const lba_t start, const size_t count,
+			       unsigned char *const buf)
+{
+	if ((dev_num < dev_count) && devices[dev_num]->read_blocks512)
+		return devices[dev_num]->read_blocks512(
+				devices[dev_num], start, count, buf);
+	else
+		return -1;
+}
+
+/**
+ * Initializes storage controllers
+ *
+ * This function should be called once at startup to bring up supported
+ * strorage controllers.
+ */
+void storage_initialize(void)
+{
+#ifdef CONFIG_STORAGE_AHCI
+	ahci_initialize();
+#endif
+}