[haiku-commits] r39252 - in haiku/trunk: headers/private/drivers src/add-ons/kernel/bus_managers/ata src/add-ons/kernel/drivers/disk/scsi/scsi_disk src/add-ons/kernel/generic/scsi_periph

  • From: korli@xxxxxxxxxxxxxxxx
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Mon, 1 Nov 2010 17:31:09 +0100 (CET)

Author: korli
Date: 2010-11-01 17:31:09 +0100 (Mon, 01 Nov 2010)
New Revision: 39252
Changeset: http://dev.haiku-os.org/changeset/39252

Modified:
   haiku/trunk/headers/private/drivers/scsi_cmds.h
   haiku/trunk/src/add-ons/kernel/bus_managers/ata/ATADevice.cpp
   haiku/trunk/src/add-ons/kernel/bus_managers/ata/ATAPrivate.h
   haiku/trunk/src/add-ons/kernel/drivers/disk/scsi/scsi_disk/scsi_disk.cpp
   haiku/trunk/src/add-ons/kernel/generic/scsi_periph/block.cpp
Log:
* ata: added ATADevice::ReadCapacity16()
* ata: don't fail if lba_sector_count is null and lba48_sector_count is not
* scsi_periph: if ReadCapacity() returns 0xffffffff, use ReadCapacity16() 
instead
* scsi_disk: use a different computation in the struct geometry computation for 
bigger disks
Tested successfully with a virtual 10TB hard drive.


Modified: haiku/trunk/headers/private/drivers/scsi_cmds.h
===================================================================
--- haiku/trunk/headers/private/drivers/scsi_cmds.h     2010-11-01 15:37:46 UTC 
(rev 39251)
+++ haiku/trunk/headers/private/drivers/scsi_cmds.h     2010-11-01 16:31:09 UTC 
(rev 39252)
@@ -313,7 +313,7 @@
        char    psn[1];                 // size according to page_length
 } _PACKED scsi_page_usn;
 
-// READ CAPACITY
+// READ CAPACITY (10)
 
 typedef struct scsi_cmd_read_capacity {
        uint8   opcode;
@@ -336,7 +336,23 @@
        uint32  block_size;                             // in bytes
 } _PACKED scsi_res_read_capacity;
 
+// READ CAPACITY (16)
 
+typedef struct scsi_cmd_read_capacity_long {
+       uint8   opcode;
+       uint8   service_action;
+       uint64  lba;
+       uint32  alloc_length;
+       uint8   relative_address;
+       uint8   control;
+} _PACKED scsi_cmd_read_capacity_long;
+
+typedef struct scsi_res_read_capacity_long {
+       uint64  lba;                                    // big endian
+       uint32  block_size;                             // in bytes
+} _PACKED scsi_res_read_capacity_long;
+
+
 // READ (6), WRITE (6)
 
 typedef struct scsi_cmd_rw_6 {

Modified: haiku/trunk/src/add-ons/kernel/bus_managers/ata/ATADevice.cpp
===================================================================
--- haiku/trunk/src/add-ons/kernel/bus_managers/ata/ATADevice.cpp       
2010-11-01 15:37:46 UTC (rev 39251)
+++ haiku/trunk/src/add-ons/kernel/bus_managers/ata/ATADevice.cpp       
2010-11-01 16:31:09 UTC (rev 39252)
@@ -182,7 +182,27 @@
        uint32 lastBlock = fTotalSectors - 1;
        data.lba = B_HOST_TO_BENDIAN_INT32(lastBlock);
        TRACE("returning last block: %lu\n", B_BENDIAN_TO_HOST_INT32(data.lba));
+       
+       copy_sg_data(ccb, 0, ccb->data_length, &data, sizeof(data), false);
+       ccb->data_resid = MAX(ccb->data_length - sizeof(data), 0);
+       return B_OK;
+}
 
+
+status_t
+ATADevice::ReadCapacity16(ATARequest *request)
+{
+       TRACE_FUNCTION("%p\n", request);
+       
+       scsi_ccb *ccb = request->CCB();
+       scsi_res_read_capacity_long data;
+       data.block_size = B_HOST_TO_BENDIAN_INT32(fBlockSize);
+
+       uint64 lastBlock = fTotalSectors - 1;
+       data.lba = (((uint64)B_HOST_TO_BENDIAN_INT32(lastBlock >> 32)) << 32)
+               | B_HOST_TO_BENDIAN_INT32(lastBlock);
+       TRACE("returning last block: %llu\n", data.lba);
+
        copy_sg_data(ccb, 0, ccb->data_length, &data, sizeof(data), false);
        ccb->data_resid = MAX(ccb->data_length - sizeof(data), 0);
        return B_OK;
@@ -251,6 +271,11 @@
                case SCSI_OP_READ_CAPACITY:
                        return ReadCapacity(request);
 
+               case SCSI_OP_SERVICE_ACTION_IN:
+                       if ((ccb->cdb[1] & 0x1f) == SCSI_SAI_READ_CAPACITY_16)
+                               return ReadCapacity16(request);
+                       break;
+
                case SCSI_OP_SYNCHRONIZE_CACHE:
                        // we ignore range and immediate bit, we always 
immediately
                        // flush everything
@@ -443,7 +468,8 @@
                }
        }
 
