ahci(4)/sili(4): Fix for drives >2TB.
authorSascha Wildner <saw@online.de>
Mon, 13 Aug 2012 00:33:30 +0000 (02:33 +0200)
committerSascha Wildner <saw@online.de>
Mon, 13 Aug 2012 00:34:24 +0000 (02:34 +0200)
CAM will issue the 16 byte version of the READ CAPACITY command when
maxsector is 0xffffffff:

----- scsi_da.c -----
if (maxsector == 0xffffffff) {
softc->state = DA_STATE_PROBE2;
kfree(rdcap, M_SCSIDA);
xpt_release_ccb(done_ccb);
xpt_schedule(periph, /*priority*/5);
return;
}
---------------------

However, we are subtracting 1 from it (presumably because it's a "last
sector on the device" value starting at 0) so in CAM, it ended up being
0xfffffffe, resulting in disks attached via ahci(4) and sili(4) to be
limited to 2TB.

To fix, set the local var to 0 in this case, so that after subtracting 1
from the value (cast to 32 bit) CAM gets 0xffffffff.

Fix-by: dillon
sys/dev/disk/ahci/ahci_cam.c
sys/dev/disk/sili/sili_cam.c

index d225919..3b5d857 100644 (file)
@@ -1121,8 +1121,14 @@ ahci_xpt_scsi_disk_io(struct ahci_port *ap, struct ata_port *atx,
                bzero(rdata, rdata_len);
                if (cdb->generic.opcode == READ_CAPACITY) {
                        rdata_len = sizeof(rdata->read_capacity_data);
-                       if (capacity > 0xFFFFFFFFU)
-                               capacity = 0xFFFFFFFFU;
+                       if (capacity > 0xFFFFFFFFU) {
+                               /*
+                                * Set capacity to 0 so maxsector winds up
+                                * being 0xffffffff in CAM in order to trigger
+                                * DA_STATE_PROBE2.
+                                */
+                               capacity = 0;
+                       }
                        bzero(&rdata->read_capacity_data, rdata_len);
                        scsi_ulto4b((u_int32_t)capacity - 1,
                                    rdata->read_capacity_data.addr);
index 11fc695..ec4350b 100644 (file)
@@ -1093,8 +1093,14 @@ sili_xpt_scsi_disk_io(struct sili_port *ap, struct ata_port *atx,
                bzero(rdata, rdata_len);
                if (cdb->generic.opcode == READ_CAPACITY) {
                        rdata_len = sizeof(rdata->read_capacity_data);
-                       if (capacity > 0xFFFFFFFFU)
-                               capacity = 0xFFFFFFFFU;
+                       if (capacity > 0xFFFFFFFFU) {
+                               /*
+                                * Set capacity to 0 so maxsector winds up
+                                * being 0xffffffff in CAM in order to trigger
+                                * DA_STATE_PROBE2.
+                                */
+                               capacity = 0;
+                       }
                        bzero(&rdata->read_capacity_data, rdata_len);
                        scsi_ulto4b((u_int32_t)capacity - 1,
                                    rdata->read_capacity_data.addr);