1 /* 2 * Copyright 2004-2013, Haiku, Inc. All RightsReserved. 3 * Copyright 2002-2003, Thomas Kurschel. All rights reserved. 4 * 5 * Distributed under the terms of the MIT License. 6 */ 7 8 9 //! Handling of block device 10 11 12 #include <string.h> 13 14 #include <AutoDeleter.h> 15 16 #include "scsi_periph_int.h" 17 18 19 status_t 20 periph_check_capacity(scsi_periph_device_info *device, scsi_ccb *request) 21 { 22 scsi_res_read_capacity capacityResult; 23 scsi_cmd_read_capacity *cmd = (scsi_cmd_read_capacity *)request->cdb; 24 uint64 capacity; 25 uint32 blockSize; 26 status_t res; 27 28 SHOW_FLOW(3, "%p, %p", device, request); 29 30 // driver doesn't support capacity callback - seems to be no block 31 // device driver, so ignore 32 if (device->callbacks->set_capacity == NULL) 33 return B_OK; 34 35 request->flags = SCSI_DIR_IN; 36 37 request->data = (uint8*)&capacityResult; 38 request->data_length = sizeof(capacityResult); 39 request->cdb_length = sizeof(scsi_cmd_read_capacity); 40 request->timeout = device->std_timeout; 41 request->sort = -1; 42 request->sg_list = NULL; 43 44 memset(cmd, 0, sizeof(*cmd)); 45 cmd->opcode = SCSI_OP_READ_CAPACITY; 46 // we don't set PMI (partial medium indicator) as we want the whole capacity; 47 // in this case, all other parameters must be zero 48 49 res = periph_safe_exec(device, request); 50 51 if (res == B_DEV_MEDIA_CHANGED) { 52 // in this case, the error handler has already called check_capacity 53 // recursively, so we ignore our (invalid) result 54 SHOW_FLOW0( 3, "ignore result because medium change" ); 55 return B_DEV_MEDIA_CHANGED; 56 } 57 58 mutex_lock(&device->mutex); 59 60 if (res == B_OK && request->data_resid == 0) { 61 capacity = B_BENDIAN_TO_HOST_INT32(capacityResult.lba); 62 63 if (capacity == UINT_MAX) { 64 mutex_unlock(&device->mutex); 65 66 scsi_cmd_read_capacity_long *cmd 67 = (scsi_cmd_read_capacity_long *)request->cdb; 68 69 scsi_res_read_capacity_long capacityLongResult; 70 request->data = (uint8*)&capacityLongResult; 71 request->data_length = sizeof(capacityLongResult); 72 request->cdb_length = sizeof(scsi_cmd_read_capacity_long); 73 74 memset(cmd, 0, sizeof(*cmd)); 75 cmd->opcode = SCSI_OP_SERVICE_ACTION_IN; 76 cmd->service_action = SCSI_SAI_READ_CAPACITY_16; 77 78 res = periph_safe_exec(device, request); 79 80 mutex_lock(&device->mutex); 81 82 if (res == B_OK && request->data_resid == 0) { 83 capacity = B_BENDIAN_TO_HOST_INT64(capacityLongResult.lba); 84 } else 85 capacity = 0; 86 } 87 88 // the command returns the index of the _last_ block, 89 // i.e. the size is one larger 90 ++capacity; 91 92 blockSize = B_BENDIAN_TO_HOST_INT32(capacityResult.block_size); 93 } else { 94 capacity = 0; 95 blockSize = 0; 96 } 97 98 SHOW_FLOW(3, "capacity = %" B_PRId64 ", block_size = %" B_PRId32, capacity, 99 blockSize); 100 101 device->block_size = blockSize; 102 103 device->callbacks->set_capacity(device->periph_device, 104 capacity, blockSize); 105 106 /* device->byte2blk_shift = log2( device->block_size ); 107 if( device->byte2blk_shift < 0 ) { 108 // this may be too restrictive... 109 device->capacity = -1; 110 return ERR_DEV_GENERAL; 111 }*/ 112 113 mutex_unlock(&device->mutex); 114 115 SHOW_FLOW(3, "done (%s)", strerror(res)); 116 117 return res; 118 } 119 120 121 status_t 122 periph_trim_device(scsi_periph_device_info *device, scsi_ccb *request, 123 scsi_block_range* ranges, uint32 rangeCount) 124 { 125 size_t unmapBlockSize = (rangeCount - 1) 126 * sizeof(scsi_unmap_block_descriptor) 127 + sizeof(scsi_unmap_parameter_list); 128 129 // TODO: check block limits VPD page 130 // TODO: instead of failing, we should try to complete the request in 131 // several passes. 132 if (unmapBlockSize > 65536 || rangeCount == 0) 133 return B_BAD_VALUE; 134 135 scsi_unmap_parameter_list* unmapBlocks 136 = (scsi_unmap_parameter_list*)malloc(unmapBlockSize); 137 if (unmapBlocks == NULL) 138 return B_NO_MEMORY; 139 140 MemoryDeleter deleter(unmapBlocks); 141 142 // Prepare request data 143 memset(unmapBlocks, 0, unmapBlockSize); 144 unmapBlocks->data_length = B_HOST_TO_BENDIAN_INT16(unmapBlockSize - 1); 145 unmapBlocks->block_data_length 146 = B_HOST_TO_BENDIAN_INT16(unmapBlockSize - 7); 147 148 for (uint32 i = 0; i < rangeCount; i++) { 149 unmapBlocks->blocks[i].lba = B_HOST_TO_BENDIAN_INT64( 150 ranges[i].offset / device->block_size); 151 unmapBlocks->blocks[i].block_count = B_HOST_TO_BENDIAN_INT32( 152 ranges[i].size / device->block_size); 153 } 154 155 request->flags = SCSI_DIR_OUT; 156 request->sort = ranges[0].offset / device->block_size; 157 request->timeout = device->std_timeout; 158 159 scsi_cmd_unmap* cmd = (scsi_cmd_unmap*)request->cdb; 160 161 memset(cmd, 0, sizeof(*cmd)); 162 cmd->opcode = SCSI_OP_UNMAP; 163 cmd->length = B_HOST_TO_BENDIAN_INT16(unmapBlockSize); 164 165 request->data = (uint8*)unmapBlocks; 166 request->data_length = unmapBlockSize; 167 168 request->cdb_length = sizeof(*cmd); 169 170 status_t status = periph_safe_exec(device, request); 171 172 // peripheral layer only creates "read" error 173 if (status == B_DEV_READ_ERROR) 174 return B_DEV_WRITE_ERROR; 175 176 return status; 177 } 178 179