Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ad355b46 authored by Jeff Garzik's avatar Jeff Garzik
Browse files

[libata] SCSI: support INQUIRY page 89h (ATA info page)



Signed-off-by: default avatarJeff Garzik <jeff@garzik.org>
parent d4155e6f
Loading
Loading
Loading
Loading
+68 −4
Original line number Diff line number Diff line
@@ -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,15 +2935,24 @@ 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:
		case MODE_SENSE_10: