📄 scsi_lib.c
字号:
* If there are blocks left over at the end, set up the command * to queue the remainder of them. */ if (req->bh) { request_queue_t *q; if( !requeue ) { return SCpnt; } q = &SCpnt->device->request_queue; req->buffer = bh->b_data; /* * Bleah. Leftovers again. Stick the leftovers in * the front of the queue, and goose the queue again. */ scsi_queue_next_request(q, SCpnt); return SCpnt; } /* * This request is done. If there is someone blocked waiting for this * request, wake them up. Typically used to wake up processes trying * to swap a page into memory. */ if (req->waiting != NULL) { complete(req->waiting); } add_blkdev_randomness(MAJOR(req->rq_dev)); SDpnt = SCpnt->device; /* * This will goose the queue request function at the end, so we don't * need to worry about launching another command. */ __scsi_release_command(SCpnt); if( frequeue ) { request_queue_t *q; q = &SDpnt->request_queue; scsi_queue_next_request(q, NULL); } return NULL;}/* * Function: scsi_end_request() * * Purpose: Post-processing of completed commands called from interrupt * handler or a bottom-half handler. * * Arguments: SCpnt - command that is complete. * uptodate - 1 if I/O indicates success, 0 for I/O error. * sectors - number of sectors we want to mark. * * Lock status: Assumed that lock is not held upon entry. * * Returns: Nothing * * Notes: This is called for block device requests in order to * mark some number of sectors as complete. * * We are guaranteeing that the request queue will be goosed * at some point during this call. */Scsi_Cmnd *scsi_end_request(Scsi_Cmnd * SCpnt, int uptodate, int sectors){ return __scsi_end_request(SCpnt, uptodate, sectors, 1, 1);}/* * Function: scsi_release_buffers() * * Purpose: Completion processing for block device I/O requests. * * Arguments: SCpnt - command that we are bailing. * * Lock status: Assumed that no lock is held upon entry. * * Returns: Nothing * * Notes: In the event that an upper level driver rejects a * command, we must release resources allocated during * the __init_io() function. Primarily this would involve * the scatter-gather table, and potentially any bounce * buffers. */static void scsi_release_buffers(Scsi_Cmnd * SCpnt){ ASSERT_LOCK(&io_request_lock, 0); /* * Free up any indirection buffers we allocated for DMA purposes. */ if (SCpnt->use_sg) { struct scatterlist *sgpnt; void **bbpnt; int i; sgpnt = (struct scatterlist *) SCpnt->request_buffer; bbpnt = SCpnt->bounce_buffers; if (bbpnt) { for (i = 0; i < SCpnt->use_sg; i++) { if (bbpnt[i]) scsi_free(sgpnt[i].address, sgpnt[i].length); } } scsi_free(SCpnt->request_buffer, SCpnt->sglist_len); } else { if (SCpnt->request_buffer != SCpnt->request.buffer) { scsi_free(SCpnt->request_buffer, SCpnt->request_bufflen); } } /* * Zero these out. They now point to freed memory, and it is * dangerous to hang onto the pointers. */ SCpnt->buffer = NULL; SCpnt->bufflen = 0; SCpnt->request_buffer = NULL; SCpnt->request_bufflen = 0;}/* * Function: scsi_io_completion() * * Purpose: Completion processing for block device I/O requests. * * Arguments: SCpnt - command that is finished. * * Lock status: Assumed that no lock is held upon entry. * * Returns: Nothing * * Notes: This function is matched in terms of capabilities to * the function that created the scatter-gather list. * In other words, if there are no bounce buffers * (the normal case for most drivers), we don't need * the logic to deal with cleaning up afterwards. */void scsi_io_completion(Scsi_Cmnd * SCpnt, int good_sectors, int block_sectors){ int result = SCpnt->result; int this_count = SCpnt->bufflen >> 9; request_queue_t *q = &SCpnt->device->request_queue; /* * We must do one of several things here: * * Call scsi_end_request. This will finish off the specified * number of sectors. If we are done, the command block will * be released, and the queue function will be goosed. If we * are not done, then scsi_end_request will directly goose * the queue. * * We can just use scsi_queue_next_request() here. This * would be used if we just wanted to retry, for example. * */ ASSERT_LOCK(&io_request_lock, 0); /* * Free up any indirection buffers we allocated for DMA purposes. * For the case of a READ, we need to copy the data out of the * bounce buffer and into the real buffer. */ if (SCpnt->use_sg) { struct scatterlist *sgpnt; void **bbpnt; int i; sgpnt = (struct scatterlist *) SCpnt->buffer; bbpnt = SCpnt->bounce_buffers; if (bbpnt) { for (i = 0; i < SCpnt->use_sg; i++) { if (bbpnt[i]) { if (SCpnt->request.cmd == READ) { memcpy(bbpnt[i], sgpnt[i].address, sgpnt[i].length); } scsi_free(sgpnt[i].address, sgpnt[i].length); } } } scsi_free(SCpnt->buffer, SCpnt->sglist_len); } else { if (SCpnt->buffer != SCpnt->request.buffer) { if (SCpnt->request.cmd == READ) { memcpy(SCpnt->request.buffer, SCpnt->buffer, SCpnt->bufflen); } scsi_free(SCpnt->buffer, SCpnt->bufflen); } } /* * Zero these out. They now point to freed memory, and it is * dangerous to hang onto the pointers. */ SCpnt->buffer = NULL; SCpnt->bufflen = 0; SCpnt->request_buffer = NULL; SCpnt->request_bufflen = 0; /* * Next deal with any sectors which we were able to correctly * handle. */ if (good_sectors > 0) { SCSI_LOG_HLCOMPLETE(1, printk("%ld sectors total, %d sectors done.\n", SCpnt->request.nr_sectors, good_sectors)); SCSI_LOG_HLCOMPLETE(1, printk("use_sg is %d\n ", SCpnt->use_sg)); SCpnt->request.errors = 0; /* * If multiple sectors are requested in one buffer, then * they will have been finished off by the first command. * If not, then we have a multi-buffer command. * * If block_sectors != 0, it means we had a medium error * of some sort, and that we want to mark some number of * sectors as not uptodate. Thus we want to inhibit * requeueing right here - we will requeue down below * when we handle the bad sectors. */ SCpnt = __scsi_end_request(SCpnt, 1, good_sectors, result == 0, 1); /* * If the command completed without error, then either finish off the * rest of the command, or start a new one. */ if (result == 0 || SCpnt == NULL ) { return; } } /* * Now, if we were good little boys and girls, Santa left us a request * sense buffer. We can extract information from this, so we * can choose a block to remap, etc. */ if (driver_byte(result) != 0) { if (suggestion(result) == SUGGEST_REMAP) {#ifdef REMAP /* * Not yet implemented. A read will fail after being remapped, * a write will call the strategy routine again. */ if (SCpnt->device->remap) { result = 0; }#endif } if ((SCpnt->sense_buffer[0] & 0x7f) == 0x70) { /* * If the device is in the process of becoming ready, * retry. */ if (SCpnt->sense_buffer[12] == 0x04 && SCpnt->sense_buffer[13] == 0x01) { scsi_queue_next_request(q, SCpnt); return; } if ((SCpnt->sense_buffer[2] & 0xf) == UNIT_ATTENTION) { if (SCpnt->device->removable) { /* detected disc change. set a bit * and quietly refuse further access. */ SCpnt->device->changed = 1; SCpnt = scsi_end_request(SCpnt, 0, this_count); return; } else { /* * Must have been a power glitch, or a * bus reset. Could not have been a * media change, so we just retry the * request and see what happens. */ scsi_queue_next_request(q, SCpnt); return; } } } /* If we had an ILLEGAL REQUEST returned, then we may have * performed an unsupported command. The only thing this should be * would be a ten byte read where only a six byte read was supported. * Also, on a system where READ CAPACITY failed, we have have read * past the end of the disk. */ switch (SCpnt->sense_buffer[2]) { case ILLEGAL_REQUEST: if (SCpnt->device->ten) { SCpnt->device->ten = 0; /* * This will cause a retry with a 6-byte * command. */ scsi_queue_next_request(q, SCpnt); result = 0; } else { SCpnt = scsi_end_request(SCpnt, 0, this_count); return; } break; case NOT_READY: printk(KERN_INFO "Device %s not ready.\n", kdevname(SCpnt->request.rq_dev)); SCpnt = scsi_end_request(SCpnt, 0, this_count); return; break; case MEDIUM_ERROR: case VOLUME_OVERFLOW: printk("scsi%d: ERROR on channel %d, id %d, lun %d, CDB: ", SCpnt->host->host_no, (int) SCpnt->channel, (int) SCpnt->target, (int) SCpnt->lun); print_command(SCpnt->cmnd); print_sense("sd", SCpnt); SCpnt = scsi_end_request(SCpnt, 0, block_sectors); return; default: break; } } /* driver byte != 0 */ if (host_byte(result) == DID_RESET) { /* * Third party bus reset or reset for error * recovery reasons. Just retry the request * and see what happens. */ scsi_queue_next_request(q, SCpnt); return; } if (result) { struct Scsi_Device_Template *STpnt; STpnt = scsi_get_request_dev(&SCpnt->request); printk("SCSI %s error : host %d channel %d id %d lun %d return code = %x\n", (STpnt ? STpnt->name : "device"), SCpnt->device->host->host_no, SCpnt->device->channel, SCpnt->device->id, SCpnt->device->lun, result); if (driver_byte(result) & DRIVER_SENSE) print_sense("sd", SCpnt); /* * Mark a single buffer as not uptodate. Queue the remainder. * We sometimes get this cruft in the event that a medium error * isn't properly reported. */ SCpnt = scsi_end_request(SCpnt, 0, SCpnt->request.current_nr_sectors); return; }}/* * Function: scsi_get_request_dev() * * Purpose: Find the upper-level driver that is responsible for this * request * * Arguments: request - I/O request we are preparing to queue. * * Lock status: No locks assumed to be held, but as it happens the * io_request_lock is held when this is called. * * Returns: Nothing * * Notes: The requests in the request queue may have originated * from any block device driver. We need to find out which * one so that we can later form the appropriate command. */struct Scsi_Device_Template *scsi_get_request_dev(struct request *req){ struct Scsi_Device_Template *spnt; kdev_t dev = req->rq_dev; int major = MAJOR(dev); ASSERT_LOCK(&io_request_lock, 1); for (spnt = scsi_devicelist; spnt; spnt = spnt->next) { /* * Search for a block device driver that supports this * major. */ if (spnt->blk && spnt->major == major) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -