📄 3w-xxxx.c
字号:
} /* End tw_initconnection() *//* This function will initialize the fields of a device extension */int tw_initialize_device_extension(TW_Device_Extension *tw_dev){ int i, imax; dprintk(KERN_NOTICE "3w-xxxx: tw_initialize_device_extension()\n"); imax = TW_Q_LENGTH; for (i=0; i<imax; i++) { /* Initialize command packet buffers */ tw_allocate_memory(tw_dev, i, sizeof(TW_Sector), 0); if (tw_dev->command_packet_virtual_address[i] == NULL) { printk(KERN_WARNING "3w-xxxx: tw_initialize_device_extension(): Bad command packet virtual address.\n"); return 1; } memset(tw_dev->command_packet_virtual_address[i], 0, sizeof(TW_Sector)); /* Initialize generic buffer */ tw_allocate_memory(tw_dev, i, sizeof(TW_Sector), 1); if (tw_dev->alignment_virtual_address[i] == NULL) { printk(KERN_WARNING "3w-xxxx: tw_initialize_device_extension(): Bad alignment virtual address.\n"); return 1; } memset(tw_dev->alignment_virtual_address[i], 0, sizeof(TW_Sector)); tw_dev->free_queue[i] = i; tw_dev->state[i] = TW_S_INITIAL; tw_dev->ioctl_size[i] = 0; tw_dev->aen_queue[i] = 0; tw_dev->ioctl_data[i] = NULL; } for (i=0;i<TW_MAX_UNITS;i++) { tw_dev->is_unit_present[i] = 0; tw_dev->is_raid_five[i] = 0; } tw_dev->num_units = 0; tw_dev->num_aborts = 0; tw_dev->num_resets = 0; tw_dev->posted_request_count = 0; tw_dev->max_posted_request_count = 0; tw_dev->max_sgl_entries = 0; tw_dev->sgl_entries = 0; tw_dev->host = NULL; tw_dev->pending_head = TW_Q_START; tw_dev->pending_tail = TW_Q_START; tw_dev->aen_head = 0; tw_dev->aen_tail = 0; tw_dev->sector_count = 0; tw_dev->max_sector_count = 0; tw_dev->aen_count = 0; tw_dev->num_raid_five = 0; spin_lock_init(&tw_dev->tw_lock); tw_dev->flags = 0; return 0;} /* End tw_initialize_device_extension() *//* This function will get unit info from the controller */int tw_initialize_units(TW_Device_Extension *tw_dev) { int found = 0; unsigned char request_id = 0; TW_Command *command_packet; TW_Param *param; int i, j, imax, num_units = 0, num_raid_five = 0; u32 status_reg_addr, status_reg_value; u32 command_que_addr, command_que_value; u32 response_que_addr; TW_Response_Queue response_queue; u32 param_value; unsigned char *is_unit_present; unsigned char *raid_level; dprintk(KERN_NOTICE "3w-xxxx: tw_initialize_units()\n"); status_reg_addr = tw_dev->registers.status_reg_addr; command_que_addr = tw_dev->registers.command_que_addr; response_que_addr = tw_dev->registers.response_que_addr; /* Setup the command packet */ command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id]; if (command_packet == NULL) { printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Bad command packet virtual address.\n"); return 1; } memset(command_packet, 0, sizeof(TW_Sector)); command_packet->byte0.opcode = TW_OP_GET_PARAM; 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.block_count = 1; /* Now setup the param */ if (tw_dev->alignment_virtual_address[request_id] == NULL) { printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): 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 = 3; /* unit summary table */ param->parameter_id = 3; /* unitstatus parameter */ param->parameter_size_bytes = TW_MAX_UNITS; param_value = tw_dev->alignment_physical_address[request_id]; if (param_value == 0) { printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): 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); /* Post the command packet to the board */ command_que_value = tw_dev->command_packet_physical_address[request_id]; if (command_que_value == 0) { printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Bad command packet physical address.\n"); return 1; } outl(command_que_value, command_que_addr); /* Poll for completion */ imax = TW_POLL_MAX_RETRIES; for(i=0; i<imax; i++) { mdelay(5); status_reg_value = inl(status_reg_addr); if (tw_check_bits(status_reg_value)) { dprintk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Unexpected bits.\n"); tw_decode_bits(tw_dev, status_reg_value); return 1; } if ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) { response_queue.value = inl(response_que_addr); request_id = (unsigned char)response_queue.u.response_id; if (request_id != 0) { /* unexpected request id */ printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Unexpected request id.\n"); return 1; } if (command_packet->status != 0) { /* bad response */ dprintk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Bad response, status = 0x%x, flags = 0x%x.\n", command_packet->status, command_packet->flags); tw_decode_error(tw_dev, command_packet->status, command_packet->flags, command_packet->byte3.unit); return 1; } found = 1; break; } } if (found == 0) { /* response never received */ printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): No response.\n"); return 1; } param = (TW_Param *)tw_dev->alignment_virtual_address[request_id]; is_unit_present = (unsigned char *)&(param->data[0]); /* Show all units present */ imax = TW_MAX_UNITS; for(i=0; i<imax; i++) { if (is_unit_present[i] == 0) { tw_dev->is_unit_present[i] = FALSE; } else { if (is_unit_present[i] & TW_UNIT_ONLINE) { dprintk(KERN_NOTICE "3w-xxxx: tw_initialize_units(): Unit %d found.\n", i); tw_dev->is_unit_present[i] = TRUE; num_units++; } } } tw_dev->num_units = num_units; if (num_units == 0) { dprintk(KERN_NOTICE "3w-xxxx: tw_initialize_units(): No units found.\n"); return 1; } /* Find raid 5 arrays */ for (j=0;j<TW_MAX_UNITS;j++) { if (tw_dev->is_unit_present[j] == 0) continue; command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id]; if (command_packet == NULL) { printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Bad command packet virtual address.\n"); return 1; } memset(command_packet, 0, sizeof(TW_Sector)); command_packet->byte0.opcode = TW_OP_GET_PARAM; 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.block_count = 1; /* Now setup the param */ if (tw_dev->alignment_virtual_address[request_id] == NULL) { printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): 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 = 0x300+j; /* unit summary table */ param->parameter_id = 0x6; /* unit descriptor */ param->parameter_size_bytes = 0xc; param_value = tw_dev->alignment_physical_address[request_id]; if (param_value == 0) { printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): 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); /* Post the command packet to the board */ command_que_value = tw_dev->command_packet_physical_address[request_id]; if (command_que_value == 0) { printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Bad command packet physical address.\n"); return 1; } outl(command_que_value, command_que_addr); /* Poll for completion */ imax = TW_POLL_MAX_RETRIES; for(i=0; i<imax; i++) { mdelay(5); status_reg_value = inl(status_reg_addr); if (tw_check_bits(status_reg_value)) { dprintk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Unexpected bits.\n"); tw_decode_bits(tw_dev, status_reg_value); return 1; } if ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) { response_queue.value = inl(response_que_addr); request_id = (unsigned char)response_queue.u.response_id; if (request_id != 0) { /* unexpected request id */ printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Unexpected request id.\n"); return 1; } if (command_packet->status != 0) { /* bad response */ dprintk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Bad response, status = 0x%x, flags = 0x%x.\n", command_packet->status, command_packet->flags); tw_decode_error(tw_dev, command_packet->status, command_packet->flags, command_packet->byte3.unit); return 1; } found = 1; break; } } if (found == 0) { /* response never received */ printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): No response.\n"); return 1; } param = (TW_Param *)tw_dev->alignment_virtual_address[request_id]; raid_level = (unsigned char *)&(param->data[1]); if (*raid_level == 5) { dprintk(KERN_WARNING "3w-xxxx: Found unit %d to be a raid5 unit.\n", j); tw_dev->is_raid_five[j] = 1; num_raid_five++; } } tw_dev->num_raid_five = num_raid_five; /* Now allocate raid5 bounce buffers */ if ((num_raid_five != 0) && (tw_dev->tw_pci_dev->device == TW_DEVICE_ID)) { for (i=0;i<TW_MAX_BOUNCEBUF;i++) { tw_allocate_memory(tw_dev, i, sizeof(TW_Sector)*TW_MAX_BOUNCE_SECTORS, 2); if (tw_dev->bounce_buffer[i] == NULL) { printk(KERN_WARNING "3w-xxxx: Bounce buffer allocation failed.\n"); return 1; } memset(tw_dev->bounce_buffer[i], 0, sizeof(TW_Sector)*TW_MAX_BOUNCE_SECTORS); } } return 0;} /* End tw_initialize_units() *//* This function is the interrupt service routine */static void tw_interrupt(int irq, void *dev_instance, struct pt_regs *regs) { int request_id; u32 status_reg_addr, status_reg_value; u32 response_que_addr; TW_Device_Extension *tw_dev = (TW_Device_Extension *)dev_instance; TW_Response_Queue response_que; int error = 0; int do_response_interrupt=0; int do_attention_interrupt=0; int do_host_interrupt=0; int do_command_interrupt=0; unsigned long flags = 0; TW_Command *command_packet; if (test_and_set_bit(TW_IN_INTR, &tw_dev->flags)) return; spin_lock_irqsave(&io_request_lock, flags); if (tw_dev->tw_pci_dev->irq == irq) { spin_lock(&tw_dev->tw_lock); dprintk(KERN_WARNING "3w-xxxx: tw_interrupt()\n"); /* Read the registers */ status_reg_addr = tw_dev->registers.status_reg_addr; response_que_addr = tw_dev->registers.response_que_addr; status_reg_value = inl(status_reg_addr); /* Check which interrupt */ if (status_reg_value & TW_STATUS_HOST_INTERRUPT) do_host_interrupt=1; if (status_reg_value & TW_STATUS_ATTENTION_INTERRUPT) do_attention_interrupt=1; if (status_reg_value & TW_STATUS_COMMAND_INTERRUPT) do_command_interrupt=1; if (status_reg_value & TW_STATUS_RESPONSE_INTERRUPT) do_response_interrupt=1; /* Handle host interrupt */ if (do_host_interrupt) { dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): Received host interrupt.\n"); tw_clear_host_interrupt(tw_dev); } /* Handle attention interrupt */ if (do_attention_interrupt) { dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): Received attention interrupt.\n"); dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Clearing attention interrupt.\n"); tw_clear_attention_interrupt(tw_dev); tw_state_request_start(tw_dev, &request_id); error = tw_aen_read_queue(tw_dev, request_id); if (error) { printk(KERN_WARNING "3w-xxxx: scsi%d: Error reading aen queue.\n", tw_dev->host->host_no); tw_dev->state[request_id] = TW_S_COMPLETED; tw_state_request_finish(tw_dev, request_id); } } /* Handle command interrupt */ if (do_command_interrupt) { /* 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];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -