📄 3w-xxxx.c
字号:
} if (tw_dev->state[request_id] != TW_S_POSTED) { printk(KERN_WARNING "3w-xxxx: tw_interrupt(): Received a request id (%d) (opcode = 0x%x) that wasn't posted.\n", request_id, command_packet->byte0.opcode); } error = 0; dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): Response queue request id: %d.\n", request_id); /* Check for internal command */ if (tw_dev->srb[request_id] == 0) { dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Found internally posted command.\n"); error = tw_aen_complete(tw_dev, request_id); if (error) { printk(KERN_WARNING "3w-xxxx: tw_interrupt(): Error completing aen.\n"); } status_reg_value = inl(status_reg_addr); if (tw_check_bits(status_reg_value)) { printk(KERN_WARNING "3w-xxxx: tw_interrupt(): Unexpected bits.\n"); } } else { switch (tw_dev->srb[request_id]->cmnd[0]) { case READ_10: dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught READ_10\n"); case READ_6: dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught READ_6\n"); break; case WRITE_10: dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught WRITE_10\n"); case WRITE_6: dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught WRITE_6\n"); break; case INQUIRY: dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught INQUIRY\n"); error = tw_scsiop_inquiry_complete(tw_dev, request_id); break; case READ_CAPACITY: dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught READ_CAPACITY\n"); error = tw_scsiop_read_capacity_complete(tw_dev, request_id); break; case TW_IOCTL: dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught TW_IOCTL\n"); error = tw_ioctl_complete(tw_dev, request_id); break; default: printk(KERN_WARNING "3w-xxxx: tw_interrupt(): Unknown scsi opcode: 0x%x.\n", tw_dev->srb[request_id]->cmnd[0]); tw_dev->srb[request_id]->result = (DID_BAD_TARGET << 16); tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]); } if (error) { /* Tell scsi layer there was an error */ printk(KERN_WARNING "3w-xxxx: tw_interrupt(): Scsi Error.\n"); tw_dev->srb[request_id]->result = (DID_ERROR << 16); } else { /* Tell scsi layer command was a success */ tw_dev->srb[request_id]->result = (DID_OK << 16); } tw_dev->state[request_id] = TW_S_COMPLETED; tw_state_request_finish(tw_dev, request_id); tw_dev->posted_request_count--; tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]); status_reg_value = inl(status_reg_addr); if (tw_check_bits(status_reg_value)) { printk(KERN_WARNING "3w-xxxx: tw_interrupt(): Unexpected bits.\n"); } } } } spin_unlock_irqrestore(&tw_dev->tw_lock, flags2); } spin_unlock_irqrestore(&io_request_lock, flags); clear_bit(TW_IN_INTR, &tw_dev->flags);} /* End tw_interrupt() *//* This function handles ioctls from userspace to the driver */int tw_ioctl(TW_Device_Extension *tw_dev, int request_id){ unsigned char opcode; int bufflen; TW_Param *param; TW_Command *command_packet; u32 param_value; TW_Ioctl *ioctl = NULL; int tw_aen_code; ioctl = (TW_Ioctl *)tw_dev->srb[request_id]->request_buffer; if (ioctl == NULL) { printk(KERN_WARNING "3w-xxxx: tw_ioctl(): Request buffer NULL.\n"); tw_dev->state[request_id] = TW_S_COMPLETED; tw_state_request_finish(tw_dev, request_id); tw_dev->srb[request_id]->result = (DID_OK << 16); tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]); return 0; } bufflen = tw_dev->srb[request_id]->request_bufflen; /* Initialize command packet */ command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id]; if (command_packet == NULL) { printk(KERN_WARNING "3w-xxxx: tw_ioctl(): Bad command packet virtual address.\n"); tw_dev->state[request_id] = TW_S_COMPLETED; tw_state_request_finish(tw_dev, request_id); tw_dev->srb[request_id]->result = (DID_OK << 16); tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]); return 0; } memset(command_packet, 0, sizeof(TW_Sector)); /* Initialize param */ if (tw_dev->alignment_virtual_address[request_id] == NULL) { printk(KERN_WARNING "3w-xxxx: tw_ioctl(): Bad alignment virtual address.\n"); tw_dev->state[request_id] = TW_S_COMPLETED; tw_state_request_finish(tw_dev, request_id); tw_dev->srb[request_id]->result = (DID_OK << 16); tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]); return 0; } param = (TW_Param *)tw_dev->alignment_virtual_address[request_id]; memset(param, 0, sizeof(TW_Sector)); dprintk(KERN_NOTICE "opcode = %d table_id = %d parameter_id = %d parameter_size_bytes = %d\n", ioctl->opcode, ioctl->table_id, ioctl->parameter_id,, ioctl->parameter_size_bytes); opcode = ioctl->opcode; switch (opcode) { case TW_OP_NOP: dprintk(KERN_NOTICE "3w-xxxx: tw_ioctl(): caught TW_OP_NOP.\n"); command_packet->byte0.opcode = TW_OP_NOP; break; case TW_OP_GET_PARAM: dprintk(KERN_NOTICE "3w-xxxx: tw_ioctl(): caught TW_OP_GET_PARAM.\n"); command_packet->byte0.opcode = TW_OP_GET_PARAM; param->table_id = ioctl->table_id; param->parameter_id = ioctl->parameter_id; param->parameter_size_bytes = ioctl->parameter_size_bytes; tw_dev->ioctl_size[request_id] = ioctl->parameter_size_bytes; dprintk(KERN_NOTICE "table_id = %d parameter_id = %d parameter_size_bytes %d\n", param->table_id, param->parameter_id, param->parameter_size_bytes); break; case TW_OP_SET_PARAM: dprintk(KERN_NOTICE "3w-xxxx: tw_ioctl(): caught TW_OP_SET_PARAM: table_id = %d, parameter_id = %d, parameter_size_bytes = %d.\n", ioctl->table_id, ioctl->parameter_id, ioctl->parameter_size_bytes); command_packet->byte0.opcode = TW_OP_SET_PARAM; param->table_id = ioctl->table_id; param->parameter_id = ioctl->parameter_id; param->parameter_size_bytes = ioctl->parameter_size_bytes; memcpy(param->data, ioctl->data, ioctl->parameter_size_bytes); break; case TW_OP_AEN_LISTEN: dprintk(KERN_NOTICE "3w-xxxx: tw_ioctl(): caught TW_OP_AEN_LISTEN.\n"); if (tw_dev->aen_head == tw_dev->aen_tail) { /* aen queue empty */ dprintk(KERN_NOTICE "3w-xxxx: tw_ioctl(): Aen queue empty.\n"); tw_aen_code = TW_AEN_QUEUE_EMPTY; memcpy(tw_dev->srb[request_id]->request_buffer, &tw_aen_code, ioctl->parameter_size_bytes); } else { /* Copy aen queue entry to request buffer */ dprintk(KERN_NOTICE "3w-xxxx: tw_ioctl(): Returning aen 0x%x\n", tw_dev->aen_queue[tw_dev->aen_head]); tw_aen_code = tw_dev->aen_queue[tw_dev->aen_head]; memcpy(tw_dev->srb[request_id]->request_buffer, &tw_aen_code, ioctl->parameter_size_bytes); if (tw_dev->aen_head == TW_Q_LENGTH - 1) { tw_dev->aen_head = TW_Q_START; } else { tw_dev->aen_head = tw_dev->aen_head + 1; } } tw_dev->state[request_id] = TW_S_COMPLETED; tw_state_request_finish(tw_dev, request_id); tw_dev->srb[request_id]->result = (DID_OK << 16); tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]); return 0; case TW_CMD_PACKET: memcpy(command_packet, ioctl->data, sizeof(TW_Command)); command_packet->request_id = request_id; tw_post_command_packet(tw_dev, request_id); return 0; default: printk(KERN_WARNING "3w-xxxx: Unknown ioctl 0x%x.\n", opcode); tw_dev->state[request_id] = TW_S_COMPLETED; tw_state_request_finish(tw_dev, request_id); tw_dev->srb[request_id]->result = (DID_OK << 16); tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]); return 0; } param_value = tw_dev->alignment_physical_address[request_id]; if (param_value == 0) { printk(KERN_WARNING "3w-xxxx: tw_ioctl(): Bad alignment physical address.\n"); tw_dev->state[request_id] = TW_S_COMPLETED; tw_state_request_finish(tw_dev, request_id); tw_dev->srb[request_id]->result = (DID_OK << 16); tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]); } command_packet->byte8.param.sgl[0].address = param_value; command_packet->byte8.param.sgl[0].length = sizeof(TW_Sector); command_packet->byte0.sgl_offset = 2; command_packet->size = 4; command_packet->request_id = request_id; command_packet->byte3.unit = 0; command_packet->byte3.host_id = 0; command_packet->status = 0; command_packet->flags = 0; command_packet->byte6.parameter_count = 1; /* Now try to post the command to the board */ tw_post_command_packet(tw_dev, request_id); return 0;} /* End tw_ioctl() *//* This function is called by the isr to complete ioctl requests */int tw_ioctl_complete(TW_Device_Extension *tw_dev, int request_id){ unsigned char *param_data; unsigned char *buff; TW_Param *param; dprintk(KERN_NOTICE "3w-xxxx: tw_ioctl_complete()\n"); buff = tw_dev->srb[request_id]->request_buffer; if (buff == NULL) { printk(KERN_WARNING "3w-xxxx: tw_ioctl_complete(): Request buffer NULL.\n"); return 1; } dprintk(KERN_NOTICE "3w-xxxx: tw_ioctl_complete(): Request_bufflen = %d\n", tw_dev->srb[request_id]->request_bufflen); memset(buff, 0, tw_dev->srb[request_id]->request_bufflen); param = (TW_Param *)tw_dev->alignment_virtual_address[request_id]; if (param == NULL) { printk(KERN_WARNING "3w-xxxx: tw_scsiop_read_capacity_complete(): Bad alignment virtual address.\n"); return 1; } param_data = &(param->data[0]); memcpy(buff, param_data, tw_dev->ioctl_size[request_id]); return 0;} /* End tw_ioctl_complete() *//* This function will mask the command interrupt */void tw_mask_command_interrupt(TW_Device_Extension *tw_dev){ u32 control_reg_addr, control_reg_value; control_reg_addr = tw_dev->registers.control_reg_addr; control_reg_value = TW_CONTROL_MASK_COMMAND_INTERRUPT; outl(control_reg_value, control_reg_addr);} /* End tw_mask_command_interrupt() *//* This function will poll the status register for a flag */int tw_poll_status(TW_Device_Extension *tw_dev, u32 flag, int seconds){ u32 status_reg_addr, status_reg_value; struct timeval before, timeout; status_reg_addr = tw_dev->registers.status_reg_addr; do_gettimeofday(&before); status_reg_value = inl(status_reg_addr); while ((status_reg_value & flag) != flag) { status_reg_value = inl(status_reg_addr); do_gettimeofday(&timeout); if (before.tv_sec + seconds < timeout.tv_sec) { printk(KERN_WARNING "3w-xxxx: tw_poll_status(): Flag 0x%x not found.\n", flag); return 1; } mdelay(1); } return 0;} /* End tw_poll_status() *//* This function will attempt to post a command packet to the board */int tw_post_command_packet(TW_Device_Extension *tw_dev, int request_id){ u32 status_reg_addr, status_reg_value; u32 command_que_addr, command_que_value; dprintk(KERN_NOTICE "3w-xxxx: tw_post_command_packet()\n"); command_que_addr = tw_dev->registers.command_que_addr; command_que_value = tw_dev->command_packet_physical_address[request_id]; status_reg_addr = tw_dev->registers.status_reg_addr; status_reg_value = inl(status_reg_addr); if (tw_check_bits(status_reg_value)) printk(KERN_WARNING "3w-xxxx: tw_post_command_packet(): Unexpected bits.\n"); if ((status_reg_value & TW_STATUS_COMMAND_QUEUE_FULL) == 0) { /* We successfully posted the command packet */ outl(command_que_value, command_que_addr); 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; } } else { /* Couldn't post the command packet, so we do it in the isr */ 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; if (tw_dev->pending_tail == TW_Q_LENGTH-1) { tw_dev->pending_tail = TW_Q_START; } else { tw_dev->pending_tail = tw_dev->pending_tail + 1; } } tw_unmask_command_interrupt(tw_dev); return 1; } return 0;} /* End tw_post_command_packet() *//* This function will reset a device extension */int tw_reset_device_extension(TW_Device_Extension *tw_dev) { int imax = 0; int i = 0; Scsi_Cmnd *srb; dprintk(KERN_NOTICE "3w-xxxx: tw_reset_device_extension()\n"); imax = TW_Q_LENGTH; if (tw_reset_sequence(tw_dev)) { printk(KERN_WARNING "3w-xxxx: tw_reset_device_extension(): Reset sequence failed for card %d.\n", tw_dev->host->host_no); return 1; } /* Abort all requests that are in progress */ for (i=0;i<imax;i++) { if ((tw_dev->state[i] != TW_S_FINISHED) && (tw_dev->state[i] != TW_S_INITIAL) && (tw_dev->state[i] != TW_S_COMPLETED)) { srb = tw_dev->srb[i]; srb->result = (DID_RESET << 16); tw_dev->srb[i]->scsi_done(tw_dev->srb[i]); } } /* Reset queues and counts */ for (i=0;i<imax;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_LENGTH - 1; 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; return 0;} /* End tw_reset_device_extension() *//* This function will reset a controller */int tw_reset_sequence(TW_Device_Extension *tw_dev) { int error = 0; int tries = 0; /* Disable interrupts */ tw_disable_interrupts(tw_dev); /* Reset the board */ while (tries < TW_MAX_RESET_TRIES) { tw_soft_reset(tw_dev); error = tw_aen_drain_queue(tw_dev); if (error) { printk(KERN_WARNING "3w-xxxx: tw_reset_sequence(): No attention interrupt for card %d.\n", tw_dev->host->host_no); tries++; continue; } /* Check for controller errors */ if (tw_check_errors(tw_dev)) { printk(KERN_WARNING "3w-xxxx: tw_reset_sequence(): Controller errors found, soft resetting card %d.\n", tw_dev->host->host_no); tries++; continue; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -