Index: uspace/drv/usbmast/Makefile
===================================================================
--- uspace/drv/usbmast/Makefile	(revision 19387b618c86f0b622dacb13c8ab5cfa361464a0)
+++ uspace/drv/usbmast/Makefile	(revision 70c12d6d852f29037bd6ed80ad2f0021e301e9d2)
@@ -41,4 +41,5 @@
 
 SOURCES = \
+	inquiry.c \
 	main.c \
 	mast.c
Index: uspace/drv/usbmast/inquiry.c
===================================================================
--- uspace/drv/usbmast/inquiry.c	(revision 70c12d6d852f29037bd6ed80ad2f0021e301e9d2)
+++ uspace/drv/usbmast/inquiry.c	(revision 70c12d6d852f29037bd6ed80ad2f0021e301e9d2)
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2011 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - 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.
+ * - 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 ``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 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.
+ */
+
+/** @addtogroup drvusbmast
+ * @{
+ */
+/**
+ * @file
+ * Main routines of USB mass storage driver.
+ */
+#include <usb/devdrv.h>
+#include <usb/debug.h>
+#include <usb/classes/classes.h>
+#include <usb/classes/massstor.h>
+#include <errno.h>
+#include <str_error.h>
+#include <str.h>
+#include <ctype.h>
+#include "cmds.h"
+#include "scsi.h"
+#include "mast.h"
+
+#define BITS_GET_MASK(type, bitcount) (((type)(1 << (bitcount)))-1)
+#define BITS_GET_MID_MASK(type, bitcount, offset) \
+	((type)( BITS_GET_MASK(type, (bitcount) + (offset)) - BITS_GET_MASK(type, bitcount) ))
+#define BITS_GET(type, number, bitcount, offset) \
+	((type)( (number) & (BITS_GET_MID_MASK(type, bitcount, offset)) ) >> (offset))
+
+#define INQUIRY_RESPONSE_LENGTH 36
+
+#define STR_UNKNOWN "<unknown>"
+static const char *str_peripheral_device_types[] = {
+	"direct-access device",
+	"sequential-access device",
+	"printer device",
+	"processor device",
+	"write-once device",
+	"CDROM device",
+	"scanner device",
+	"optical memory device",
+	"medium changer",
+	"communications device",
+	"graphic arts pre-press device",
+	"graphic arts pre-press device",
+	"storage array controller device",
+	"enclosure services device",
+	"simplified direct-access device",
+	"optical card reader/writer device",
+	"bridging expander",
+	"object-based storage device",
+	"automation driver interface",
+	STR_UNKNOWN, // 0x13
+	STR_UNKNOWN, // 0x14
+	STR_UNKNOWN, // 0x15
+	STR_UNKNOWN, // 0x16
+	STR_UNKNOWN, // 0x17
+	STR_UNKNOWN, // 0x18
+	STR_UNKNOWN, // 0x19
+	STR_UNKNOWN, // 0x1A
+	STR_UNKNOWN, // 0x1B
+	STR_UNKNOWN, // 0x1C
+	STR_UNKNOWN, // 0x1D
+	"well-known logical unit",
+	"uknown or no device state"
+};
+#define str_peripheral_device_types_count \
+	(sizeof(str_peripheral_device_types)/sizeof(str_peripheral_device_types[0]))
+
+const char *usb_str_masstor_scsi_peripheral_device_type(int type)
+{
+	if ((type < 0)
+	    || ((size_t)type >= str_peripheral_device_types_count)) {
+		return STR_UNKNOWN;
+	}
+	return str_peripheral_device_types[type];
+}
+
+static void trim_trailing_spaces(char *name)
+{
+	size_t len = str_length(name);
+	while ((len > 0) && isspace((int) name[len - 1])) {
+		name[len - 1] = 0;
+		len--;
+	}
+}
+
+int usb_massstor_inquiry(usb_device_t *dev,
+    size_t bulk_in_idx, size_t bulk_out_idx,
+    usb_massstor_inquiry_result_t *inquiry_result)
+{
+	scsi_cmd_inquiry_t inquiry = {
+		.op_code = 0x12,
+		.lun_evpd = 0,
+		.page_code = 0,
+		.alloc_length = host2uint16_t_be(INQUIRY_RESPONSE_LENGTH),
+		.ctrl = 0
+	};
+	size_t response_len;
+	uint8_t response[INQUIRY_RESPONSE_LENGTH];
+
+	int rc;
+
+	rc = usb_massstor_data_in(dev, bulk_in_idx, bulk_out_idx,
+	    0xDEADBEEF, 0, (uint8_t *) &inquiry, sizeof(inquiry),
+	    response, INQUIRY_RESPONSE_LENGTH, &response_len);
+
+	if (rc != EOK) {
+		usb_log_error("Failed to probe device %s using %s: %s.\n",
+		   dev->ddf_dev->name, "SCSI:INQUIRY", str_error(rc));
+		return rc;
+	}
+
+	if (response_len < 8) {
+		usb_log_error("The SCSI response is too short.\n");
+		return ERANGE;
+	}
+
+	/*
+	 * This is an ugly part of the code. We will parse the returned
+	 * data by hand and try to get as many useful data as possible.
+	 */
+	bzero(inquiry_result, sizeof(*inquiry_result));
+
+	/* This shall be returned by all devices. */
+	inquiry_result->peripheral_device_type
+	    = BITS_GET(uint8_t, response[0], 5, 0);
+	inquiry_result->removable = BITS_GET(uint8_t, response[1], 1, 7);
+
+	if (response_len < 32) {
+		return EOK;
+	}
+
+	str_ncpy(inquiry_result->vendor_id, 9,
+	    (const char *) &response[8], 8);
+	trim_trailing_spaces(inquiry_result->vendor_id);
+
+	str_ncpy(inquiry_result->product_and_revision, 12,
+	    (const char *) &response[16], 11);
+	trim_trailing_spaces(inquiry_result->product_and_revision);
+
+	return EOK;
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/usbmast/main.c
===================================================================
--- uspace/drv/usbmast/main.c	(revision 19387b618c86f0b622dacb13c8ab5cfa361464a0)
+++ uspace/drv/usbmast/main.c	(revision 70c12d6d852f29037bd6ed80ad2f0021e301e9d2)
@@ -75,65 +75,4 @@
 };
 
