Commit 7f594e47 authored by Jeff Garzik's avatar Jeff Garzik

[libata] SCSI->ATA simulator hacking: INQUIRY command

The SCSI T10 committee is working on a document describing a standard
method for translating ATA<->SCSI, since it being done quite often
these days.  Some of the recommendations are reasonable, and we implement
two here:

* Mirror that ATA 'removeable media' bit into INQUIRY output.
* Change behavior of INQUIRY output field 'product revision' from
  the libata software version number to the first 4 bytes of the
  ATA device's firmware revision number.

Rather than cache the firmware revision in struct ata_device, as was/is
done with two other strings, I took the opportunity to eliminate the
caching of the two other strings, 'vendor' and 'product'.  These strings
are now retrieved as needed from the IDENTIFY [PACKET] DEVICE info page,
since we cache its entire contents.

Retrieving a string from the identify-device page is done via the
helper function ata_dev_id_string(), which is now exported.

This patch winds up making struct ata_device 40 bytes smaller, and
the libata core gets a bit smaller as well.
parent e9c8846e
...@@ -818,7 +818,7 @@ static u8 ata_dev_try_classify(struct ata_port *ap, unsigned int device) ...@@ -818,7 +818,7 @@ static u8 ata_dev_try_classify(struct ata_port *ap, unsigned int device)
* @dev: Device whose IDENTIFY DEVICE results we will examine * @dev: Device whose IDENTIFY DEVICE results we will examine
* @s: string into which data is output * @s: string into which data is output
* @ofs: offset into identify device page * @ofs: offset into identify device page
* @len: length of string to return * @len: length of string to return. must be an even number.
* *
* The strings in the IDENTIFY DEVICE page are broken up into * The strings in the IDENTIFY DEVICE page are broken up into
* 16-bit chunks. Run through the string, and output each * 16-bit chunks. Run through the string, and output each
...@@ -847,29 +847,6 @@ void ata_dev_id_string(struct ata_device *dev, unsigned char *s, ...@@ -847,29 +847,6 @@ void ata_dev_id_string(struct ata_device *dev, unsigned char *s,
} }
} }
/**
* ata_dev_parse_strings - Store useful IDENTIFY DEVICE page strings
* @dev: Device whose IDENTIFY DEVICE page info we use
*
* We store 'vendor' and 'product' strings read from the device,
* for later use in the SCSI simulator's INQUIRY data.
*
* Set these strings here, in the case of 'product', using
* data read from the ATA IDENTIFY DEVICE page.
*
* LOCKING:
* caller.
*/
static void ata_dev_parse_strings(struct ata_device *dev)
{
assert (dev->class == ATA_DEV_ATA);
memcpy(dev->vendor, "ATA ", 8);
ata_dev_id_string(dev, dev->product, ATA_ID_PROD_OFS,
sizeof(dev->product));
}
/** /**
* __ata_dev_select - Select device 0/1 on ATA bus * __ata_dev_select - Select device 0/1 on ATA bus
* @ap: ATA channel to manipulate * @ap: ATA channel to manipulate
...@@ -1127,8 +1104,6 @@ static void ata_dev_identify(struct ata_port *ap, unsigned int device) ...@@ -1127,8 +1104,6 @@ static void ata_dev_identify(struct ata_port *ap, unsigned int device)
ata_dump_id(dev); ata_dump_id(dev);
ata_dev_parse_strings(dev);
/* ATA-specific feature tests */ /* ATA-specific feature tests */
if (dev->class == ATA_DEV_ATA) { if (dev->class == ATA_DEV_ATA) {
if (!ata_id_is_ata(dev)) /* sanity check */ if (!ata_id_is_ata(dev)) /* sanity check */
...@@ -3525,3 +3500,4 @@ EXPORT_SYMBOL_GPL(ata_scsi_error); ...@@ -3525,3 +3500,4 @@ EXPORT_SYMBOL_GPL(ata_scsi_error);
EXPORT_SYMBOL_GPL(ata_scsi_slave_config); EXPORT_SYMBOL_GPL(ata_scsi_slave_config);
EXPORT_SYMBOL_GPL(ata_scsi_release); EXPORT_SYMBOL_GPL(ata_scsi_release);
EXPORT_SYMBOL_GPL(ata_host_intr); EXPORT_SYMBOL_GPL(ata_host_intr);
EXPORT_SYMBOL_GPL(ata_dev_id_string);
...@@ -498,7 +498,9 @@ void ata_scsi_rbuf_fill(struct ata_scsi_args *args, ...@@ -498,7 +498,9 @@ void ata_scsi_rbuf_fill(struct ata_scsi_args *args,
unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf, unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf,
unsigned int buflen) unsigned int buflen)
{ {
const u8 hdr[] = { struct ata_device *dev = args->dev;
u8 hdr[] = {
TYPE_DISK, TYPE_DISK,
0, 0,
0x5, /* claim SPC-3 version compatibility */ 0x5, /* claim SPC-3 version compatibility */
...@@ -506,14 +508,20 @@ unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf, ...@@ -506,14 +508,20 @@ unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf,
96 - 4 96 - 4
}; };
/* set scsi removeable (RMB) bit per ata bit */
if (ata_id_removeable(dev))
hdr[1] |= (1 << 7);
VPRINTK("ENTER\n"); VPRINTK("ENTER\n");
memcpy(rbuf, hdr, sizeof(hdr)); memcpy(rbuf, hdr, sizeof(hdr));
if (buflen > 36) { if (buflen > 36) {
memcpy(&rbuf[8], args->dev->vendor, 8); memcpy(&rbuf[8], "ATA ", 8);
memcpy(&rbuf[16], args->dev->product, 16); ata_dev_id_string(dev, &rbuf[16], ATA_ID_PROD_OFS, 16);
memcpy(&rbuf[32], DRV_VERSION, 4); ata_dev_id_string(dev, &rbuf[32], ATA_ID_FW_REV_OFS, 4);
if (rbuf[32] == 0 || rbuf[32] == ' ')
memcpy(&rbuf[32], "n/a ", 4);
} }
if (buflen > 63) { if (buflen > 63) {
......
...@@ -36,8 +36,6 @@ struct ata_scsi_args { ...@@ -36,8 +36,6 @@ struct ata_scsi_args {
}; };
/* libata-core.c */ /* libata-core.c */
extern void ata_dev_id_string(struct ata_device *dev, unsigned char *s,
unsigned int ofs, unsigned int len);
extern struct ata_queued_cmd *ata_qc_new_init(struct ata_port *ap, extern struct ata_queued_cmd *ata_qc_new_init(struct ata_port *ap,
struct ata_device *dev); struct ata_device *dev);
extern int ata_qc_issue(struct ata_queued_cmd *qc); extern int ata_qc_issue(struct ata_queued_cmd *qc);
......
...@@ -276,8 +276,14 @@ static void sil_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val) ...@@ -276,8 +276,14 @@ static void sil_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
static void sil_dev_config(struct ata_port *ap, struct ata_device *dev) static void sil_dev_config(struct ata_port *ap, struct ata_device *dev)
{ {
unsigned int n, quirks = 0; unsigned int n, quirks = 0;
const char *s = &dev->product[0]; unsigned char model_num[40];
unsigned int len = strnlen(s, sizeof(dev->product)); const char *s;
unsigned int len;
ata_dev_id_string(dev, model_num, ATA_ID_PROD_OFS,
sizeof(model_num));
s = &model_num[0];
len = strnlen(s, sizeof(model_num));
/* ATAPI specifies that empty space is blank-filled; remove blanks */ /* ATAPI specifies that empty space is blank-filled; remove blanks */
while ((len > 0) && (s[len - 1] == ' ')) while ((len > 0) && (s[len - 1] == ' '))
......
...@@ -38,6 +38,7 @@ enum { ...@@ -38,6 +38,7 @@ enum {
ATA_ID_WORDS = 256, ATA_ID_WORDS = 256,
ATA_ID_PROD_OFS = 27, ATA_ID_PROD_OFS = 27,
ATA_ID_FW_REV_OFS = 23,
ATA_ID_SERNO_OFS = 10, ATA_ID_SERNO_OFS = 10,
ATA_ID_MAJOR_VER = 80, ATA_ID_MAJOR_VER = 80,
ATA_ID_PIO_MODES = 64, ATA_ID_PIO_MODES = 64,
...@@ -205,6 +206,7 @@ struct ata_taskfile { ...@@ -205,6 +206,7 @@ struct ata_taskfile {
#define ata_id_has_wcache(dev) ((dev)->id[82] & (1 << 5)) #define ata_id_has_wcache(dev) ((dev)->id[82] & (1 << 5))
#define ata_id_has_lba(dev) ((dev)->id[49] & (1 << 8)) #define ata_id_has_lba(dev) ((dev)->id[49] & (1 << 8))
#define ata_id_has_dma(dev) ((dev)->id[49] & (1 << 9)) #define ata_id_has_dma(dev) ((dev)->id[49] & (1 << 9))
#define ata_id_removeable(dev) ((dev)->id[0] & (1 << 7))
#define ata_id_u32(dev,n) \ #define ata_id_u32(dev,n) \
(((u32) (dev)->id[(n) + 1] << 16) | ((u32) (dev)->id[(n)])) (((u32) (dev)->id[(n) + 1] << 16) | ((u32) (dev)->id[(n)]))
#define ata_id_u64(dev,n) \ #define ata_id_u64(dev,n) \
......
...@@ -260,12 +260,6 @@ struct ata_device { ...@@ -260,12 +260,6 @@ struct ata_device {
unsigned int pio_mode; unsigned int pio_mode;
unsigned int udma_mode; unsigned int udma_mode;
unsigned char vendor[8]; /* space-padded, not ASCIIZ */
unsigned char product[32]; /* WARNING: shorter than
* ATAPI7 spec size, 40 ASCII
* characters
*/
/* cache info about current transfer mode */ /* cache info about current transfer mode */
u8 xfer_protocol; /* taskfile xfer protocol */ u8 xfer_protocol; /* taskfile xfer protocol */
u8 read_cmd; /* opcode to use on read */ u8 read_cmd; /* opcode to use on read */
...@@ -398,6 +392,8 @@ extern int ata_port_start (struct ata_port *ap); ...@@ -398,6 +392,8 @@ extern int ata_port_start (struct ata_port *ap);
extern void ata_port_stop (struct ata_port *ap); extern void ata_port_stop (struct ata_port *ap);
extern irqreturn_t ata_interrupt (int irq, void *dev_instance, struct pt_regs *regs); extern irqreturn_t ata_interrupt (int irq, void *dev_instance, struct pt_regs *regs);
extern void ata_fill_sg(struct ata_queued_cmd *qc); extern void ata_fill_sg(struct ata_queued_cmd *qc);
extern void ata_dev_id_string(struct ata_device *dev, unsigned char *s,
unsigned int ofs, unsigned int len);
extern void ata_bmdma_setup_mmio (struct ata_queued_cmd *qc); extern void ata_bmdma_setup_mmio (struct ata_queued_cmd *qc);
extern void ata_bmdma_start_mmio (struct ata_queued_cmd *qc); extern void ata_bmdma_start_mmio (struct ata_queued_cmd *qc);
extern void ata_bmdma_setup_pio (struct ata_queued_cmd *qc); extern void ata_bmdma_setup_pio (struct ata_queued_cmd *qc);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment