1 /* 2 * Copyright 2004-2011, Haiku, Inc. All Rights Reserved. 3 * Copyright 2002-03, Thomas Kurschel. All rights reserved. 4 * 5 * Distributed under the terms of the MIT License. 6 */ 7 8 9 //! Everything doing the real input/output stuff. 10 11 12 #include "scsi_periph_int.h" 13 #include <scsi.h> 14 15 #include <string.h> 16 #include <stdlib.h> 17 18 19 static status_t 20 inquiry(scsi_periph_device_info *device, scsi_inquiry *inquiry) 21 { 22 const scsi_res_inquiry *device_inquiry = NULL; 23 size_t inquiryLength; 24 25 if (gDeviceManager->get_attr_raw(device->node, SCSI_DEVICE_INQUIRY_ITEM, 26 (const void **)&device_inquiry, &inquiryLength, true) != B_OK) 27 return B_ERROR; 28 29 memcpy(inquiry, device_inquiry, min_c(inquiryLength, sizeof(scsi_inquiry))); 30 return B_OK; 31 } 32 33 34 static status_t 35 vpd_page_inquiry(scsi_periph_device_info *device, uint8 page, void* data, 36 uint16 length) 37 { 38 SHOW_FLOW0(0, ""); 39 40 scsi_ccb* ccb = device->scsi->alloc_ccb(device->scsi_device); 41 if (ccb == NULL) 42 return B_NO_MEMORY; 43 44 scsi_cmd_inquiry *cmd = (scsi_cmd_inquiry *)ccb->cdb; 45 memset(cmd, 0, sizeof(scsi_cmd_inquiry)); 46 cmd->opcode = SCSI_OP_INQUIRY; 47 cmd->lun = ccb->target_lun; 48 cmd->evpd = 1; 49 cmd->page_code = page; 50 cmd->allocation_length = length; 51 52 ccb->flags = SCSI_DIR_IN; 53 ccb->cdb_length = sizeof(scsi_cmd_inquiry); 54 55 ccb->sort = -1; 56 ccb->timeout = device->std_timeout; 57 58 ccb->data = (uint8*)data; 59 ccb->sg_list = NULL; 60 ccb->data_length = length; 61 62 status_t status = periph_safe_exec(device, ccb); 63 64 device->scsi->free_ccb(ccb); 65 66 return status; 67 } 68 69 70 status_t 71 vpd_page_get(scsi_periph_device_info *device, uint8 page, void* data, 72 uint16 length) 73 { 74 SHOW_FLOW0(0, ""); 75 76 status_t status = vpd_page_inquiry(device, 0, data, length); 77 if (status != B_OK) 78 return status; // or B_BAD_VALUE 79 80 if (page == 0) 81 return B_OK; 82 83 scsi_page_list *list_data = (scsi_page_list*)data; 84 int page_length = min_c(list_data->page_length, length - 85 offsetof(scsi_page_list, pages)); 86 for (int i = 0; i < page_length; i++) { 87 if (list_data->pages[i] == page) 88 return vpd_page_inquiry(device, page, data, length); 89 } 90 91 // TODO buffer might be not big enough 92 93 return B_BAD_VALUE; 94 } 95 96 97 98 static status_t 99 prevent_allow(scsi_periph_device_info *device, bool prevent) 100 { 101 scsi_cmd_prevent_allow cmd; 102 103 SHOW_FLOW0(0, ""); 104 105 memset(&cmd, 0, sizeof(cmd)); 106 cmd.opcode = SCSI_OP_PREVENT_ALLOW; 107 cmd.prevent = prevent; 108 109 return periph_simple_exec(device, (uint8 *)&cmd, sizeof(cmd), NULL, 0, 110 SCSI_DIR_NONE); 111 } 112 113 114 /*! Keep this in sync with scsi_raw driver!!! */ 115 static status_t 116 raw_command(scsi_periph_device_info *device, raw_device_command *cmd) 117 { 118 scsi_ccb *request; 119 120 SHOW_FLOW0(0, ""); 121 122 request = device->scsi->alloc_ccb(device->scsi_device); 123 if (request == NULL) 124 return B_NO_MEMORY; 125 126 request->flags = 0; 127 128 if (cmd->flags & B_RAW_DEVICE_DATA_IN) 129 request->flags |= SCSI_DIR_IN; 130 else if (cmd->data_length) 131 request->flags |= SCSI_DIR_OUT; 132 else 133 request->flags |= SCSI_DIR_NONE; 134 135 request->data = (uint8*)cmd->data; 136 request->sg_list = NULL; 137 request->data_length = cmd->data_length; 138 request->sort = -1; 139 request->timeout = cmd->timeout; 140 141 memcpy(request->cdb, cmd->command, SCSI_MAX_CDB_SIZE); 142 request->cdb_length = cmd->command_length; 143 144 device->scsi->sync_io(request); 145 146 // TBD: should we call standard error handler here, or may the 147 // actions done there (like starting the unit) confuse the application? 148 149 cmd->cam_status = request->subsys_status; 150 cmd->scsi_status = request->device_status; 151 152 if ((request->subsys_status & SCSI_AUTOSNS_VALID) != 0 && cmd->sense_data) { 153 memcpy(cmd->sense_data, request->sense, min_c(cmd->sense_data_length, 154 (size_t)SCSI_MAX_SENSE_SIZE - request->sense_resid)); 155 } 156 157 if ((cmd->flags & B_RAW_DEVICE_REPORT_RESIDUAL) != 0) { 158 // this is a bit strange, see Be's sample code where I pinched this from; 159 // normally, residual means "number of unused bytes left" 160 // but here, we have to return "number of used bytes", which is the opposite 161 cmd->data_length = cmd->data_length - request->data_resid; 162 cmd->sense_data_length = SCSI_MAX_SENSE_SIZE - request->sense_resid; 163 } 164 165 device->scsi->free_ccb(request); 166 167 return B_OK; 168 } 169 170 171 /*! Universal read/write function */ 172 static status_t 173 read_write(scsi_periph_device_info *device, scsi_ccb *request, 174 io_operation *operation, uint64 offset, size_t originalNumBlocks, 175 physical_entry* vecs, size_t vecCount, bool isWrite, 176 size_t* _bytesTransferred) 177 { 178 uint32 blockSize = device->block_size; 179 size_t numBlocks = originalNumBlocks; 180 uint32 pos = offset; 181 err_res res; 182 int retries = 0; 183 184 do { 185 size_t numBytes; 186 bool isReadWrite10 = false; 187 188 request->flags = isWrite ? SCSI_DIR_OUT : SCSI_DIR_IN; 189 190 // io_operations are generated by a DMAResource and thus contain DMA 191 // safe physical vectors 192 if (operation != NULL) 193 request->flags |= SCSI_DMA_SAFE; 194 195 // make sure we avoid 10 byte commands if they aren't supported 196 if (!device->rw10_enabled || device->preferred_ccb_size == 6) { 197 // restricting transfer is OK - the block manager will 198 // take care of transferring the rest 199 if (numBlocks > 0x100) 200 numBlocks = 0x100; 201 202 // no way to break the 21 bit address limit 203 if (offset > 0x200000) 204 return B_BAD_VALUE; 205 206 // don't allow transfer cross the 24 bit address limit 207 // (I'm not sure whether this is allowed, but this way we 208 // are sure to not ask for trouble) 209 if (offset < 0x100000) 210 numBlocks = min_c(numBlocks, 0x100000 - pos); 211 } 212 213 numBytes = numBlocks * blockSize; 214 if (numBlocks != originalNumBlocks) 215 panic("I/O operation would need to be cut."); 216 217 request->data = NULL; 218 request->sg_list = vecs; 219 request->data_length = numBytes; 220 request->sg_count = vecCount; 221 request->io_operation = operation; 222 request->sort = pos; 223 request->timeout = device->std_timeout; 224 // see whether daemon instructed us to post an ordered command; 225 // reset flag after read 226 SHOW_FLOW(3, "flag=%x, next_tag=%x, ordered: %s", 227 (int)request->flags, (int)device->next_tag_action, 228 (request->flags & SCSI_ORDERED_QTAG) != 0 ? "yes" : "no"); 229 230 // use shortest commands whenever possible 231 if (offset + numBlocks < 0x200000LL && numBlocks <= 0x100) { 232 scsi_cmd_rw_6 *cmd = (scsi_cmd_rw_6 *)request->cdb; 233 234 isReadWrite10 = false; 235 236 memset(cmd, 0, sizeof(*cmd)); 237 cmd->opcode = isWrite ? SCSI_OP_WRITE_6 : SCSI_OP_READ_6; 238 cmd->high_lba = (pos >> 16) & 0x1f; 239 cmd->mid_lba = (pos >> 8) & 0xff; 240 cmd->low_lba = pos & 0xff; 241 cmd->length = numBlocks; 242 243 request->cdb_length = sizeof(*cmd); 244 } else if (offset + numBlocks < 0x100000000LL && numBlocks <= 0x10000) { 245 scsi_cmd_rw_10 *cmd = (scsi_cmd_rw_10 *)request->cdb; 246 247 isReadWrite10 = true; 248 249 memset(cmd, 0, sizeof(*cmd)); 250 cmd->opcode = isWrite ? SCSI_OP_WRITE_10 : SCSI_OP_READ_10; 251 cmd->relative_address = 0; 252 cmd->force_unit_access = 0; 253 cmd->disable_page_out = 0; 254 cmd->lba = B_HOST_TO_BENDIAN_INT32(pos); 255 cmd->length = B_HOST_TO_BENDIAN_INT16(numBlocks); 256 257 request->cdb_length = sizeof(*cmd); 258 } else if (offset + numBlocks < 0x100000000LL && numBlocks <= 0x10000000) { 259 scsi_cmd_rw_12 *cmd = (scsi_cmd_rw_12 *)request->cdb; 260 261 memset(cmd, 0, sizeof(*cmd)); 262 cmd->opcode = isWrite ? SCSI_OP_WRITE_12 : SCSI_OP_READ_12; 263 cmd->relative_address = 0; 264 cmd->force_unit_access = 0; 265 cmd->disable_page_out = 0; 266 cmd->lba = B_HOST_TO_BENDIAN_INT32(pos); 267 cmd->length = B_HOST_TO_BENDIAN_INT32(numBlocks); 268 269 request->cdb_length = sizeof(*cmd); 270 } else { 271 scsi_cmd_rw_16 *cmd = (scsi_cmd_rw_16 *)request->cdb; 272 273 memset(cmd, 0, sizeof(*cmd)); 274 cmd->opcode = isWrite ? SCSI_OP_WRITE_16 : SCSI_OP_READ_16; 275 cmd->force_unit_access_non_volatile = 0; 276 cmd->force_unit_access = 0; 277 cmd->disable_page_out = 0; 278 cmd->lba = B_HOST_TO_BENDIAN_INT64(offset); 279 cmd->length = B_HOST_TO_BENDIAN_INT32(numBlocks); 280 281 request->cdb_length = sizeof(*cmd); 282 } 283 284 // TODO: last chance to detect errors that occured during concurrent accesses 285 //status_t status = handle->pending_error; 286 //if (status != B_OK) 287 // return status; 288 289 device->scsi->async_io(request); 290 291 acquire_sem(request->completion_sem); 292 293 // ask generic peripheral layer what to do now 294 res = periph_check_error(device, request); 295 296 // TODO: bytes might have been transferred even in the error case! 297 switch (res.action) { 298 case err_act_ok: 299 *_bytesTransferred = numBytes - request->data_resid; 300 break; 301 302 case err_act_start: 303 res = periph_send_start_stop(device, request, 1, 304 device->removable); 305 if (res.action == err_act_ok) 306 res.action = err_act_retry; 307 break; 308 309 case err_act_invalid_req: 310 // if this was a 10 byte command, the device probably doesn't 311 // support them, so disable them and retry 312 if (isReadWrite10) { 313 atomic_and(&device->rw10_enabled, 0); 314 res.action = err_act_retry; 315 } else 316 res.action = err_act_fail; 317 break; 318 } 319 } while ((res.action == err_act_retry && retries++ < 3) 320 || (res.action == err_act_many_retries && retries++ < 30)); 321 322 // peripheral layer only created "read" error, so we have to 323 // map them to "write" errors if this was a write request 324 if (res.error_code == B_DEV_READ_ERROR && isWrite) 325 return B_DEV_WRITE_ERROR; 326 327 return res.error_code; 328 } 329 330 331 // #pragma mark - public functions 332 333 334 status_t 335 periph_ioctl(scsi_periph_handle_info *handle, int op, void *buffer, 336 size_t length) 337 { 338 switch (op) { 339 case B_GET_MEDIA_STATUS: 340 { 341 status_t status = B_OK; 342 343 if (handle->device->removable) 344 status = periph_get_media_status(handle); 345 346 SHOW_FLOW(2, "%s", strerror(status)); 347 348 *(status_t *)buffer = status; 349 return B_OK; 350 } 351 352 case B_GET_DEVICE_NAME: 353 { 354 // TODO: this should be written as an attribute to the node 355 // Try driver further up first 356 if (handle->device->scsi->ioctl != NULL) { 357 status_t status = handle->device->scsi->ioctl( 358 handle->device->scsi_device, op, buffer, length); 359 if (status == B_OK) 360 return B_OK; 361 } 362 363 // If that fails, get SCSI vendor/product 364 const char* vendor; 365 if (gDeviceManager->get_attr_string(handle->device->node, 366 SCSI_DEVICE_VENDOR_ITEM, &vendor, true) == B_OK) { 367 char name[B_FILE_NAME_LENGTH]; 368 strlcpy(name, vendor, sizeof(name)); 369 370 const char* product; 371 if (gDeviceManager->get_attr_string(handle->device->node, 372 SCSI_DEVICE_PRODUCT_ITEM, &product, true) == B_OK) { 373 strlcat(name, " ", sizeof(name)); 374 strlcat(name, product, sizeof(name)); 375 } 376 377 return user_strlcpy((char*)buffer, name, length) >= 0 378 ? B_OK : B_BAD_ADDRESS; 379 } 380 return B_ERROR; 381 } 382 383 case B_SCSI_INQUIRY: 384 return inquiry(handle->device, (scsi_inquiry *)buffer); 385 386 case B_SCSI_PREVENT_ALLOW: 387 return prevent_allow(handle->device, *(bool *)buffer); 388 389 case B_RAW_DEVICE_COMMAND: 390 return raw_command(handle->device, (raw_device_command*)buffer); 391 392 default: 393 if (handle->device->scsi->ioctl != NULL) { 394 return handle->device->scsi->ioctl(handle->device->scsi_device, 395 op, buffer, length); 396 } 397 398 SHOW_ERROR(4, "Unknown ioctl: %x", op); 399 return B_DEV_INVALID_IOCTL; 400 } 401 } 402 403 404 /*! Kernel daemon - once in a minute, it sets a flag so that the next command 405 is executed ordered; this way, we avoid starvation of SCSI commands inside 406 the SCSI queuing system - the ordered command waits for all previous 407 commands and thus no command can starve longer then a minute 408 */ 409 void 410 periph_sync_queue_daemon(void *arg, int iteration) 411 { 412 scsi_periph_device_info *device = (scsi_periph_device_info *)arg; 413 414 SHOW_FLOW0(3, "Setting ordered flag for next R/W access"); 415 atomic_or(&device->next_tag_action, SCSI_ORDERED_QTAG); 416 } 417 418 419 status_t 420 periph_read_write(scsi_periph_device_info *device, scsi_ccb *request, 421 uint64 offset, size_t numBlocks, physical_entry* vecs, size_t vecCount, 422 bool isWrite, size_t* _bytesTransferred) 423 { 424 return read_write(device, request, NULL, offset, numBlocks, vecs, vecCount, 425 isWrite, _bytesTransferred); 426 } 427 428 429 status_t 430 periph_io(scsi_periph_device_info *device, io_operation *operation, 431 size_t* _bytesTransferred) 432 { 433 const uint32 blockSize = device->block_size; 434 if (blockSize == 0) 435 return B_BAD_VALUE; 436 437 // don't test rw10_enabled restrictions - this flag may get changed 438 scsi_ccb *request = device->scsi->alloc_ccb(device->scsi_device); 439 if (request == NULL) 440 return B_NO_MEMORY; 441 442 status_t status = read_write(device, request, operation, 443 operation->Offset() / blockSize, operation->Length() / blockSize, 444 (physical_entry *)operation->Vecs(), operation->VecCount(), 445 operation->IsWrite(), _bytesTransferred); 446 447 device->scsi->free_ccb(request); 448 return status; 449 } 450 451