3w-9xxx.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,986 行 · 第 1/5 页
C
1,986 行
/* Handle host interrupt */ if (status_reg_value & TW_STATUS_HOST_INTERRUPT) TW_CLEAR_HOST_INTERRUPT(tw_dev); /* Handle attention interrupt */ if (status_reg_value & TW_STATUS_ATTENTION_INTERRUPT) { TW_CLEAR_ATTENTION_INTERRUPT(tw_dev); if (!(test_and_set_bit(TW_IN_ATTENTION_LOOP, &tw_dev->flags))) { twa_get_request_id(tw_dev, &request_id); error = twa_aen_read_queue(tw_dev, request_id); if (error) { tw_dev->state[request_id] = TW_S_COMPLETED; twa_free_request_id(tw_dev, request_id); clear_bit(TW_IN_ATTENTION_LOOP, &tw_dev->flags); } } } /* Handle command interrupt */ if (status_reg_value & TW_STATUS_COMMAND_INTERRUPT) { TW_MASK_COMMAND_INTERRUPT(tw_dev); /* Drain as many pending commands as we can */ while (tw_dev->pending_request_count > 0) { request_id = tw_dev->pending_queue[tw_dev->pending_head]; if (tw_dev->state[request_id] != TW_S_PENDING) { TW_PRINTK(tw_dev->host, TW_DRIVER, 0x19, "Found request id that wasn't pending"); TW_CLEAR_ALL_INTERRUPTS(tw_dev); goto twa_interrupt_bail; } if (twa_post_command_packet(tw_dev, request_id, 1)==0) { tw_dev->pending_head = (tw_dev->pending_head + 1) % TW_Q_LENGTH; tw_dev->pending_request_count--; } else { /* If we get here, we will continue re-posting on the next command interrupt */ break; } } } /* Handle response interrupt */ if (status_reg_value & TW_STATUS_RESPONSE_INTERRUPT) { /* Drain the response queue from the board */ while ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) { /* Complete the response */ response_que.value = readl(TW_RESPONSE_QUEUE_REG_ADDR(tw_dev)); request_id = TW_RESID_OUT(response_que.response_id); full_command_packet = tw_dev->command_packet_virt[request_id]; error = 0; command_packet = &full_command_packet->command.oldcommand; /* Check for command packet errors */ if (full_command_packet->command.newcommand.status != 0) { if (tw_dev->srb[request_id] != 0) { error = twa_fill_sense(tw_dev, request_id, 1, 1); } else { /* Skip ioctl error prints */ if (request_id != tw_dev->chrdev_request_id) { error = twa_fill_sense(tw_dev, request_id, 0, 1); } } } /* Check for correct state */ if (tw_dev->state[request_id] != TW_S_POSTED) { if (tw_dev->srb[request_id] != 0) { TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1a, "Received a request id that wasn't posted"); TW_CLEAR_ALL_INTERRUPTS(tw_dev); goto twa_interrupt_bail; } } /* Check for internal command completion */ if (tw_dev->srb[request_id] == 0) { if (request_id != tw_dev->chrdev_request_id) { if (twa_aen_complete(tw_dev, request_id)) TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1b, "Error completing AEN during attention interrupt"); } else { tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE; wake_up(&tw_dev->ioctl_wqueue); } } else { twa_scsiop_execute_scsi_complete(tw_dev, request_id); /* If no error command was a success */ if (error == 0) { tw_dev->srb[request_id]->result = (DID_OK << 16); } /* If error, command failed */ if (error == 1) { /* Ask for a host reset */ tw_dev->srb[request_id]->result = (DID_OK << 16) | (CHECK_CONDITION << 1); } /* Now complete the io */ tw_dev->state[request_id] = TW_S_COMPLETED; twa_free_request_id(tw_dev, request_id); tw_dev->posted_request_count--; tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]); twa_unmap_scsi_data(tw_dev, request_id); } /* Check for valid status after each drain */ status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev)); if (twa_check_bits(status_reg_value)) { if (twa_decode_bits(tw_dev, status_reg_value)) { TW_CLEAR_ALL_INTERRUPTS(tw_dev); goto twa_interrupt_bail; } } } } }twa_interrupt_bail: spin_unlock(tw_dev->host->host_lock); return IRQ_RETVAL(handled);} /* End twa_interrupt() *//* This function will load the request id and various sgls for ioctls */static void twa_load_sgl(TW_Command_Full *full_command_packet, int request_id, dma_addr_t dma_handle, int length){ TW_Command *oldcommand; TW_Command_Apache *newcommand; TW_SG_Entry *sgl; if (TW_OP_OUT(full_command_packet->command.newcommand.opcode__reserved) == TW_OP_EXECUTE_SCSI) { newcommand = &full_command_packet->command.newcommand; newcommand->request_id = request_id; newcommand->sg_list[0].address = dma_handle + sizeof(TW_Ioctl_Buf_Apache) - 1; newcommand->sg_list[0].length = length; } else { oldcommand = &full_command_packet->command.oldcommand; oldcommand->request_id = request_id; if (TW_SGL_OUT(oldcommand->opcode__sgloffset)) { /* Load the sg list */ sgl = (TW_SG_Entry *)((u32 *)oldcommand+TW_SGL_OUT(oldcommand->opcode__sgloffset)); sgl->address = dma_handle + sizeof(TW_Ioctl_Buf_Apache) - 1; sgl->length = length; } }} /* End twa_load_sgl() *//* This function will perform a pci-dma mapping for a scatter gather list */static int twa_map_scsi_sg_data(TW_Device_Extension *tw_dev, int request_id){ int use_sg; struct scsi_cmnd *cmd = tw_dev->srb[request_id]; struct pci_dev *pdev = tw_dev->tw_pci_dev; int retval = 0; if (cmd->use_sg == 0) goto out; use_sg = pci_map_sg(pdev, cmd->buffer, cmd->use_sg, DMA_BIDIRECTIONAL); if (use_sg == 0) { TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1c, "Failed to map scatter gather list"); goto out; } cmd->SCp.phase = TW_PHASE_SGLIST; cmd->SCp.have_data_in = use_sg; retval = use_sg;out: return retval;} /* End twa_map_scsi_sg_data() *//* This function will perform a pci-dma map for a single buffer */static dma_addr_t twa_map_scsi_single_data(TW_Device_Extension *tw_dev, int request_id){ dma_addr_t mapping; struct scsi_cmnd *cmd = tw_dev->srb[request_id]; struct pci_dev *pdev = tw_dev->tw_pci_dev; int retval = 0; if (cmd->request_bufflen == 0) { retval = 0; goto out; } mapping = pci_map_single(pdev, cmd->request_buffer, cmd->request_bufflen, DMA_BIDIRECTIONAL); if (mapping == 0) { TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1d, "Failed to map page"); goto out; } cmd->SCp.phase = TW_PHASE_SINGLE; cmd->SCp.have_data_in = mapping; retval = mapping;out: return retval;} /* End twa_map_scsi_single_data() *//* This function will poll for a response interrupt of a request */static int twa_poll_response(TW_Device_Extension *tw_dev, int request_id, int seconds){ int retval = 1, found = 0, response_request_id; TW_Response_Queue response_queue; TW_Command_Full *full_command_packet = tw_dev->command_packet_virt[request_id]; if (twa_poll_status_gone(tw_dev, TW_STATUS_RESPONSE_QUEUE_EMPTY, seconds) == 0) { response_queue.value = readl(TW_RESPONSE_QUEUE_REG_ADDR(tw_dev)); response_request_id = TW_RESID_OUT(response_queue.response_id); if (request_id != response_request_id) { TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1e, "Found unexpected request id while polling for response"); goto out; } if (TW_OP_OUT(full_command_packet->command.newcommand.opcode__reserved) == TW_OP_EXECUTE_SCSI) { if (full_command_packet->command.newcommand.status != 0) { /* bad response */ twa_fill_sense(tw_dev, request_id, 0, 0); goto out; } found = 1; } else { if (full_command_packet->command.oldcommand.status != 0) { /* bad response */ twa_fill_sense(tw_dev, request_id, 0, 0); goto out; } found = 1; } } if (found) retval = 0;out: return retval;} /* End twa_poll_response() *//* This function will poll the status register for a flag */static int twa_poll_status(TW_Device_Extension *tw_dev, u32 flag, int seconds){ u32 status_reg_value; unsigned long before; int retval = 1; status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev)); before = jiffies; if (twa_check_bits(status_reg_value)) twa_decode_bits(tw_dev, status_reg_value); while ((status_reg_value & flag) != flag) { status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev)); if (twa_check_bits(status_reg_value)) twa_decode_bits(tw_dev, status_reg_value); if (time_after(jiffies, before + HZ * seconds)) goto out; msleep(50); } retval = 0;out: return retval;} /* End twa_poll_status() *//* This function will poll the status register for disappearance of a flag */static int twa_poll_status_gone(TW_Device_Extension *tw_dev, u32 flag, int seconds){ u32 status_reg_value; unsigned long before; int retval = 1; status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev)); before = jiffies; if (twa_check_bits(status_reg_value)) twa_decode_bits(tw_dev, status_reg_value); while ((status_reg_value & flag) != 0) { status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev)); if (twa_check_bits(status_reg_value)) twa_decode_bits(tw_dev, status_reg_value); if (time_after(jiffies, before + HZ * seconds)) goto out; msleep(50); } retval = 0;out: return retval;} /* End twa_poll_status_gone() *//* This function will attempt to post a command packet to the board */static int twa_post_command_packet(TW_Device_Extension *tw_dev, int request_id, char internal){ u32 status_reg_value; unsigned long command_que_value; int retval = 1; command_que_value = tw_dev->command_packet_phys[request_id]; status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev)); if (twa_check_bits(status_reg_value)) twa_decode_bits(tw_dev, status_reg_value); if (((tw_dev->pending_request_count > 0) && (tw_dev->state[request_id] != TW_S_PENDING)) || (status_reg_value & TW_STATUS_COMMAND_QUEUE_FULL)) { /* Only pend internal driver commands */ if (!internal) { retval = SCSI_MLQUEUE_HOST_BUSY; goto out; } /* Couldn't post the command packet, so we do it later */ if (tw_dev->state[request_id] != TW_S_PENDING) { tw_dev->state[request_id] = TW_S_PENDING; tw_dev->pending_request_count++; if (tw_dev->pending_request_count > tw_dev->max_pending_request_count) { tw_dev->max_pending_request_count = tw_dev->pending_request_count; } tw_dev->pending_queue[tw_dev->pending_tail] = request_id; tw_dev->pending_tail = (tw_dev->pending_tail + 1) % TW_Q_LENGTH; } TW_UNMASK_COMMAND_INTERRUPT(tw_dev); goto out; } else { /* We successfully posted the command packet */#if BITS_PER_LONG > 32 writeq(TW_COMMAND_OFFSET + command_que_value, TW_COMMAND_QUEUE_REG_ADDR(tw_dev));#else writel(TW_COMMAND_OFFSET + command_que_value, TW_COMMAND_QUEUE_REG_ADDR(tw_dev));#endif tw_dev->state[request_id] = TW_S_POSTED; tw_dev->posted_request_count++; if (tw_dev->posted_request_count > tw_dev->max_posted_request_count) { tw_dev->max_posted_request_count = tw_dev->posted_request_count; } } retval = 0;out: return retval;} /* End twa_post_command_packet() *//* This function will reset a device extension */static int twa_reset_device_extension(TW_Device_Extension *tw_dev){ int i = 0; int retval = 1; /* Abort all requests that are in progress */ for (i = 0; i < TW_Q_LENGTH; i++) { if ((tw_dev->state[i] != TW_S_FINISHED) && (tw_dev->state[i] != TW_S_INITIAL) && (tw_dev->state[i] != TW_S_COMPLETED)) { if (tw_dev->srb[i]) { tw_dev->srb[i]->result = (DID_RESET << 16); tw_dev->srb[i]->scsi_done(tw_dev->srb[i]); twa_unmap_scsi_data(tw_dev, i); } } } /* Reset queues and counts */ for (i = 0; i < TW_Q_LENGTH; i++) { tw_dev->free_queue[i] = i; tw_dev->state[i] = TW_S_INITIAL; } tw_dev->free_head = TW_Q_START; tw_dev->free_tail = TW_Q_START; tw_dev->posted_request_count = 0; tw_dev->pending_request_count = 0; tw_dev->pending_head = TW_Q_START; tw_dev->pending_tail = TW_Q_START; tw_dev->reset_print = 0; tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE; tw_dev->flags = 0; TW_DISABLE_INTERRUPTS(tw_dev); if (twa_reset_sequence(tw_dev, 1)) goto out; TW_ENABLE_AND_CLEAR_INTERRUPTS(tw_dev); retval = 0;out: return retval;} /* End twa_reset_device_extension() *//* This function will reset a controller */static int twa_reset_sequence(TW_Device_Extension *tw_dev, int soft_reset){ int tries = 0, retval = 1, flashed = 0, do_soft_reset = soft_reset; while (tries < TW_MAX_RESET_TRIES) { if (do_soft_reset) TW_SOFT_RESET(tw_dev); /* Make sure controller is in a good state */ if (twa_poll_status(tw_dev, TW_STATUS_MICROCONTROLLER_READY | (do_soft_reset == 1 ? TW_STATUS_ATTENTION_INTERRUPT : 0), 30)) {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?