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