-#define BITS_GET_MASK(type, bitcount) (((type)(1 << (bitcount)))-1)
-#define BITS_GET_MID_MASK(type, bitcount, offset) \
-	((type)( BITS_GET_MASK(type, (bitcount) + (offset)) - BITS_GET_MASK(type, bitcount) ))
-#define BITS_GET(type, number, bitcount, offset) \
-	((type)( (number) & (BITS_GET_MID_MASK(type, bitcount, offset)) ) >> (offset))
-
-#define INQUIRY_RESPONSE_LENGTH 35
-
-static void try_inquiry(usb_device_t *dev)
-{
-	scsi_cmd_inquiry_t inquiry = {
-		.op_code = 0x12,
-		.lun_evpd = 0,
-		.page_code = 0,
-		.alloc_length = INQUIRY_RESPONSE_LENGTH,
-		.ctrl = 0
-	};
-	size_t response_len;
-	uint8_t response[INQUIRY_RESPONSE_LENGTH];
-
-	int rc;
-
-	rc = usb_massstor_data_in(GET_BULK_IN(dev), GET_BULK_OUT(dev),
-	    0xDEADBEEF, 0, (uint8_t *) &inquiry, sizeof(inquiry),
-	    response, INQUIRY_RESPONSE_LENGTH, &response_len);
-
-	if (rc != EOK) {
-		usb_log_error("Failed to probe device %s using %s: %s.\n",
-		   dev->ddf_dev->name, "SCSI:INQUIRY", str_error(rc));
-		return;
-	}
-
-	if (response_len < 8) {
-		usb_log_error("The SCSI response is too short.\n");
-		return;
-	}
-
-	/*
-	 * This is an ugly part of the code. We will parse the returned
-	 * data by hand and try to get as many useful data as possible.
-	 */
-	int device_type = BITS_GET(uint8_t, response[0], 5, 0);
-	int removable = BITS_GET(uint8_t, response[1], 1, 7);
-
-	usb_log_info("SCSI information for device `%s':\n", dev->ddf_dev->name);
-	usb_log_info("  - peripheral device type: %d\n", device_type);
-	usb_log_info("  - removable: %s\n", removable ? "yes" : "no");
-
-	if (response_len < 32) {
-		return;
-	}
-
-	char dev_vendor[9];
-	str_ncpy(dev_vendor, 9, (const char *) &response[8], 8);
-	usb_log_info("  - vendor: '%s'\n", dev_vendor);
-
-	char dev_product[9];
-	str_ncpy(dev_product, 9, (const char *) &response[16], 8);
-	usb_log_info("  - product: '%s'\n", dev_vendor);
-}
-
 /** Callback when new device is attached and recognized as a mass storage.
  *
@@ -168,5 +107,30 @@
 	    (size_t) dev->pipes[BULK_OUT_EP].descriptor->max_packet_size);
 
-	try_inquiry(dev);
+	int lun_count = usb_massstor_get_max_lun(dev);
+	/* Return value:
+	 * rc < 0 => device does not know this request, only single LUN
+	 *     could be present
+	 * rc >= 0 - the rc is the maximum LUN, thus count is +1
+	 */
+	if (lun_count < 0) {
+		lun_count = 1;
+	} else {
+		lun_count++;
+	}
+
+	usb_massstor_inquiry_result_t inquiry;
+	rc = usb_massstor_inquiry(dev, BULK_IN_EP, BULK_OUT_EP, &inquiry);
+	if (rc != EOK) {
+		usb_log_warning("Failed to inquiry device `%s': %s.\n",
+		    dev->ddf_dev->name, str_error(rc));
+		return EOK;
+	}
+
+	usb_log_info("Mass storage `%s': `%s' by `%s' is %s (%s), %d LUN(s).\n",
+	    dev->ddf_dev->name,
+	    inquiry.product_and_revision, inquiry.vendor_id,
+	    usb_str_masstor_scsi_peripheral_device_type(inquiry.peripheral_device_type),
+	    inquiry.removable ? "removable" : "non-removable",
+	    lun_count);
 
 	return EOK;