-       if (!fInfoBlock.lba_supported || fInfoBlock.lba_sector_count == 0) {
+       if (!fInfoBlock.lba_supported || (fInfoBlock.lba_sector_count == 0
+               && fInfoBlock.lba48_sector_count == 0)) {
                TRACE_ERROR("non-lba devices not supported\n");
                return B_ERROR;
        }

Modified: haiku/trunk/src/add-ons/kernel/bus_managers/ata/ATAPrivate.h
===================================================================
--- haiku/trunk/src/add-ons/kernel/bus_managers/ata/ATAPrivate.h        
2010-11-01 15:37:46 UTC (rev 39251)
+++ haiku/trunk/src/add-ons/kernel/bus_managers/ata/ATAPrivate.h        
2010-11-01 16:31:09 UTC (rev 39252)
@@ -176,6 +176,7 @@
                        status_t                        Eject(ATARequest 
*request);
                        status_t                        Inquiry(ATARequest 
*request);
                        status_t                        ReadCapacity(ATARequest 
*request);
+                       status_t                        
ReadCapacity16(ATARequest *request);
        virtual status_t                        ExecuteIO(ATARequest *request);
 
                        void                            GetRestrictions(bool 
*noAutoSense,

Modified: 
haiku/trunk/src/add-ons/kernel/drivers/disk/scsi/scsi_disk/scsi_disk.cpp
===================================================================
--- haiku/trunk/src/add-ons/kernel/drivers/disk/scsi/scsi_disk/scsi_disk.cpp    
2010-11-01 15:37:46 UTC (rev 39251)
+++ haiku/trunk/src/add-ons/kernel/drivers/disk/scsi/scsi_disk/scsi_disk.cpp    
2010-11-01 16:31:09 UTC (rev 39252)
@@ -92,9 +92,16 @@
                return status;
 
        geometry->bytes_per_sector = info->block_size;
-       geometry->sectors_per_track = 1;
-       geometry->cylinder_count = info->capacity;
-       geometry->head_count = 1;
+       if (info->capacity > UINT_MAX) {
+               // TODO this doesn't work for capacity greater than 35TB
+               geometry->sectors_per_track = 256;
+               geometry->cylinder_count = info->capacity / (256 * 32);
+               geometry->head_count = 32;
+       } else {
+               geometry->sectors_per_track = 1;
+               geometry->cylinder_count = info->capacity;
+               geometry->head_count = 1;
+       }
        geometry->device_type = B_DISK;
        geometry->removable = info->removable;
 
@@ -323,7 +330,7 @@
        das_handle* handle = (das_handle*)cookie;
        das_driver_info* info = handle->info;
 
-       TRACE("ioctl(op = %d)\n", op);
+       TRACE("ioctl(op = %ld)\n", op);
 
        switch (op) {
                case B_GET_DEVICE_SIZE:
@@ -398,7 +405,7 @@
 das_set_capacity(das_driver_info* info, uint64 capacity, uint32 blockSize)
 {
        TRACE("das_set_capacity(device = %p, capacity = %Ld, blockSize = 
%ld)\n",
-               device, capacity, blockSize);
+               info, capacity, blockSize);
 
        // get log2, if possible
        uint32 blockShift = log2(blockSize);

Modified: haiku/trunk/src/add-ons/kernel/generic/scsi_periph/block.cpp
===================================================================
--- haiku/trunk/src/add-ons/kernel/generic/scsi_periph/block.cpp        
2010-11-01 15:37:46 UTC (rev 39251)
+++ haiku/trunk/src/add-ons/kernel/generic/scsi_periph/block.cpp        
2010-11-01 16:31:09 UTC (rev 39252)
@@ -56,6 +56,33 @@
        if (res == B_OK && request->data_resid == 0) {
                capacity = B_BENDIAN_TO_HOST_INT32(capacityResult.lba);
 
+               if (capacity == UINT_MAX) {
+                       RELEASE_BEN(&device->mutex);
+                       
+                       scsi_cmd_read_capacity_long *cmd =
+                               (scsi_cmd_read_capacity_long *)request->cdb;
+                       
+                       scsi_res_read_capacity_long capacityLongResult;
+                       request->data = (uint8*)&capacityLongResult;
+                       request->data_length = sizeof(capacityLongResult);
+                       request->cdb_length = 
sizeof(scsi_cmd_read_capacity_long);
+
+                       memset(cmd, 0, sizeof(*cmd));
+                       cmd->opcode = SCSI_OP_SERVICE_ACTION_IN;
+                       cmd->service_action = SCSI_SAI_READ_CAPACITY_16;
+
+                       res = periph_safe_exec(device, request);
+
+                       ACQUIRE_BEN(&device->mutex);
+
+                       if (res == B_OK && request->data_resid == 0) {
+                               capacity = (((uint64)B_BENDIAN_TO_HOST_INT32(
+                                               capacityLongResult.lba >> 32)) 
<< 32)
+                                       | 
B_BENDIAN_TO_HOST_INT32(capacityLongResult.lba);
+                       } else
+                               capacity = 0;
+               }
+
                // the command returns the index of the _last_ block,
                // i.e. the size is one larger
                ++capacity;
@@ -66,7 +93,7 @@
                blockSize = 0;
        }
 
-       SHOW_FLOW(3, "capacity = %Ld, block_size = %ld", capacity, blockSize);
+       SHOW_FLOW(3, "capacity = %lld, block_size = %ld", capacity, blockSize);
 
        device->block_size = blockSize;
 


Other related posts: