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