Index: uspace/drv/usbmast/mast.c
===================================================================
--- uspace/drv/usbmast/mast.c	(revision 19387b618c86f0b622dacb13c8ab5cfa361464a0)
+++ uspace/drv/usbmast/mast.c	(revision 70c12d6d852f29037bd6ed80ad2f0021e301e9d2)
@@ -40,4 +40,5 @@
 #include <str_error.h>
 #include <usb/debug.h>
+#include <usb/request.h>
 
 bool usb_mast_verbose = true;
@@ -63,5 +64,6 @@
  * @return Error code.
  */
-int usb_massstor_data_in(usb_pipe_t *bulk_in_pipe, usb_pipe_t *bulk_out_pipe,
+int usb_massstor_data_in(usb_device_t *dev,
+    size_t bulk_in_pipe_index, size_t bulk_out_pipe_index,
     uint32_t tag, uint8_t lun, void *cmd, size_t cmd_size,
     void *in_buffer, size_t in_buffer_size, size_t *received_size)
@@ -69,4 +71,6 @@
 	int rc;
 	size_t act_size;
+	usb_pipe_t *bulk_in_pipe = dev->pipes[bulk_in_pipe_index].pipe;
+	usb_pipe_t *bulk_out_pipe = dev->pipes[bulk_out_pipe_index].pipe;
 
 	/* Prepare CBW - command block wrapper */
@@ -135,4 +139,38 @@
 }
 
+int usb_massstor_reset(usb_device_t *dev)
+{
+	return usb_control_request_set(&dev->ctrl_pipe,
+	    USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_INTERFACE,
+	    0xFF, 0, dev->interface_no, NULL, 0);
+}
+
+void usb_massstor_reset_recovery(usb_device_t *dev,
+    size_t bulk_in_idx, size_t bulk_out_idx)
+{
+	/* We would ignore errors here because if this fails
+	 * we are doomed anyway and any following transaction would fail.
+	 */
+	usb_massstor_reset(dev);
+	usb_pipe_clear_halt(&dev->ctrl_pipe, dev->pipes[bulk_in_idx].pipe);
+	usb_pipe_clear_halt(&dev->ctrl_pipe, dev->pipes[bulk_out_idx].pipe);
+}
+
+int usb_massstor_get_max_lun(usb_device_t *dev)
+{
+	uint8_t max_lun;
+	size_t data_recv_len;
+	int rc = usb_control_request_get(&dev->ctrl_pipe,
+	    USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_INTERFACE,
+	    0xFE, 0, dev->interface_no, &max_lun, 1, &data_recv_len);
+	if (rc != EOK) {
+		return rc;
+	}
+	if (data_recv_len != 1) {
+		return EEMPTY;
+	}
+	return (int) max_lun;
+}
+
 /**
  * @}
Index: uspace/drv/usbmast/mast.h
===================================================================
--- uspace/drv/usbmast/mast.h	(revision 19387b618c86f0b622dacb13c8ab5cfa361464a0)
+++ uspace/drv/usbmast/mast.h	(revision 70c12d6d852f29037bd6ed80ad2f0021e301e9d2)
@@ -40,7 +40,21 @@
 #include <usb/usb.h>
 #include <usb/pipes.h>
+#include <usb/devdrv.h>
 
-int usb_massstor_data_in(usb_pipe_t *, usb_pipe_t *, uint32_t, uint8_t,
-    void *, size_t, void *, size_t, size_t *);
+typedef struct {
+	int peripheral_device_type;
+	bool removable;
+	char vendor_id[9];
+	char product_and_revision[12];
+} usb_massstor_inquiry_result_t;
+
+int usb_massstor_data_in(usb_device_t *dev, size_t, size_t,
+    uint32_t, uint8_t, void *, size_t, void *, size_t, size_t *);
+int usb_massstor_reset(usb_device_t *);
+void usb_massstor_reset_recovery(usb_device_t *, size_t, size_t);
+int usb_massstor_get_max_lun(usb_device_t *);
+int usb_massstor_inquiry(usb_device_t *, size_t, size_t,
+    usb_massstor_inquiry_result_t *);
+const char *usb_str_masstor_scsi_peripheral_device_type(int);
 
 #endif
