linux-ide.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH libata-dev-2.6 3/3] Add CHS support
@ 2005-02-06  6:08 Albert Lee
  0 siblings, 0 replies; only message in thread
From: Albert Lee @ 2005-02-06  6:08 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: Bartlomiej Zolnierkiewicz, Doug Maxey, IDE Linux

[-- Attachment #1: Type: text/plain, Size: 9996 bytes --]

Hi Jeff,

  These are the patches for libata CHS support. 

  Attached please find the patch 3/3 against the libata-dev-2.6 tree for your review. Thanks.

Albert

Signed-off-by: Albert Lee <albertcc@tw.ibm.com>
-----------------------------------------------------------------------------------------
--- libata-dev-2.6/drivers/scsi/libata-scsi.c 2005-02-05 10:41:49.000000000 +0800
+++ libata-dev-2.6-mod/drivers/scsi/libata-scsi.c 2005-02-05 12:46:26.000000000 +0800
@@ -689,72 +689,101 @@
 static unsigned int ata_scsi_verify_xlat(struct ata_queued_cmd *qc, u8 *scsicmd)
 {
  struct ata_taskfile *tf = &qc->tf;
+ struct ata_device *dev = qc->dev;
+ unsigned int lba   = tf->flags & ATA_TFLAG_LBA;
  unsigned int lba48 = tf->flags & ATA_TFLAG_LBA48;
  u64 dev_sectors = qc->dev->n_sectors;
- u64 sect = 0;
- u32 n_sect = 0;
+ u64 block = 0;
+ u32 n_block = 0;
 
  tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
  tf->protocol = ATA_PROT_NODATA;
- tf->device |= ATA_LBA;
 
  if (scsicmd[0] == VERIFY) {
-  sect |= ((u64)scsicmd[2]) << 24;
-  sect |= ((u64)scsicmd[3]) << 16;
-  sect |= ((u64)scsicmd[4]) << 8;
-  sect |= ((u64)scsicmd[5]);
+  block |= ((u64)scsicmd[2]) << 24;
+  block |= ((u64)scsicmd[3]) << 16;
+  block |= ((u64)scsicmd[4]) << 8;
+  block |= ((u64)scsicmd[5]);
 
-  n_sect |= ((u32)scsicmd[7]) << 8;
-  n_sect |= ((u32)scsicmd[8]);
+  n_block |= ((u32)scsicmd[7]) << 8;
+  n_block |= ((u32)scsicmd[8]);
  }
 
  else if (scsicmd[0] == VERIFY_16) {
-  sect |= ((u64)scsicmd[2]) << 56;
-  sect |= ((u64)scsicmd[3]) << 48;
-  sect |= ((u64)scsicmd[4]) << 40;
-  sect |= ((u64)scsicmd[5]) << 32;
-  sect |= ((u64)scsicmd[6]) << 24;
-  sect |= ((u64)scsicmd[7]) << 16;
-  sect |= ((u64)scsicmd[8]) << 8;
-  sect |= ((u64)scsicmd[9]);
-
-  n_sect |= ((u32)scsicmd[10]) << 24;
-  n_sect |= ((u32)scsicmd[11]) << 16;
-  n_sect |= ((u32)scsicmd[12]) << 8;
-  n_sect |= ((u32)scsicmd[13]);
+  block |= ((u64)scsicmd[2]) << 56;
+  block |= ((u64)scsicmd[3]) << 48;
+  block |= ((u64)scsicmd[4]) << 40;
+  block |= ((u64)scsicmd[5]) << 32;
+  block |= ((u64)scsicmd[6]) << 24;
+  block |= ((u64)scsicmd[7]) << 16;
+  block |= ((u64)scsicmd[8]) << 8;
+  block |= ((u64)scsicmd[9]);
+
+  n_block |= ((u32)scsicmd[10]) << 24;
+  n_block |= ((u32)scsicmd[11]) << 16;
+  n_block |= ((u32)scsicmd[12]) << 8;
+  n_block |= ((u32)scsicmd[13]);
  }
 
  else
   return 1;
 
- if (!n_sect)
+ if (!n_block)
   return 1;
- if (sect >= dev_sectors)
+ if (block >= dev_sectors)
   return 1;
- if ((sect + n_sect) > dev_sectors)
+ if ((block + n_block) > dev_sectors)
   return 1;
  if (lba48) {
-  if (n_sect > (64 * 1024))
+  if (n_block > (64 * 1024))
    return 1;
  } else {
-  if (n_sect > 256)
+  if (n_block > 256)
    return 1;
  }
 
- if (lba48) {
-  tf->hob_nsect = (n_sect >> 8) & 0xff;
+ if (lba) {
+  if (lba48) {
+   tf->hob_nsect = (n_block >> 8) & 0xff;
 
-  tf->hob_lbah = (sect >> 40) & 0xff;
-  tf->hob_lbam = (sect >> 32) & 0xff;
-  tf->hob_lbal = (sect >> 24) & 0xff;
- } else
-  tf->device |= (sect >> 24) & 0xf;
+   tf->hob_lbah = (block >> 40) & 0xff;
+   tf->hob_lbam = (block >> 32) & 0xff;
+   tf->hob_lbal = (block >> 24) & 0xff;
+  } else
+   tf->device |= (block >> 24) & 0xf;
+
+  tf->nsect = n_block & 0xff;
 
- tf->nsect = n_sect & 0xff;
+  tf->lbah = (block >> 16) & 0xff;
+  tf->lbam = (block >> 8) & 0xff;
+  tf->lbal = block & 0xff;
 
- tf->hob_lbah = (sect >> 16) & 0xff;
- tf->hob_lbam = (sect >> 8) & 0xff;
- tf->hob_lbal = sect & 0xff;
+  tf->device |= ATA_LBA;
+ } else {
+  /* CHS */
+  u32 sect, head, cyl, track;
+
+  /* Convert LBA to CHS */
+  track = (u32)block / dev->sectors;
+  cyl   = track / dev->heads;
+  head  = track % dev->heads;
+  sect  = (u32)block % dev->sectors + 1;
+
+  DPRINTK("block[%u] track[%u] cyl[%u] head[%u] sect[%u] \n", (u32)block, track, cyl, head, sect);
+  
+  /* Check whether the converted CHS can fit. 
+     Cylinder: 0-65535 
+     Head: 0-15
+     Sector: 1-255*/
+  if ((cyl >> 16) || (head >> 4) || (sect >> 8) || (!sect)) 
+   return 1;
+  
+  tf->nsect = n_block & 0xff; /* Sector count 0 means 256 sectors */
+  tf->lbal = sect;
+  tf->lbam = cyl;
+  tf->lbah = cyl >> 8;
+  tf->device |= head;
+ }
 
  return 0;
 }
@@ -782,11 +811,14 @@
 static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, u8 *scsicmd)
 {
  struct ata_taskfile *tf = &qc->tf;
+ struct ata_device *dev = qc->dev;
+ unsigned int lba   = tf->flags & ATA_TFLAG_LBA;
  unsigned int lba48 = tf->flags & ATA_TFLAG_LBA48;
+ u64 block = 0;
+ u32 n_block = 0;
 
  tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
  tf->protocol = qc->dev->xfer_protocol;
- tf->device |= ATA_LBA;
 
  if (scsicmd[0] == READ_10 || scsicmd[0] == READ_6 ||
      scsicmd[0] == READ_16) {
@@ -796,80 +828,111 @@
   tf->flags |= ATA_TFLAG_WRITE;
  }
 
+ /* Calculate the SCSI LBA and transfer length. */
  if (scsicmd[0] == READ_10 || scsicmd[0] == WRITE_10) {
-  if (lba48) {
-   tf->hob_nsect = scsicmd[7];
-   tf->hob_lbal = scsicmd[2];
+  block |= ((u64)scsicmd[2]) << 24;
+  block |= ((u64)scsicmd[3]) << 16;
+  block |= ((u64)scsicmd[4]) << 8;
+  block |= ((u64)scsicmd[5]);
 
-   qc->nsect = ((unsigned int)scsicmd[7] << 8) |
-     scsicmd[8];
-  } else {
-   /* if we don't support LBA48 addressing, the request
-    * -may- be too large. */
-   if ((scsicmd[2] & 0xf0) || scsicmd[7])
-    return 1;
-
-   /* stores LBA27:24 in lower 4 bits of device reg */
-   tf->device |= scsicmd[2];
-
-   qc->nsect = scsicmd[8];
-  }
-
-  tf->nsect = scsicmd[8];
-  tf->lbal = scsicmd[5];
-  tf->lbam = scsicmd[4];
-  tf->lbah = scsicmd[3];
+  n_block |= ((u32)scsicmd[7]) << 8;
+  n_block |= ((u32)scsicmd[8]);
 
   VPRINTK("ten-byte command\n");
-  return 0;
- }
-
- if (scsicmd[0] == READ_6 || scsicmd[0] == WRITE_6) {
-  qc->nsect = tf->nsect = scsicmd[4];
-  tf->lbal = scsicmd[3];
-  tf->lbam = scsicmd[2];
-  tf->lbah = scsicmd[1] & 0x1f; /* mask out reserved bits */
-
+ } else if (scsicmd[0] == READ_6 || scsicmd[0] == WRITE_6) {
+  block |= ((u64)scsicmd[2]) << 8;
+  block |= ((u64)scsicmd[3]);
+  n_block |= ((u32)scsicmd[4]);
+ 
   VPRINTK("six-byte command\n");
-  return 0;
+ } else if (scsicmd[0] == READ_16 || scsicmd[0] == WRITE_16) {
+  block |= ((u64)scsicmd[2]) << 56;
+  block |= ((u64)scsicmd[3]) << 48;
+  block |= ((u64)scsicmd[4]) << 40;
+  block |= ((u64)scsicmd[5]) << 32;
+  block |= ((u64)scsicmd[6]) << 24;
+  block |= ((u64)scsicmd[7]) << 16;
+  block |= ((u64)scsicmd[8]) << 8;
+  block |= ((u64)scsicmd[9]);
+
+  n_block |= ((u32)scsicmd[10]) << 24;
+  n_block |= ((u32)scsicmd[11]) << 16;
+  n_block |= ((u32)scsicmd[12]) << 8;
+  n_block |= ((u32)scsicmd[13]);
+
+  VPRINTK("sixteen-byte command\n");
+ } else {
+  DPRINTK("no-byte command\n");
+  return 1;
  }
 
- if (scsicmd[0] == READ_16 || scsicmd[0] == WRITE_16) {
-  /* rule out impossible LBAs and sector counts */
-  if (scsicmd[2] || scsicmd[3] || scsicmd[10] || scsicmd[11])
-   return 1;
+ /* Check and compose ATA command */
+ if (!n_block)
+  /* In ATA, sector count 0 are 256 or 65536 sectors, not 0 sectors. */
+  return 1;
 
+ if (lba) {
   if (lba48) {
-   tf->hob_nsect = scsicmd[12];
-   tf->hob_lbal = scsicmd[6];
-   tf->hob_lbam = scsicmd[5];
-   tf->hob_lbah = scsicmd[4];
-
-   qc->nsect = ((unsigned int)scsicmd[12] << 8) |
-     scsicmd[13];
-  } else {
-   /* once again, filter out impossible non-zero values */
-   if (scsicmd[4] || scsicmd[5] || scsicmd[12] ||
-       (scsicmd[6] & 0xf0))
+   /* The request -may- be too large for LBA48. */
+   if ((block >> 48) || (n_block > 65536))
     return 1;
 
-   /* stores LBA27:24 in lower 4 bits of device reg */
-   tf->device |= scsicmd[2];
+   tf->hob_nsect = (n_block >> 8) & 0xff;
+
+   tf->hob_lbah = (block >> 40) & 0xff;
+   tf->hob_lbam = (block >> 32) & 0xff;
+   tf->hob_lbal = (block >> 24) & 0xff;
+  } else { 
+   /* LBA28 */
 
-   qc->nsect = scsicmd[13];
+   /* The request -may- be too large for LBA28. */
+   if ((block >> 28) || (n_block > 256))
+    return 1;
+
+   tf->device |= (block >> 24) & 0xf;
   }
 
-  tf->nsect = scsicmd[13];
-  tf->lbal = scsicmd[9];
-  tf->lbam = scsicmd[8];
-  tf->lbah = scsicmd[7];
+  qc->nsect = n_block;
+  tf->nsect = n_block & 0xff;
 
-  VPRINTK("sixteen-byte command\n");
-  return 0;
+  tf->lbah = (block >> 16) & 0xff;
+  tf->lbam = (block >> 8) & 0xff;
+  tf->lbal = block & 0xff;
+
+  tf->device |= ATA_LBA;
+ } else { 
+  /* CHS */
+  u32 sect, head, cyl, track;
+
+  /* The request -may- be too large for CHS addressing. */
+  if ((block >> 28) || (n_block > 256))
+   return 1;
+   
+  /* Convert LBA to CHS */
+  track = (u32)block / dev->sectors;
+  cyl   = track / dev->heads;
+  head  = track % dev->heads;
+  sect  = (u32)block % dev->sectors + 1;
+
+  DPRINTK("block[%u] track[%u] cyl[%u] head[%u] sect[%u] \n", 
+   (u32)block, track, cyl, head, sect);
+  
+  /* Check whether the converted CHS can fit. 
+     Cylinder: 0-65535 
+     Head: 0-15
+     Sector: 1-255*/
+  if ((cyl >> 16) || (head >> 4) || (sect >> 8) || (!sect)) 
+   return 1;
+  
+  qc->nsect = n_block;
+  tf->nsect = n_block & 0xff; /* Sector count 0 means 256 sectors */
+  tf->lbal = sect;
+  tf->lbam = cyl;
+  tf->lbah = cyl >> 8;
+  tf->device |= head;
  }
 
- DPRINTK("no-byte command\n");
- return 1;
+ return 0;
 }
 
 static int ata_scsi_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat)
