aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi
diff options
context:
space:
mode:
authorMatthew Wilcox <matthew@wil.cx>2008-12-31 13:12:46 -0500
committerJames Bottomley <James.Bottomley@HansenPartnership.com>2009-03-12 13:57:54 -0400
commit881a256d84e658d14ca1c162fe56e9cbbb1cdd49 (patch)
tree76f77b27d87f823b6a2429a04ff925bee6c3107d /drivers/scsi
parent5fa0ae19822d60307059ee64b80ba9e5effdce58 (diff)
[SCSI] Add VPD helper
Based on prior work by Martin Petersen and James Bottomley, this patch adds a generic helper for retrieving VPD pages from SCSI devices. Signed-off-by: Matthew Wilcox <willy@linux.intel.com> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Diffstat (limited to 'drivers/scsi')
-rw-r--r--drivers/scsi/scsi.c104
1 files changed, 104 insertions, 0 deletions
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index cbcd3f681b62..a2ef03243a2c 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -967,6 +967,110 @@ int scsi_track_queue_full(struct scsi_device *sdev, int depth)
967EXPORT_SYMBOL(scsi_track_queue_full); 967EXPORT_SYMBOL(scsi_track_queue_full);
968 968
969/** 969/**
970 * scsi_vpd_inquiry - Request a device provide us with a VPD page
971 * @sdev: The device to ask
972 * @buffer: Where to put the result
973 * @page: Which Vital Product Data to return
974 * @len: The length of the buffer
975 *
976 * This is an internal helper function. You probably want to use
977 * scsi_get_vpd_page instead.
978 *
979 * Returns 0 on success or a negative error number.
980 */
981static int scsi_vpd_inquiry(struct scsi_device *sdev, unsigned char *buffer,
982 u8 page, unsigned len)
983{
984 int result;
985 unsigned char cmd[16];
986
987 cmd[0] = INQUIRY;
988 cmd[1] = 1; /* EVPD */
989 cmd[2] = page;
990 cmd[3] = len >> 8;
991 cmd[4] = len & 0xff;
992 cmd[5] = 0; /* Control byte */
993
994 /*
995 * I'm not convinced we need to try quite this hard to get VPD, but
996 * all the existing users tried this hard.
997 */
998 result = scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE, buffer,
999 len + 4, NULL, 30 * HZ, 3, NULL);
1000 if (result)
1001 return result;
1002
1003 /* Sanity check that we got the page back that we asked for */
1004 if (buffer[1] != page)
1005 return -EIO;
1006
1007 return 0;
1008}
1009
1010/**
1011 * scsi_get_vpd_page - Get Vital Product Data from a SCSI device
1012 * @sdev: The device to ask
1013 * @page: Which Vital Product Data to return
1014 *
1015 * SCSI devices may optionally supply Vital Product Data. Each 'page'
1016 * of VPD is defined in the appropriate SCSI document (eg SPC, SBC).
1017 * If the device supports this VPD page, this routine returns a pointer
1018 * to a buffer containing the data from that page. The caller is
1019 * responsible for calling kfree() on this pointer when it is no longer
1020 * needed. If we cannot retrieve the VPD page this routine returns %NULL.
1021 */
1022unsigned char *scsi_get_vpd_page(struct scsi_device *sdev, u8 page)
1023{
1024 int i, result;
1025 unsigned int len;
1026 unsigned char *buf = kmalloc(259, GFP_KERNEL);
1027
1028 if (!buf)
1029 return NULL;
1030
1031 /* Ask for all the pages supported by this device */
1032 result = scsi_vpd_inquiry(sdev, buf, 0, 255);
1033 if (result)
1034 goto fail;
1035
1036 /* If the user actually wanted this page, we can skip the rest */
1037 if (page == 0)
1038 return buf;
1039
1040 for (i = 0; i < buf[3]; i++)
1041 if (buf[i + 4] == page)
1042 goto found;
1043 /* The device claims it doesn't support the requested page */
1044 goto fail;
1045
1046 found:
1047 result = scsi_vpd_inquiry(sdev, buf, page, 255);
1048 if (result)
1049 goto fail;
1050
1051 /*
1052 * Some pages are longer than 255 bytes. The actual length of
1053 * the page is returned in the header.
1054 */
1055 len = (buf[2] << 8) | buf[3];
1056 if (len <= 255)
1057 return buf;
1058
1059 kfree(buf);
1060 buf = kmalloc(len + 4, GFP_KERNEL);
1061 result = scsi_vpd_inquiry(sdev, buf, page, len);
1062 if (result)
1063 goto fail;
1064
1065 return buf;
1066
1067 fail:
1068 kfree(buf);
1069 return NULL;
1070}
1071EXPORT_SYMBOL_GPL(scsi_get_vpd_page);
1072
1073/**
970 * scsi_device_get - get an additional reference to a scsi_device 1074 * scsi_device_get - get an additional reference to a scsi_device
971 * @sdev: device to get a reference to 1075 * @sdev: device to get a reference to
972 * 1076 *