summaryrefslogtreecommitdiff
path: root/common/cmd_scsi.c
diff options
context:
space:
mode:
authorGabe Black <gabeblack@chromium.org>2012-03-13 16:03:33 -0700
committerGerrit <chrome-bot@google.com>2012-03-13 19:21:27 -0700
commit1bd4fbf1cd120275c3f05425ac7273e7d0cb4a0a (patch)
treed74bdabf87a1b497adc2f67387ff0f48bb3764ca /common/cmd_scsi.c
parentcf2aaf1a7d548fa575f3c6a8df0e16b918472d28 (diff)
gen: Make the SCSI command aware of READ CAPACITY (16) and how to use it
The generic SCSI code in U-Boot was only aware of the READ CAPACITY (10) SCSI command which can detect the size of disks up to 2TB in size. If that size is exceeded, it should then try the READ CAPACITY (16) command which returns a 64 bit block count value. BUG=chrome-os-partner:8180 TEST=In conjunction with the next change, built and booted into ChromeOS on the Emerald Lake 2 CRB with a 250 GB SSD. Did the same but forced the READ CAPACITY (10) command to saturate and the code to fall back to READ CAPACITY (16). Note that this code has not be tested with a real SCSI disk, just the AHCI code pretending to be a SCSI disk as it historically has. Change-Id: Ia0ee3fa1264649f25065658d5d368101d39ce614 Signed-off-by: Gabe Black <gabeblack@google.com> Reviewed-on: https://gerrit.chromium.org/gerrit/18060 Reviewed-by: Vincent Palatin <vpalatin@chromium.org>
Diffstat (limited to 'common/cmd_scsi.c')
-rw-r--r--common/cmd_scsi.c93
1 files changed, 67 insertions, 26 deletions
diff --git a/common/cmd_scsi.c b/common/cmd_scsi.c
index 5ecbad040f..3fe48d6d6d 100644
--- a/common/cmd_scsi.c
+++ b/common/cmd_scsi.c
@@ -75,7 +75,6 @@ static block_dev_desc_t scsi_dev_desc[CONFIG_SYS_SCSI_MAX_DEVICE];
* forward declerations of some Setup Routines
*/
void scsi_setup_test_unit_ready(ccb * pccb);
-void scsi_setup_read_capacity(ccb * pccb);
void scsi_setup_read6(ccb * pccb, unsigned long start, unsigned short blocks);
void scsi_setup_read_ext(ccb * pccb, unsigned long start, unsigned short blocks);
void scsi_setup_write_ext(ccb *pccb, unsigned long start,
@@ -84,6 +83,9 @@ void scsi_setup_inquiry(ccb * pccb);
void scsi_ident_cpy (unsigned char *dest, unsigned char *src, unsigned int len);
+static int scsi_read_capacity(ccb *pccb, lbaint_t *capacity,
+ unsigned long *blksz);
+
ulong scsi_read(int device, ulong blknr, lbaint_t blkcnt, void *buffer);
ulong scsi_write(int device, ulong blknr, lbaint_t blkcnt, const void *buffer);
@@ -95,7 +97,8 @@ ulong scsi_write(int device, ulong blknr, lbaint_t blkcnt, const void *buffer);
void scsi_scan(int mode)
{
unsigned char i,perq,modi,lun;
- unsigned long capacity,blksz;
+ lbaint_t capacity;
+ unsigned long blksz;
ccb* pccb=(ccb *)&tempccb;
if(mode==1) {
@@ -160,16 +163,10 @@ void scsi_scan(int mode)
scsi_print_error(pccb);
continue;
}
- pccb->datalen=8;
- scsi_setup_read_capacity(pccb);
- if(scsi_exec(pccb)!=TRUE) {
+ if (scsi_read_capacity(pccb, &capacity, &blksz)) {
scsi_print_error(pccb);
continue;
}
- capacity=((unsigned long)tempbuff[0]<<24)|((unsigned long)tempbuff[1]<<16)|
- ((unsigned long)tempbuff[2]<<8)|((unsigned long)tempbuff[3]);
- blksz=((unsigned long)tempbuff[4]<<24)|((unsigned long)tempbuff[5]<<16)|
- ((unsigned long)tempbuff[6]<<8)|((unsigned long)tempbuff[7]);
scsi_dev_desc[scsi_max_devs].lba=capacity;
scsi_dev_desc[scsi_max_devs].blksz=blksz;
scsi_dev_desc[scsi_max_devs].type=perq;
@@ -635,6 +632,67 @@ void scsi_trim_trail (unsigned char *str, unsigned int len)
}
}
+int scsi_read_capacity(ccb *pccb, lbaint_t *capacity, unsigned long *blksz)
+{
+ *capacity = 0;
+
+ memset(pccb->cmd, 0, sizeof(pccb->cmd));
+ pccb->cmd[0] = SCSI_RD_CAPAC10;
+ pccb->cmd[1] = pccb->lun << 5;
+ pccb->cmdlen = 10;
+ pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */
+
+ pccb->datalen = 8;
+ if (scsi_exec(pccb) != TRUE)
+ return 1;
+
+ *capacity = ((lbaint_t)pccb->pdata[0] << 24) |
+ ((lbaint_t)pccb->pdata[1] << 16) |
+ ((lbaint_t)pccb->pdata[2] << 8) |
+ ((lbaint_t)pccb->pdata[3]);
+
+ if (*capacity != 0xffffffff) {
+ /* Read capacity (10) was sufficient for this drive. */
+ *blksz = ((unsigned long)pccb->pdata[4] << 24) |
+ ((unsigned long)pccb->pdata[5] << 16) |
+ ((unsigned long)pccb->pdata[6] << 8) |
+ ((unsigned long)pccb->pdata[7]);
+ return 0;
+ }
+
+ /* Read capacity (10) was insufficient. Use read capacity (16). */
+
+ memset(pccb->cmd, 0, sizeof(pccb->cmd));
+ pccb->cmd[0] = SCSI_RD_CAPAC16;
+ pccb->cmd[1] = 0x10;
+ pccb->cmdlen = 16;
+ pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */
+
+ pccb->datalen = 16;
+ if (scsi_exec(pccb) != TRUE)
+ return 1;
+
+ *capacity = ((uint64_t)pccb->pdata[0] << 56) |
+ ((uint64_t)pccb->pdata[1] << 48) |
+ ((uint64_t)pccb->pdata[2] << 40) |
+ ((uint64_t)pccb->pdata[3] << 32) |
+ ((uint64_t)pccb->pdata[4] << 24) |
+ ((uint64_t)pccb->pdata[5] << 16) |
+ ((uint64_t)pccb->pdata[6] << 8) |
+ ((uint64_t)pccb->pdata[7]);
+
+ *blksz = ((uint64_t)pccb->pdata[8] << 56) |
+ ((uint64_t)pccb->pdata[9] << 48) |
+ ((uint64_t)pccb->pdata[10] << 40) |
+ ((uint64_t)pccb->pdata[11] << 32) |
+ ((uint64_t)pccb->pdata[12] << 24) |
+ ((uint64_t)pccb->pdata[13] << 16) |
+ ((uint64_t)pccb->pdata[14] << 8) |
+ ((uint64_t)pccb->pdata[15]);
+
+ return 0;
+}
+
/************************************************************************************
* Some setup (fill-in) routines
@@ -651,23 +709,6 @@ void scsi_setup_test_unit_ready(ccb * pccb)
pccb->msgout[0]=SCSI_IDENTIFY; /* NOT USED */
}
-void scsi_setup_read_capacity(ccb * pccb)
-{
- pccb->cmd[0]=SCSI_RD_CAPAC;
- pccb->cmd[1]=pccb->lun<<5;
- pccb->cmd[2]=0;
- pccb->cmd[3]=0;
- pccb->cmd[4]=0;
- pccb->cmd[5]=0;
- pccb->cmd[6]=0;
- pccb->cmd[7]=0;
- pccb->cmd[8]=0;
- pccb->cmd[9]=0;
- pccb->cmdlen=10;
- pccb->msgout[0]=SCSI_IDENTIFY; /* NOT USED */
-
-}
-
void scsi_setup_read_ext(ccb * pccb, unsigned long start, unsigned short blocks)
{
pccb->cmd[0]=SCSI_READ10;