@@ -1422,10 +1485,20 @@
 
  VPRINTK("ENTER\n");
 
- if (ata_id_has_lba48(args->id))
-  n_sectors = ata_id_u64(args->id, 100);
- else
-  n_sectors = ata_id_u32(args->id, 60);
+ if (ata_id_has_lba(args->id)) {
+  if (ata_id_has_lba48(args->id))
+   n_sectors = ata_id_u64(args->id, 100);
+  else
+   n_sectors = ata_id_u32(args->id, 60);
+ } else {
+  /* CHS default translation */
+  n_sectors = args->id[1] * args->id[3] * args->id[6];
+
+  if (ata_id_current_chs_valid(args->id))
+   /* CHS current translation */
+   n_sectors = ata_id_u32(args->id, 57);
+ }
+
  n_sectors--;  /* ATA TotalUserSectors - 1 */
 
  tmp = n_sectors; /* note: truncates, if lba48 */

[-- Attachment #2: chs3.diff --]
[-- Type: application/octet-stream, Size: 10047 bytes --]

--- libata-dev-2.6/drivers/scsi/libata-scsi.c	2005-02-05 10:41:49.000000000 +0800
+++ libata-dev-2.6-mod/drivers/scsi/libata-scsi.c	2005-02-05 12:46:26.000000000 +0800
@@ -689,72 +689,101 @@
 static unsigned int ata_scsi_verify_xlat(struct ata_queued_cmd *qc, u8 *scsicmd)
 {
 	struct ata_taskfile *tf = &qc->tf;
+	struct ata_device *dev = qc->dev;
+	unsigned int lba   = tf->flags & ATA_TFLAG_LBA;
 	unsigned int lba48 = tf->flags & ATA_TFLAG_LBA48;
 	u64 dev_sectors = qc->dev->n_sectors;
-	u64 sect = 0;
-	u32 n_sect = 0;
+	u64 block = 0;
+	u32 n_block = 0;
 
 	tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
 	tf->protocol = ATA_PROT_NODATA;
-	tf->device |= ATA_LBA;
 
 	if (scsicmd[0] == VERIFY) {
-		sect |= ((u64)scsicmd[2]) << 24;
-		sect |= ((u64)scsicmd[3]) << 16;
-		sect |= ((u64)scsicmd[4]) << 8;
-		sect |= ((u64)scsicmd[5]);
+		block |= ((u64)scsicmd[2]) << 24;
+		block |= ((u64)scsicmd[3]) << 16;
+		block |= ((u64)scsicmd[4]) << 8;
+		block |= ((u64)scsicmd[5]);
 
-		n_sect |= ((u32)scsicmd[7]) << 8;
-		n_sect |= ((u32)scsicmd[8]);
+		n_block |= ((u32)scsicmd[7]) << 8;
+		n_block |= ((u32)scsicmd[8]);
 	}
 
 	else if (scsicmd[0] == VERIFY_16) {
-		sect |= ((u64)scsicmd[2]) << 56;
-		sect |= ((u64)scsicmd[3]) << 48;
-		sect |= ((u64)scsicmd[4]) << 40;
-		sect |= ((u64)scsicmd[5]) << 32;
-		sect |= ((u64)scsicmd[6]) << 24;
-		sect |= ((u64)scsicmd[7]) << 16;
-		sect |= ((u64)scsicmd[8]) << 8;
-		sect |= ((u64)scsicmd[9]);
-
-		n_sect |= ((u32)scsicmd[10]) << 24;
-		n_sect |= ((u32)scsicmd[11]) << 16;
-		n_sect |= ((u32)scsicmd[12]) << 8;
-		n_sect |= ((u32)scsicmd[13]);
+		block |= ((u64)scsicmd[2]) << 56;
+		block |= ((u64)scsicmd[3]) << 48;
+		block |= ((u64)scsicmd[4]) << 40;
+		block |= ((u64)scsicmd[5]) << 32;
+		block |= ((u64)scsicmd[6]) << 24;
+		block |= ((u64)scsicmd[7]) << 16;
+		block |= ((u64)scsicmd[8]) << 8;
+		block |= ((u64)scsicmd[9]);
+
+		n_block |= ((u32)scsicmd[10]) << 24;
+		n_block |= ((u32)scsicmd[11]) << 16;
+		n_block |= ((u32)scsicmd[12]) << 8;
+		n_block |= ((u32)scsicmd[13]);
 	}
 
 	else
 		return 1;
 
-	if (!n_sect)
+	if (!n_block)
 		return 1;
-	if (sect >= dev_sectors)
+	if (block >= dev_sectors)
 		return 1;
-	if ((sect + n_sect) > dev_sectors)
+	if ((block + n_block) > dev_sectors)
 		return 1;
 	if (lba48) {
-		if (n_sect > (64 * 1024))
+		if (n_block > (64 * 1024))
 			return 1;
 	} else {
-		if (n_sect > 256)
+		if (n_block > 256)
 			return 1;
 	}
 
-	if (lba48) {
-		tf->hob_nsect = (n_sect >> 8) & 0xff;
+	if (lba) {
+		if (lba48) {
+			tf->hob_nsect = (n_block >> 8) & 0xff;
 
-		tf->hob_lbah = (sect >> 40) & 0xff;
-		tf->hob_lbam = (sect >> 32) & 0xff;
-		tf->hob_lbal = (sect >> 24) & 0xff;
-	} else
-		tf->device |= (sect >> 24) & 0xf;
+			tf->hob_lbah = (block >> 40) & 0xff;
+			tf->hob_lbam = (block >> 32) & 0xff;
+			tf->hob_lbal = (block >> 24) & 0xff;
+		} else
+			tf->device |= (block >> 24) & 0xf;
+
+		tf->nsect = n_block & 0xff;
 
-	tf->nsect = n_sect & 0xff;
+		tf->lbah = (block >> 16) & 0xff;
+		tf->lbam = (block >> 8) & 0xff;
+		tf->lbal = block & 0xff;
 
-	tf->hob_lbah = (sect >> 16) & 0xff;
-	tf->hob_lbam = (sect >> 8) & 0xff;
-	tf->hob_lbal = sect & 0xff;
+		tf->device |= ATA_LBA;
+	} else {
+		/* CHS */
+		u32 sect, head, cyl, track;
+
+		/* Convert LBA to CHS */
+		track = (u32)block / dev->sectors;
+		cyl   = track / dev->heads;
+		head  = track % dev->heads;
+		sect  = (u32)block % dev->sectors + 1;
+
+		DPRINTK("block[%u] track[%u] cyl[%u] head[%u] sect[%u] \n", (u32)block, track, cyl, head, sect);
+		
+		/* Check whether the converted CHS can fit. 
+		   Cylinder: 0-65535 
+		   Head: 0-15
+		   Sector: 1-255*/
+		if ((cyl >> 16) || (head >> 4) || (sect >> 8) || (!sect)) 
+			return 1;
+		
+		tf->nsect = n_block & 0xff; /* Sector count 0 means 256 sectors */
+		tf->lbal = sect;
+		tf->lbam = cyl;
+		tf->lbah = cyl >> 8;
+		tf->device |= head;
+	}
 
 	return 0;
 }
@@ -782,11 +811,14 @@
 static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, u8 *scsicmd)
 {
 	struct ata_taskfile *tf = &qc->tf;
+	struct ata_device *dev = qc->dev;
+	unsigned int lba   = tf->flags & ATA_TFLAG_LBA;
 	unsigned int lba48 = tf->flags & ATA_TFLAG_LBA48;
+	u64 block = 0;
+	u32 n_block = 0;
 
 	tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
 	tf->protocol = qc->dev->xfer_protocol;
-	tf->device |= ATA_LBA;
 
 	if (scsicmd[0] == READ_10 || scsicmd[0] == READ_6 ||
 	    scsicmd[0] == READ_16) {
@@ -796,80 +828,111 @@
 		tf->flags |= ATA_TFLAG_WRITE;
 	}
 
+	/* Calculate the SCSI LBA and transfer length. */
 	if (scsicmd[0] == READ_10 || scsicmd[0] == WRITE_10) {
-		if (lba48) {
-			tf->hob_nsect = scsicmd[7];
-			tf->hob_lbal = scsicmd[2];
+		block |= ((u64)scsicmd[2]) << 24;
+		block |= ((u64)scsicmd[3]) << 16;
+		block |= ((u64)scsicmd[4]) << 8;
+		block |= ((u64)scsicmd[5]);
 
-			qc->nsect = ((unsigned int)scsicmd[7] << 8) |
-					scsicmd[8];
-		} else {
-			/* if we don't support LBA48 addressing, the request
-			 * -may- be too large. */
-			if ((scsicmd[2] & 0xf0) || scsicmd[7])
-				return 1;
-
-			/* stores LBA27:24 in lower 4 bits of device reg */
-			tf->device |= scsicmd[2];
-
-			qc->nsect = scsicmd[8];
-		}
-
-		tf->nsect = scsicmd[8];
-		tf->lbal = scsicmd[5];
-		tf->lbam = scsicmd[4];
-		tf->lbah = scsicmd[3];
+		n_block |= ((u32)scsicmd[7]) << 8;
+		n_block |= ((u32)scsicmd[8]);
 
 		VPRINTK("ten-byte command\n");
-		return 0;
-	}
-
-	if (scsicmd[0] == READ_6 || scsicmd[0] == WRITE_6) {
-		qc->nsect = tf->nsect = scsicmd[4];
-		tf->lbal = scsicmd[3];
-		tf->lbam = scsicmd[2];
-		tf->lbah = scsicmd[1] & 0x1f; /* mask out reserved bits */
-
+	} else if (scsicmd[0] == READ_6 || scsicmd[0] == WRITE_6) {
+		block |= ((u64)scsicmd[2]) << 8;
+		block |= ((u64)scsicmd[3]);
+		n_block |= ((u32)scsicmd[4]);
+	
 		VPRINTK("six-byte command\n");
-		return 0;
+	} else if (scsicmd[0] == READ_16 || scsicmd[0] == WRITE_16) {
+		block |= ((u64)scsicmd[2]) << 56;
+		block |= ((u64)scsicmd[3]) << 48;
+		block |= ((u64)scsicmd[4]) << 40;
+		block |= ((u64)scsicmd[5]) << 32;
+		block |= ((u64)scsicmd[6]) << 24;
+		block |= ((u64)scsicmd[7]) << 16;
+		block |= ((u64)scsicmd[8]) << 8;
+		block |= ((u64)scsicmd[9]);
+
+		n_block |= ((u32)scsicmd[10]) << 24;
+		n_block |= ((u32)scsicmd[11]) << 16;
+		n_block |= ((u32)scsicmd[12]) << 8;
+		n_block |= ((u32)scsicmd[13]);
+
+		VPRINTK("sixteen-byte command\n");
+	} else {
+		DPRINTK("no-byte command\n");
+		return 1;
 	}
 
-	if (scsicmd[0] == READ_16 || scsicmd[0] == WRITE_16) {
-		/* rule out impossible LBAs and sector counts */
-		if (scsicmd[2] || scsicmd[3] || scsicmd[10] || scsicmd[11])
-			return 1;
+	/* Check and compose ATA command */
+	if (!n_block)
+		/* In ATA, sector count 0 are 256 or 65536 sectors, not 0 sectors. */
+		return 1;
 
+	if (lba) {
 		if (lba48) {
-			tf->hob_nsect = scsicmd[12];
-			tf->hob_lbal = scsicmd[6];
-			tf->hob_lbam = scsicmd[5];
-			tf->hob_lbah = scsicmd[4];
-
-			qc->nsect = ((unsigned int)scsicmd[12] << 8) |
-					scsicmd[13];
-		} else {
-			/* once again, filter out impossible non-zero values */
-			if (scsicmd[4] || scsicmd[5] || scsicmd[12] ||
-			    (scsicmd[6] & 0xf0))
+			/* The request -may- be too large for LBA48. */
+			if ((block >> 48) || (n_block > 65536))
 				return 1;
 
-			/* stores LBA27:24 in lower 4 bits of device reg */
-			tf->device |= scsicmd[2];
+			tf->hob_nsect = (n_block >> 8) & 0xff;
+
+			tf->hob_lbah = (block >> 40) & 0xff;
+			tf->hob_lbam = (block >> 32) & 0xff;
+			tf->hob_lbal = (block >> 24) & 0xff;
+		} else { 
+			/* LBA28 */
 
-			qc->nsect = scsicmd[13];
+			/* The request -may- be too large for LBA28. */
+			if ((block >> 28) || (n_block > 256))
+				return 1;
+
+			tf->device |= (block >> 24) & 0xf;
 		}
 
-		tf->nsect = scsicmd[13];
-		tf->lbal = scsicmd[9];
-		tf->lbam = scsicmd[8];
-		tf->lbah = scsicmd[7];
+		qc->nsect = n_block;
+		tf->nsect = n_block & 0xff;
 
-		VPRINTK("sixteen-byte command\n");
-		return 0;
+		tf->lbah = (block >> 16) & 0xff;
+		tf->lbam = (block >> 8) & 0xff;
+		tf->lbal = block & 0xff;
+
+		tf->device |= ATA_LBA;
+	} else { 
+		/* CHS */
+		u32 sect, head, cyl, track;
+
+		/* The request -may- be too large for CHS addressing. */
+		if ((block >> 28) || (n_block > 256))
+			return 1;
+			
+		/* Convert LBA to CHS */
+		track = (u32)block / dev->sectors;
+		cyl   = track / dev->heads;
+		head  = track % dev->heads;
+		sect  = (u32)block % dev->sectors + 1;
+
+		DPRINTK("block[%u] track[%u] cyl[%u] head[%u] sect[%u] \n", 
+			(u32)block, track, cyl, head, sect);
+		
+		/* Check whether the converted CHS can fit. 
+		   Cylinder: 0-65535 
+		   Head: 0-15
+		   Sector: 1-255*/
+		if ((cyl >> 16) || (head >> 4) || (sect >> 8) || (!sect)) 
+			return 1;
+		
+		qc->nsect = n_block;
+		tf->nsect = n_block & 0xff; /* Sector count 0 means 256 sectors */
+		tf->lbal = sect;
+		tf->lbam = cyl;
+		tf->lbah = cyl >> 8;
+		tf->device |= head;
 	}
 
-	DPRINTK("no-byte command\n");
-	return 1;
+	return 0;
 }
 
 static int ata_scsi_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat)
@@ -1422,10 +1485,20 @@
 
 	VPRINTK("ENTER\n");
 
-	if (ata_id_has_lba48(args->id))
-		n_sectors = ata_id_u64(args->id, 100);
-	else
-		n_sectors = ata_id_u32(args->id, 60);
+	if (ata_id_has_lba(args->id)) {
+		if (ata_id_has_lba48(args->id))
+			n_sectors = ata_id_u64(args->id, 100);
+		else
+			n_sectors = ata_id_u32(args->id, 60);
+	} else {
+		/* CHS default translation */
+		n_sectors = args->id[1] * args->id[3] * args->id[6];
+
+		if (ata_id_current_chs_valid(args->id))
+			/* CHS current translation */
+			n_sectors = ata_id_u32(args->id, 57);
+	}
+
 	n_sectors--;		/* ATA TotalUserSectors - 1 */
 
 	tmp = n_sectors;	/* note: truncates, if lba48 */

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2005-02-06  6:08 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-02-06  6:08 [PATCH libata-dev-2.6 3/3] Add CHS support Albert Lee

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).