===== drivers/scsi/sd.c 1.161 vs edited ===== --- 1.161/drivers/scsi/sd.c 2004-10-15 10:46:07 -04:00 +++ edited/drivers/scsi/sd.c 2004-10-25 13:28:23 -04:00 @@ -987,6 +987,152 @@ } } +/* sd_read_true_cap: Some device servers incorrectly return the + * capacity as opposed to the LBA of the last logical block of the + * block device. + * + * We try to fix this as follows: Let x = Returned LBA from the last + * READ CAPACITY command issued (result in "buffer"). Reissue the + * READ CAPACITY command as follows: set the partial medium indicator + * (PMI) bit to one; set the LBA to x - 1. Fire off that READ CAPACITY + * command. + * + * If we get success, + * If Returned LBA > x - 1, then capacity is x+1, spec behavior. + * Else Returned LBA <= x - 1, then capacity is x, broken device server. + * Else error, nothing can be assumed, capacity is x+1. + */ +static void sd_read_true_cap(struct scsi_disk *sd, char *diskname, + struct scsi_request *SRpnt, unsigned char *buffer, + int longrc) +{ + unsigned char cmd[16]; + unsigned char buf[12]; + + /* save the old buffer contents here */ + memcpy(buf, buffer, 12); + + if (longrc) { + u64 *lba = (u64 *) (cmd+2); + u64 rlba; + + memset((void *) cmd, 0, 16); + cmd[0] = SERVICE_ACTION_IN; + cmd[1] = SAI_READ_CAPACITY_16; + cmd[13] = 12; + + rlba = be64_to_cpu(*(u64 *)buffer); + rlba -= 1; + *lba = cpu_to_be64(rlba); + /* turn on the PMI bit */ + cmd[14] |= 1; + memset((void *) buffer, 0, 12); + } else { + u32 *lba = (u32 *) (cmd+2); + u32 rlba; + + cmd[0] = READ_CAPACITY; + memset((void *) &cmd[1], 0, 9); + + rlba = be32_to_cpu(*(u32 *)buffer); + rlba -= 1; + *lba = cpu_to_be32(rlba); + /* turn on the PMI bit */ + cmd[8] |= 1; + memset((void *) buffer, 0, 8); + } + + SRpnt->sr_cmd_len = 0; + SRpnt->sr_sense_buffer[0] = 0; + SRpnt->sr_sense_buffer[2] = 0; + SRpnt->sr_data_direction = DMA_FROM_DEVICE; + + scsi_wait_req(SRpnt, (void *) cmd, (void *) buffer, + longrc ? 12 : 8, SD_TIMEOUT, SD_MAX_RETRIES); + + if (SRpnt->sr_result) { + /* Nothing can be assumed. */ + printk(KERN_NOTICE "%s: %s: PMI not supported\n", + __FUNCTION__, diskname); + memcpy(buffer, buf, 12); + return; + } + + if (longrc) { + u64 rlba = be64_to_cpu(*(u64 *)buffer); + u64 x = be64_to_cpu(*(u64 *)buf); + if (rlba > x - 1) { + goto out_spec; + } + } else { + u32 rlba = be32_to_cpu(*(u32 *)buffer); + u32 x = be32_to_cpu(*(u32 *)buf); + if (rlba > x - 1) { + goto out_spec; + } + } + printk(KERN_NOTICE "%s: %s: broken device server\n", __FUNCTION__, + diskname); + return; + + out_spec: + /* Capacity is x+1, spec behavior. */ + printk(KERN_NOTICE "%s: %s: spec behavior\n", __FUNCTION__, diskname); + memcpy(buffer, buf, 12); +} /* end sd_read_true_cap() */ + + +/* Try to use the READ FORMAT CAPACITIES command to check whether the + * READ CAPACITY result is correct. + */ +static void sd_read_format_cap(struct scsi_disk *sd, char *diskname, + struct scsi_request *SRpnt, unsigned char *buffer) +{ + unsigned char cmd[12]; + unsigned char buf[12]; + u32 rlba; + u32 x; + + /* save the old buffer contents here */ + memcpy(buf, buffer, 12); + + rlba = be32_to_cpu(*(u32 *)buffer); + + cmd[0] = 0x23; /* READ_FORMAT_CAPACITIES */ + memset(&cmd[1], 0, 11); + cmd[8] = 12; + memset(buffer, 0, 12); + + SRpnt->sr_cmd_len = 0; + SRpnt->sr_sense_buffer[0] = 0; + SRpnt->sr_sense_buffer[2] = 0; + SRpnt->sr_data_direction = DMA_FROM_DEVICE; + + scsi_wait_req(SRpnt, (void *) cmd, (void *) buffer, + 12, SD_TIMEOUT, SD_MAX_RETRIES); + + if (SRpnt->sr_result) { + /* Nothing can be assumed. */ + printk(KERN_NOTICE "%s: %s: READ FORMAT CAPACITIES " + "not supported\n", __FUNCTION__, diskname); + goto done; + } + + x = be32_to_cpu(*(u32 *)(buffer + 4)); + printk(KERN_NOTICE "%s: %s: %u vs. %u\n", + __FUNCTION__, diskname, rlba, x); + if (0 < x && x <= rlba) { + u32 *lba = (u32 *) buf; + + printk(KERN_NOTICE "%s: %s: using lower capacity\n", + __FUNCTION__, diskname); + x -= 1; + *lba = cpu_to_be32(x); + } + done: + memcpy(buffer, buf, 12); +} + /* * read disk capacity */ @@ -1070,7 +1216,14 @@ sdkp->capacity = 1 + (sector_t) 0xffffffff; goto got_data; - } + } + + /* Check if the device reported CAPACITY as opposed to + * the maxumum LBA (as per the SBC spec). + */ + sd_read_true_cap(sdkp, diskname, SRpnt, buffer, longrc); + if (!longrc) + sd_read_format_cap(sdkp, diskname, SRpnt, buffer); if (!longrc) { sector_size = (buffer[4] << 24) | @@ -1078,12 +1231,14 @@ if (buffer[0] == 0xff && buffer[1] == 0xff && buffer[2] == 0xff && buffer[3] == 0xff) { if(sizeof(sdkp->capacity) > 4) { - printk(KERN_NOTICE "%s : very big device. try to use" - " READ CAPACITY(16).\n", diskname); + printk(KERN_NOTICE "%s : very big device. " + "try to use READ CAPACITY(16).\n", + diskname); longrc = 1; goto repeat; } else { - printk(KERN_ERR "%s: too big for kernel. Assuming maximum 2Tb\n", diskname); + printk(KERN_ERR "%s: too big for kernel. " + "Assuming maximum 2Tb\n", diskname); } } sdkp->capacity = 1 + (((sector_t)buffer[0] << 24) | @@ -1102,7 +1257,7 @@ sector_size = (buffer[8] << 24) | (buffer[9] << 16) | (buffer[10] << 8) | buffer[11]; - } + } got_data: if (sector_size == 0) {