📄 3w-xxxx.c
字号:
if ((status_reg_value & TW_STATUS_COMMAND_QUEUE_FULL) == 0) { /* We successfully posted the command packet */ outl(command_que_value, TW_COMMAND_QUEUE_REG_ADDR(tw_dev)); 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 return valid sense buffer information for failed cmds */static int tw_decode_sense(TW_Device_Extension *tw_dev, int request_id, int fill_sense){ int i; TW_Command *command; dprintk(KERN_WARNING "3w-xxxx: tw_decode_sense()\n"); command = (TW_Command *)tw_dev->command_packet_virtual_address[request_id]; printk(KERN_WARNING "3w-xxxx: scsi%d: Command failed: status = 0x%x, flags = 0x%x, unit #%d.\n", tw_dev->host->host_no, command->status, command->flags, TW_UNIT_OUT(command->unit__hostid)); /* Attempt to return intelligent sense information */ if (fill_sense) { if ((command->status == 0xc7) || (command->status == 0xcb)) { for (i = 0; i < ARRAY_SIZE(tw_sense_table); i++) { if (command->flags == tw_sense_table[i][0]) { /* Valid bit and 'current errors' */ tw_dev->srb[request_id]->sense_buffer[0] = (0x1 << 7 | 0x70); /* Sense key */ tw_dev->srb[request_id]->sense_buffer[2] = tw_sense_table[i][1]; /* Additional sense length */ tw_dev->srb[request_id]->sense_buffer[7] = 0xa; /* 10 bytes */ /* Additional sense code */ tw_dev->srb[request_id]->sense_buffer[12] = tw_sense_table[i][2]; /* Additional sense code qualifier */ tw_dev->srb[request_id]->sense_buffer[13] = tw_sense_table[i][3]; tw_dev->srb[request_id]->result = (DID_OK << 16) | (CHECK_CONDITION << 1); return TW_ISR_DONT_RESULT; /* Special case for isr to not over-write result */ } } } /* If no table match, error so we get a reset */ return 1; } return 0;} /* End tw_decode_sense() *//* This function will report controller error status */static int tw_check_errors(TW_Device_Extension *tw_dev) { u32 status_reg_value; status_reg_value = inl(TW_STATUS_REG_ADDR(tw_dev)); if (TW_STATUS_ERRORS(status_reg_value) || tw_check_bits(status_reg_value)) { tw_decode_bits(tw_dev, status_reg_value, 0); return 1; } return 0;} /* End tw_check_errors() *//* This function will empty the response que */static void tw_empty_response_que(TW_Device_Extension *tw_dev) { u32 status_reg_value, response_que_value; status_reg_value = inl(TW_STATUS_REG_ADDR(tw_dev)); while ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) { response_que_value = inl(TW_RESPONSE_QUEUE_REG_ADDR(tw_dev)); status_reg_value = inl(TW_STATUS_REG_ADDR(tw_dev)); }} /* End tw_empty_response_que() *//* This function will free a request_id */static void tw_state_request_finish(TW_Device_Extension *tw_dev, int request_id){ tw_dev->free_queue[tw_dev->free_tail] = request_id; tw_dev->state[request_id] = TW_S_FINISHED; tw_dev->free_tail = (tw_dev->free_tail + 1) % TW_Q_LENGTH;} /* End tw_state_request_finish() *//* This function will assign an available request_id */static void tw_state_request_start(TW_Device_Extension *tw_dev, int *request_id){ *request_id = tw_dev->free_queue[tw_dev->free_head]; tw_dev->free_head = (tw_dev->free_head + 1) % TW_Q_LENGTH; tw_dev->state[*request_id] = TW_S_STARTED;} /* End tw_state_request_start() *//* Show some statistics about the card */static ssize_t tw_show_stats(struct class_device *class_dev, char *buf){ struct Scsi_Host *host = class_to_shost(class_dev); TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata; unsigned long flags = 0; ssize_t len; spin_lock_irqsave(tw_dev->host->host_lock, flags); len = snprintf(buf, PAGE_SIZE, "3w-xxxx Driver version: %s\n" "Current commands posted: %4d\n" "Max commands posted: %4d\n" "Current pending commands: %4d\n" "Max pending commands: %4d\n" "Last sgl length: %4d\n" "Max sgl length: %4d\n" "Last sector count: %4d\n" "Max sector count: %4d\n" "SCSI Host Resets: %4d\n" "AEN's: %4d\n", TW_DRIVER_VERSION, tw_dev->posted_request_count, tw_dev->max_posted_request_count, tw_dev->pending_request_count, tw_dev->max_pending_request_count, tw_dev->sgl_entries, tw_dev->max_sgl_entries, tw_dev->sector_count, tw_dev->max_sector_count, tw_dev->num_resets, tw_dev->aen_count); spin_unlock_irqrestore(tw_dev->host->host_lock, flags); return len;} /* End tw_show_stats() *//* This function will set a devices queue depth */static int tw_change_queue_depth(struct scsi_device *sdev, int queue_depth){ if (queue_depth > TW_Q_LENGTH-2) queue_depth = TW_Q_LENGTH-2; scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, queue_depth); return queue_depth;} /* End tw_change_queue_depth() *//* Create sysfs 'stats' entry */static struct class_device_attribute tw_host_stats_attr = { .attr = { .name = "stats", .mode = S_IRUGO, }, .show = tw_show_stats};/* Host attributes initializer */static struct class_device_attribute *tw_host_attrs[] = { &tw_host_stats_attr, NULL,};/* This function will read the aen queue from the isr */static int tw_aen_read_queue(TW_Device_Extension *tw_dev, int request_id) { TW_Command *command_packet; TW_Param *param; unsigned long command_que_value; u32 status_reg_value; unsigned long param_value = 0; dprintk(KERN_NOTICE "3w-xxxx: tw_aen_read_queue()\n"); status_reg_value = inl(TW_STATUS_REG_ADDR(tw_dev)); if (tw_check_bits(status_reg_value)) { dprintk(KERN_WARNING "3w-xxxx: tw_aen_read_queue(): Unexpected bits.\n"); tw_decode_bits(tw_dev, status_reg_value, 1); return 1; } if (tw_dev->command_packet_virtual_address[request_id] == NULL) { printk(KERN_WARNING "3w-xxxx: tw_aen_read_queue(): Bad command packet virtual address.\n"); return 1; } command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id]; memset(command_packet, 0, sizeof(TW_Sector)); command_packet->opcode__sgloffset = TW_OPSGL_IN(2, TW_OP_GET_PARAM); command_packet->size = 4; command_packet->request_id = request_id; command_packet->status = 0; command_packet->flags = 0; command_packet->byte6.parameter_count = 1; command_que_value = tw_dev->command_packet_physical_address[request_id]; if (command_que_value == 0) { printk(KERN_WARNING "3w-xxxx: tw_aen_read_queue(): Bad command packet physical address.\n"); return 1; } /* Now setup the param */ if (tw_dev->alignment_virtual_address[request_id] == NULL) { printk(KERN_WARNING "3w-xxxx: tw_aen_read_queue(): Bad alignment virtual address.\n"); return 1; } param = (TW_Param *)tw_dev->alignment_virtual_address[request_id]; memset(param, 0, sizeof(TW_Sector)); param->table_id = 0x401; /* AEN table */ param->parameter_id = 2; /* Unit code */ param->parameter_size_bytes = 2; param_value = tw_dev->alignment_physical_address[request_id]; if (param_value == 0) { printk(KERN_WARNING "3w-xxxx: tw_aen_read_queue(): Bad alignment physical address.\n"); return 1; } command_packet->byte8.param.sgl[0].address = param_value; command_packet->byte8.param.sgl[0].length = sizeof(TW_Sector); /* Now post the command packet */ if ((status_reg_value & TW_STATUS_COMMAND_QUEUE_FULL) == 0) { dprintk(KERN_WARNING "3w-xxxx: tw_aen_read_queue(): Post succeeded.\n"); tw_dev->srb[request_id] = NULL; /* Flag internal command */ tw_dev->state[request_id] = TW_S_POSTED; outl(command_que_value, TW_COMMAND_QUEUE_REG_ADDR(tw_dev)); } else { printk(KERN_WARNING "3w-xxxx: tw_aen_read_queue(): Post failed, will retry.\n"); return 1; } return 0;} /* End tw_aen_read_queue() *//* This function will complete an aen request from the isr */static int tw_aen_complete(TW_Device_Extension *tw_dev, int request_id) { TW_Param *param; unsigned short aen; int error = 0, table_max = 0; dprintk(KERN_WARNING "3w-xxxx: tw_aen_complete()\n"); if (tw_dev->alignment_virtual_address[request_id] == NULL) { printk(KERN_WARNING "3w-xxxx: tw_aen_complete(): Bad alignment virtual address.\n"); return 1; } param = (TW_Param *)tw_dev->alignment_virtual_address[request_id]; aen = *(unsigned short *)(param->data); dprintk(KERN_NOTICE "3w-xxxx: tw_aen_complete(): Queue'd code 0x%x\n", aen); /* Print some useful info when certain aen codes come out */ if (aen == 0x0ff) { printk(KERN_WARNING "3w-xxxx: scsi%d: AEN: INFO: AEN queue overflow.\n", tw_dev->host->host_no); } else { table_max = ARRAY_SIZE(tw_aen_string); if ((aen & 0x0ff) < table_max) { if ((tw_aen_string[aen & 0xff][strlen(tw_aen_string[aen & 0xff])-1]) == '#') { printk(KERN_WARNING "3w-xxxx: scsi%d: AEN: %s%d.\n", tw_dev->host->host_no, tw_aen_string[aen & 0xff], aen >> 8); } else { if (aen != 0x0) printk(KERN_WARNING "3w-xxxx: scsi%d: AEN: %s.\n", tw_dev->host->host_no, tw_aen_string[aen & 0xff]); } } else { printk(KERN_WARNING "3w-xxxx: scsi%d: Received AEN %d.\n", tw_dev->host->host_no, aen); } } if (aen != TW_AEN_QUEUE_EMPTY) { tw_dev->aen_count++; /* Now queue the code */ tw_dev->aen_queue[tw_dev->aen_tail] = aen; if (tw_dev->aen_tail == TW_Q_LENGTH - 1) { tw_dev->aen_tail = TW_Q_START; } else { tw_dev->aen_tail = tw_dev->aen_tail + 1; } if (tw_dev->aen_head == tw_dev->aen_tail) { 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; } } error = tw_aen_read_queue(tw_dev, request_id); if (error) { printk(KERN_WARNING "3w-xxxx: scsi%d: Error completing AEN.\n", tw_dev->host->host_no); tw_dev->state[request_id] = TW_S_COMPLETED; tw_state_request_finish(tw_dev, request_id); } } else { tw_dev->state[request_id] = TW_S_COMPLETED; tw_state_request_finish(tw_dev, request_id); } return 0;} /* End tw_aen_complete() *//* This function will drain the aen queue after a soft reset */static int tw_aen_drain_queue(TW_Device_Extension *tw_dev){ TW_Command *command_packet; TW_Param *param; int request_id = 0; unsigned long command_que_value; unsigned long param_value; TW_Response_Queue response_queue; unsigned short aen; unsigned short aen_code; int finished = 0; int first_reset = 0; int queue = 0; int found = 0, table_max = 0; dprintk(KERN_NOTICE "3w-xxxx: tw_aen_drain_queue()\n"); if (tw_poll_status(tw_dev, TW_STATUS_ATTENTION_INTERRUPT | TW_STATUS_MICROCONTROLLER_READY, 30)) { dprintk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): No attention interrupt for card %d.\n", tw_device_extension_count); return 1; } TW_CLEAR_ATTENTION_INTERRUPT(tw_dev); /* Empty response queue */ tw_empty_response_que(tw_dev); /* Initialize command packet */ if (tw_dev->command_packet_virtual_address[request_id] == NULL) { printk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Bad command packet virtual address.\n"); return 1; } command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id]; memset(command_packet, 0, sizeof(TW_Sector)); command_packet->opcode__sgloffset = TW_OPSGL_IN(2, TW_OP_GET_PARAM); command_packet->size = 4; command_packet->request_id = request_id; command_packet->status = 0; command_packet->flags = 0; command_packet->byte6.parameter_count = 1; command_que_value = tw_dev->command_packet_physical_address[request_id]; if (command_que_value == 0) { printk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Bad command packet physical address.\n"); return 1; } /* Now setup the param */ if (tw_dev->alignment_virtual_address[request_id] == NULL) { printk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Bad alignment virtual address.\n"); return 1; } param = (TW_Param *)tw_dev->alignment_virtual_address[request_id]; memset(param, 0, sizeof(TW_Sector)); param->table_id = 0x401; /* AEN table */ param->parameter_id = 2; /* Unit code */ param->parameter_size_bytes = 2; param_value = tw_dev->alignment_physical_address[request_id]; if (param_value == 0) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -