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