📄 3w-xxxx.c
字号:
return numcards;} /* End tw_findcards() *//* This function will free up device extension resources */void tw_free_device_extension(TW_Device_Extension *tw_dev){ int i, imax; imax = TW_Q_LENGTH; dprintk(KERN_NOTICE "3w-xxxx: tw_free_device_extension()\n"); /* Free command packet and generic buffer memory */ for (i=0;i<imax;i++) { if (tw_dev->command_packet_virtual_address[i]) kfree(tw_dev->command_packet_virtual_address[i]); if (tw_dev->alignment_virtual_address[i]) kfree(tw_dev->alignment_virtual_address[i]); }} /* End tw_free_device_extension() *//* Clean shutdown routine */static int tw_halt(struct notifier_block *nb, ulong event, void *buf){ int i; for (i=0;i<tw_device_extension_count;i++) { printk(KERN_NOTICE "3w-xxxx: Notifying card #%d\n", i); tw_shutdown_device(tw_device_extension_list[i]); } unregister_reboot_notifier(&tw_notifier); return NOTIFY_OK;} /* End tw_halt() *//* This function will send an initconnection command to controller */int tw_initconnection(TW_Device_Extension *tw_dev, int message_credits) { u32 command_que_addr, command_que_value; u32 status_reg_addr, status_reg_value; u32 response_que_addr; TW_Command *command_packet; TW_Response_Queue response_queue; int request_id = 0; int i = 0; int imax = 0; dprintk(KERN_NOTICE "3w-xxxx: tw_initconnection()\n"); command_que_addr = tw_dev->registers.command_que_addr; status_reg_addr = tw_dev->registers.status_reg_addr; response_que_addr = tw_dev->registers.response_que_addr; /* Initialize InitConnection command packet */ if (tw_dev->command_packet_virtual_address[request_id] == NULL) { printk(KERN_WARNING "3w-xxxx: tw_initconnection(): 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->byte0.opcode = TW_OP_INIT_CONNECTION; command_packet->byte0.sgl_offset = 0x0; command_packet->size = TW_INIT_COMMAND_PACKET_SIZE; command_packet->request_id = request_id; command_packet->byte3.unit = 0x0; command_packet->byte3.host_id = 0x0; command_packet->status = 0x0; command_packet->flags = 0x0; command_packet->byte6.message_credits = message_credits; command_packet->byte8.init_connection.response_queue_pointer = 0x0; command_que_value = tw_dev->command_packet_physical_address[request_id]; if (command_que_value == 0) { printk(KERN_WARNING "3w-xxxx: tw_initconnection(): Bad command packet physical address.\n"); return 1; } /* Send command packet to the board */ outl(command_que_value, command_que_addr); /* Poll for completion */ imax = TW_POLL_MAX_RETRIES; for (i=0;i<imax;i++) { mdelay(10); status_reg_value = inl(status_reg_addr); if (tw_check_bits(status_reg_value)) { printk(KERN_WARNING "3w-xxxx: tw_initconnection(): Unexpected bits.\n"); 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_initconnection(): Unexpected request id.\n"); return 1; } if (command_packet->status != 0) { /* bad response */ printk(KERN_WARNING "3w-xxxx: tw_initconnection(): Bad response, status = 0x%x, flags = 0x%x.\n", command_packet->status, command_packet->flags); return 1; } break; /* Response was okay, so we exit */ } } return 0;} /* 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; } for (i=0;i<TW_MAX_UNITS;i++) tw_dev->is_unit_present[i] = 0; tw_dev->num_units = 0; tw_dev->num_aborts = 0; tw_dev->num_resets = 0; tw_dev->free_head = TW_Q_START; tw_dev->free_tail = TW_Q_LENGTH - 1; 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; 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, imax, num_units = 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; 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(10); status_reg_value = inl(status_reg_addr); if (tw_check_bits(status_reg_value)) { printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Unexpected bits.\n"); 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 */ printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Bad response, status = 0x%x, flags = 0x%x.\n", command_packet->status, command_packet->flags); 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) { printk(KERN_NOTICE "3w-xxxx: tw_initialize_units(): No units found.\n"); return 1; } 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; int flags = 0; int flags2 = 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_irqsave(&tw_dev->tw_lock, flags2); dprintk(KERN_NOTICE "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"); tw_state_request_start(tw_dev, &request_id); error = tw_aen_read_queue(tw_dev, request_id); if (error) { printk(KERN_WARNING "3w-xxxx: tw_interrupt(): Error reading aen queue.\n"); tw_dev->state[request_id] = TW_S_COMPLETED; tw_state_request_finish(tw_dev, request_id); } else { dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Clearing attention interrupt.\n"); tw_clear_attention_interrupt(tw_dev); } } /* 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]; if (tw_dev->state[request_id] != TW_S_PENDING) { printk(KERN_WARNING "3w-xxxx: tw_interrupt(): Found request id that wasn't pending.\n"); break; } if (tw_post_command_packet(tw_dev, request_id)==0) { if (tw_dev->pending_head == TW_Q_LENGTH-1) { tw_dev->pending_head = TW_Q_START; } else { tw_dev->pending_head = tw_dev->pending_head + 1; } tw_dev->pending_request_count--; } else { break; } } /* If there are no more pending requests, we mask command interrupt */ if (tw_dev->pending_request_count == 0) tw_mask_command_interrupt(tw_dev); } /* Handle response interrupt */ if (do_response_interrupt) { /* Drain the response queue from the board */ while ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) { response_que.value = inl(response_que_addr); request_id = response_que.u.response_id; command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id]; if (command_packet->status != 0) { printk(KERN_WARNING "3w-xxxx: tw_interrupt(): Bad response, status = 0x%x, flags = 0x%x.\n", command_packet->status, command_packet->flags);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -