1.6.4 scsi命令的执行
负责执行具体scsi命令的函数是scsi_dispatch_cmd,来自drivers/scsi/scsi.c:
468 int scsi_dispatch_cmd(struct scsi_cmnd *cmd) 469 { 470 struct Scsi_Host *host = cmd->device->host; 471 unsigned long flags = 0; 472 unsigned long timeout; 473 int rtn = 0; 474 475 /* check if the device is still usable */ 476 if (unlikely(cmd->device->sdev_state == SDEV_DEL)) { 477 /* in SDEV_DEL we error all commands. DID_NO_CONNECT 478 * returns an immediate error upwards, and signals 479 * that the device is no longer present */ 480 cmd->result = DID_NO_CONNECT << 16; 481 atomic_inc(&cmd->device->iorequest_cnt); 482 __scsi_done(cmd); 483 /* return 0 (because the command has been processed) */ 484 goto out; 485 } 486 487 /* Check to see if the scsi lld put this device into state SDEV_BLOCK. */ 488 if (unlikely(cmd->device->sdev_state == SDEV_BLOCK)) { 489 /* 490 * in SDEV_BLOCK, the command is just put back on the device 491 * queue. The suspend state has already blocked the queue so 492 * future requests should not occur until the device 493 * transitions out of the suspend state. 494 */ 495 scsi_queue_insert(cmd, SCSI_MLQUEUE_DEVICE_BUSY); 496 497 SCSI_LOG_MLQUEUE(3, printk("queuecommand : device blocked /n")); 498 499 /* 500 * NOTE: rtn is still zero here because we don't need the 501 * queue to be plugged on return (it's already stopped) 502 */ 503 goto out; 504 } 505 506 /* 507 * If SCSI-2 or lower, store the LUN value in cmnd. 508 */ 509 if (cmd->device->scsi_level <= SCSI_2 && 510 cmd->device->scsi_level != SCSI_UNKNOWN) { 511 cmd->cmnd[1] = (cmd->cmnd[1] & 0x1f) | 512 (cmd->device->lun << 5 & 0xe0); 513 } 514 515 /* 516 * We will wait MIN_RESET_DELAY clock ticks after the last reset so 517 * we can avoid the drive not being ready. 518 */ 519 timeout = host->last_reset + MIN_RESET_DELAY; 520 521 if (host->resetting && time_before(jiffies, timeout)) { 522 int ticks_remaining = timeout - jiffies; 523 /* 524 * NOTE: This may be executed from within an interrupt 525 * handler! This is bad, but for now, it'll do. The irq 526 * level of the interrupt handler has been masked out by the 527 * platform dependent interrupt handling code already, so the 528 * sti() here will not cause another call to the SCSI host's 529 * interrupt handler (assuming there is one irq-level per 530 * host). 531 */ 532 while (--ticks_remaining >= 0) 533 mdelay(1 + 999 / HZ); 534 host->resetting = 0; 535 } 536 537 /* 538 * AK: unlikely race here: for some reason the timer could 539 * expire before the serial number is set up below. 540 */ 541 scsi_add_timer(cmd, cmd->timeout_per_command, scsi_times_out); 542 543 scsi_log_send(cmd); 544 545 /* 546 * We will use a queued command if possible, otherwise we will 547 * emulate the queuing and calling of completion function ourselves. 548 */ 549 atomic_inc(&cmd->device->iorequest_cnt); 550 551 /* 552 * Before we queue this command, check if the command 553 * length exceeds what the host adapter can handle. 554 */ 555 if (CDB_SIZE(cmd) > cmd->device->host->max_cmd_len) { 556 SCSI_LOG_MLQUEUE(3, 557 printk("queuecommand : command too long./n")); 558 cmd->result = (DID_ABORT << 16); 559 560 scsi_done(cmd); 561 goto out; 562 } 563 564 spin_lock_irqsave(host->host_lock, flags); 565 scsi_cmd_get_serial(host, cmd); 566 567 if (unlikely(host->shost_state == SHOST_DEL)) { 568 cmd->result = (DID_NO_CONNECT << 16); 569 scsi_done(cmd); 570 } else { 571 rtn = host->hostt->queuecommand(cmd, scsi_done); 572 } 573 spin_unlock_irqrestore(host->host_lock, flags); 574 if (rtn) { 575 if (scsi_delete_timer(cmd)) { 576 atomic_inc(&cmd->device->iodone_cnt); 577 scsi_queue_insert(cmd, 578 (rtn == SCSI_MLQUEUE_DEVICE_BUSY) ? 579 rtn : SCSI_MLQUEUE_HOST_BUSY); 580 } 581 SCSI_LOG_MLQUEUE(3, 582 printk("queuecommand : request rejected/n")); 583 } 584 585 out: 586 SCSI_LOG_MLQUEUE(3, printk("leaving scsi_dispatch_cmnd()/n")); 587 return rtn; 588 } |
scsi_dispatch_cmd函数将一个scsi命令提交给底层scsi host驱动。在命令dispatch的过程中,middle level会检查scsi host是否出于busy状态,是否还有空间存放新的scsi command。如果所有条件都满足,那么会调用上下层之间的接口函数queuecommand函数转发请求。
queuecomand函数的实现由scsi host driver完成。通常该函数的实现很简单,只需要将传下来的scsi命令挂载到host的scsi命令队列中。由于queuecommand函数在持有spinlock的上下文中运行,所以不宜做过多复杂的操作,否则很容易导致程序睡眠,从而使程序运行不稳定。
一路走来的兄弟一定会一眼就看出这里我们最期待的一行代码就是571那个queuecommand()的调用。因为这之后我们就知道该发生什么了。比如对于U盘驱动来说,命令就从这里接过去开始执行。而对于实际的scsi控制器,其对应的驱动中的queuecommand也会被调用,剩下的事情我们就不用操心了。正常情况下queuecommand返回0。于是紧接着scsi_dispatch_cmd也返回0。这样就算是执行了一条scsi命令了。
queuecomand函数的实现由scsi host driver完成。通常该函数的实现很简单,只需要将传下来的scsi命令scsi_cmnd挂载到host的scsi命令队列中。由于queuecommand函数在持有 spinlock的上下文中运行,所以不宜做过多复杂的操作,否则很容易导致程序睡眠,从而使程序运行不稳定。
而scsi_request_fn()是否结束还得看while循环的条件是否满足,而这就得看blk_queue_plugged()的脸色了。那么我们从字面上来分析,什么叫queue plugged?比如说,北四环上上下班高峰期,许许多多的车辆排成一队又一队,但是可能半天都前进不了,这就叫plugged,或者说堵车,也叫塞车。为此咱们使用一个flag来标志堵车与否,来自include/linux/blkdev.h:
523 #define blk_queue_plugged(q) test_bit(QUEUE_FLAG_PLUGGED, &(q)->queue_flags)
改变这个这个flag的函数有两个,一个是设置,一个是取消。负责设置的是blk_plug_device,负责取消的是blk_remove_plug(),前面讲的理论知识,这里就用到了。