[libata] SCSI: support INQUIRY page 89h (ATA info page)
authorJeff Garzik <jeff@garzik.org>
Sat, 22 Sep 2007 00:38:03 +0000 (20:38 -0400)
committerJeff Garzik <jeff@garzik.org>
Fri, 12 Oct 2007 18:55:40 +0000 (14:55 -0400)
Signed-off-by: Jeff Garzik <jeff@garzik.org>
drivers/ata/libata-scsi.c

index 7ad046b7c356a845613bc8e76b5f3c47fc07426e..b39966299e7be6bbebc185b57e390bb6e975e1fa 100644 (file)
@@ -1803,6 +1803,61 @@ unsigned int ata_scsiop_inq_83(struct ata_scsi_args *args, u8 *rbuf,
        return 0;
 }
 
+/**
+ *     ata_scsiop_inq_89 - Simulate INQUIRY VPD page 89, ATA info
+ *     @args: device IDENTIFY data / SCSI command of interest.
+ *     @rbuf: Response buffer, to which simulated SCSI cmd output is sent.
+ *     @buflen: Response buffer length.
+ *
+ *     Yields SAT-specified ATA VPD page.
+ *
+ *     LOCKING:
+ *     spin_lock_irqsave(host lock)
+ */
+
+unsigned int ata_scsiop_inq_89(struct ata_scsi_args *args, u8 *rbuf,
+                             unsigned int buflen)
+{
+       u8 pbuf[60];
+       struct ata_taskfile tf;
+       unsigned int i;
+
+       if (!buflen)
+               return 0;
+
+       memset(&pbuf, 0, sizeof(pbuf));
+       memset(&tf, 0, sizeof(tf));
+
+       pbuf[1] = 0x89;                 /* our page code */
+       pbuf[2] = (0x238 >> 8);         /* page size fixed at 238h */
+       pbuf[3] = (0x238 & 0xff);
+
+       memcpy(&pbuf[8], "ATA     ", 8);
+       ata_id_string(args->id, &pbuf[16], ATA_ID_PROD, 16);
+       ata_id_string(args->id, &pbuf[32], ATA_ID_FW_REV, 4);
+
+       /* we don't store the ATA device signature, so we fake it */
+
+       tf.command = ATA_DRDY;          /* really, this is Status reg */
+       tf.lbal = 0x1;
+       tf.nsect = 0x1;
+
+       ata_tf_to_fis(&tf, 0, 1, &pbuf[36]);    /* TODO: PMP? */
+       pbuf[36] = 0x34;                /* force D2H Reg FIS (34h) */
+
+       pbuf[56] = ATA_CMD_ID_ATA;
+
+       i = min(buflen, 60U);
+       memcpy(rbuf, &pbuf[0], i);
+       buflen -= i;
+
+       if (!buflen)
+               return 0;
+
+       memcpy(&rbuf[60], &args->id[0], min(buflen, 512U));
+       return 0;
+}
+
 /**
  *     ata_scsiop_noop - Command handler that simply returns success.
  *     @args: device IDENTIFY data / SCSI command of interest.
@@ -2880,14 +2935,23 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd,
                                ata_scsi_invalid_field(cmd, done);
                        else if ((scsicmd[1] & 1) == 0)    /* is EVPD clear? */
                                ata_scsi_rbuf_fill(&args, ata_scsiop_inq_std);
-                       else if (scsicmd[2] == 0x00)
+                       else switch (scsicmd[2]) {
+                       case 0x00:
                                ata_scsi_rbuf_fill(&args, ata_scsiop_inq_00);
-                       else if (scsicmd[2] == 0x80)
+                               break;
+                       case 0x80:
                                ata_scsi_rbuf_fill(&args, ata_scsiop_inq_80);
-                       else if (scsicmd[2] == 0x83)
+                               break;
+                       case 0x83:
                                ata_scsi_rbuf_fill(&args, ata_scsiop_inq_83);
-                       else
+                               break;
+                       case 0x89:
+                               ata_scsi_rbuf_fill(&args, ata_scsiop_inq_89);
+                               break;
+                       default:
                                ata_scsi_invalid_field(cmd, done);
+                               break;
+                       }
                        break;
 
                case MODE_SENSE: