static int isd200_scsi_to_ata()

in storage/isd200.c [1219:1427]


static int isd200_scsi_to_ata(struct scsi_cmnd *srb, struct us_data *us,
			      union ata_cdb * ataCdb)
{
	struct isd200_info *info = (struct isd200_info *)us->extra;
	u16 *id = info->id;
	int sendToTransport = 1;
	unsigned char sectnum, head;
	unsigned short cylinder;
	unsigned long lba;
	unsigned long blockCount;
	unsigned char senseData[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };

	memset(ataCdb, 0, sizeof(union ata_cdb));

	/* SCSI Command */
	switch (srb->cmnd[0]) {
	case INQUIRY:
		usb_stor_dbg(us, "   ATA OUT - INQUIRY\n");

		/* copy InquiryData */
		usb_stor_set_xfer_buf((unsigned char *) &info->InquiryData,
				sizeof(info->InquiryData), srb);
		srb->result = SAM_STAT_GOOD;
		sendToTransport = 0;
		break;

	case MODE_SENSE:
		usb_stor_dbg(us, "   ATA OUT - SCSIOP_MODE_SENSE\n");

		/* Initialize the return buffer */
		usb_stor_set_xfer_buf(senseData, sizeof(senseData), srb);

		if (info->DeviceFlags & DF_MEDIA_STATUS_ENABLED)
		{
			ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand;
			ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand;
			ataCdb->generic.TransferBlockSize = 1;
			ataCdb->generic.RegisterSelect = REG_COMMAND;
			ataCdb->write.CommandByte = ATA_COMMAND_GET_MEDIA_STATUS;
			isd200_srb_set_bufflen(srb, 0);
		} else {
			usb_stor_dbg(us, "   Media Status not supported, just report okay\n");
			srb->result = SAM_STAT_GOOD;
			sendToTransport = 0;
		}
		break;

	case TEST_UNIT_READY:
		usb_stor_dbg(us, "   ATA OUT - SCSIOP_TEST_UNIT_READY\n");

		if (info->DeviceFlags & DF_MEDIA_STATUS_ENABLED)
		{
			ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand;
			ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand;
			ataCdb->generic.TransferBlockSize = 1;
			ataCdb->generic.RegisterSelect = REG_COMMAND;
			ataCdb->write.CommandByte = ATA_COMMAND_GET_MEDIA_STATUS;
			isd200_srb_set_bufflen(srb, 0);
		} else {
			usb_stor_dbg(us, "   Media Status not supported, just report okay\n");
			srb->result = SAM_STAT_GOOD;
			sendToTransport = 0;
		}
		break;

	case READ_CAPACITY:
	{
		unsigned long capacity;
		struct read_capacity_data readCapacityData;

		usb_stor_dbg(us, "   ATA OUT - SCSIOP_READ_CAPACITY\n");

		if (ata_id_has_lba(id))
			capacity = ata_id_u32(id, ATA_ID_LBA_CAPACITY) - 1;
		else
			capacity = (id[ATA_ID_HEADS] * id[ATA_ID_CYLS] *
				    id[ATA_ID_SECTORS]) - 1;

		readCapacityData.LogicalBlockAddress = cpu_to_be32(capacity);
		readCapacityData.BytesPerBlock = cpu_to_be32(0x200);

		usb_stor_set_xfer_buf((unsigned char *) &readCapacityData,
				sizeof(readCapacityData), srb);
		srb->result = SAM_STAT_GOOD;
		sendToTransport = 0;
	}
	break;

	case READ_10:
		usb_stor_dbg(us, "   ATA OUT - SCSIOP_READ\n");

		lba = be32_to_cpu(*(__be32 *)&srb->cmnd[2]);
		blockCount = (unsigned long)srb->cmnd[7]<<8 | (unsigned long)srb->cmnd[8];

		if (ata_id_has_lba(id)) {
			sectnum = (unsigned char)(lba);
			cylinder = (unsigned short)(lba>>8);
			head = ATA_ADDRESS_DEVHEAD_LBA_MODE | (unsigned char)(lba>>24 & 0x0F);
		} else {
			sectnum = (u8)((lba % id[ATA_ID_SECTORS]) + 1);
			cylinder = (u16)(lba / (id[ATA_ID_SECTORS] *
					id[ATA_ID_HEADS]));
			head = (u8)((lba / id[ATA_ID_SECTORS]) %
					id[ATA_ID_HEADS]);
		}
		ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand;
		ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand;
		ataCdb->generic.TransferBlockSize = 1;
		ataCdb->generic.RegisterSelect =
		  REG_SECTOR_COUNT | REG_SECTOR_NUMBER |
		  REG_CYLINDER_LOW | REG_CYLINDER_HIGH |
		  REG_DEVICE_HEAD  | REG_COMMAND;
		ataCdb->write.SectorCountByte = (unsigned char)blockCount;
		ataCdb->write.SectorNumberByte = sectnum;
		ataCdb->write.CylinderHighByte = (unsigned char)(cylinder>>8);
		ataCdb->write.CylinderLowByte = (unsigned char)cylinder;
		ataCdb->write.DeviceHeadByte = (head | ATA_ADDRESS_DEVHEAD_STD);
		ataCdb->write.CommandByte = ATA_CMD_PIO_READ;
		break;

	case WRITE_10:
		usb_stor_dbg(us, "   ATA OUT - SCSIOP_WRITE\n");

		lba = be32_to_cpu(*(__be32 *)&srb->cmnd[2]);
		blockCount = (unsigned long)srb->cmnd[7]<<8 | (unsigned long)srb->cmnd[8];

		if (ata_id_has_lba(id)) {
			sectnum = (unsigned char)(lba);
			cylinder = (unsigned short)(lba>>8);
			head = ATA_ADDRESS_DEVHEAD_LBA_MODE | (unsigned char)(lba>>24 & 0x0F);
		} else {
			sectnum = (u8)((lba % id[ATA_ID_SECTORS]) + 1);
			cylinder = (u16)(lba / (id[ATA_ID_SECTORS] *
					id[ATA_ID_HEADS]));
			head = (u8)((lba / id[ATA_ID_SECTORS]) %
					id[ATA_ID_HEADS]);
		}
		ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand;
		ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand;
		ataCdb->generic.TransferBlockSize = 1;
		ataCdb->generic.RegisterSelect =
		  REG_SECTOR_COUNT | REG_SECTOR_NUMBER |
		  REG_CYLINDER_LOW | REG_CYLINDER_HIGH |
		  REG_DEVICE_HEAD  | REG_COMMAND;
		ataCdb->write.SectorCountByte = (unsigned char)blockCount;
		ataCdb->write.SectorNumberByte = sectnum;
		ataCdb->write.CylinderHighByte = (unsigned char)(cylinder>>8);
		ataCdb->write.CylinderLowByte = (unsigned char)cylinder;
		ataCdb->write.DeviceHeadByte = (head | ATA_ADDRESS_DEVHEAD_STD);
		ataCdb->write.CommandByte = ATA_CMD_PIO_WRITE;
		break;

	case ALLOW_MEDIUM_REMOVAL:
		usb_stor_dbg(us, "   ATA OUT - SCSIOP_MEDIUM_REMOVAL\n");

		if (info->DeviceFlags & DF_REMOVABLE_MEDIA) {
			usb_stor_dbg(us, "   srb->cmnd[4] = 0x%X\n",
				     srb->cmnd[4]);
	    
			ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand;
			ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand;
			ataCdb->generic.TransferBlockSize = 1;
			ataCdb->generic.RegisterSelect = REG_COMMAND;
			ataCdb->write.CommandByte = (srb->cmnd[4] & 0x1) ?
				ATA_CMD_MEDIA_LOCK : ATA_CMD_MEDIA_UNLOCK;
			isd200_srb_set_bufflen(srb, 0);
		} else {
			usb_stor_dbg(us, "   Not removable media, just report okay\n");
			srb->result = SAM_STAT_GOOD;
			sendToTransport = 0;
		}
		break;

	case START_STOP:    
		usb_stor_dbg(us, "   ATA OUT - SCSIOP_START_STOP_UNIT\n");
		usb_stor_dbg(us, "   srb->cmnd[4] = 0x%X\n", srb->cmnd[4]);

		if ((srb->cmnd[4] & 0x3) == 0x2) {
			usb_stor_dbg(us, "   Media Eject\n");
			ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand;
			ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand;
			ataCdb->generic.TransferBlockSize = 0;
			ataCdb->generic.RegisterSelect = REG_COMMAND;
			ataCdb->write.CommandByte = ATA_COMMAND_MEDIA_EJECT;
		} else if ((srb->cmnd[4] & 0x3) == 0x1) {
			usb_stor_dbg(us, "   Get Media Status\n");
			ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand;
			ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand;
			ataCdb->generic.TransferBlockSize = 1;
			ataCdb->generic.RegisterSelect = REG_COMMAND;
			ataCdb->write.CommandByte = ATA_COMMAND_GET_MEDIA_STATUS;
			isd200_srb_set_bufflen(srb, 0);
		} else {
			usb_stor_dbg(us, "   Nothing to do, just report okay\n");
			srb->result = SAM_STAT_GOOD;
			sendToTransport = 0;
		}
		break;

	default:
		usb_stor_dbg(us, "Unsupported SCSI command - 0x%X\n",
			     srb->cmnd[0]);
		srb->result = DID_ERROR << 16;
		sendToTransport = 0;
		break;
	}

	return(sendToTransport);
}