?? 3w-xxxx.c
字號:
/* Check for errors and clear them */ status_reg_value = inl(tw_dev->registers.status_reg_addr); if (TW_STATUS_ERRORS(status_reg_value)) tw_decode_bits(tw_dev, status_reg_value, 0); /* Poll status register for 60 secs for 'Controller Ready' flag */ if (tw_poll_status(tw_dev, TW_STATUS_MICROCONTROLLER_READY, 60)) { printk(KERN_WARNING "3w-xxxx: tw_findcards(): Microcontroller not ready for card %d.\n", j); tw_free_device_extension(tw_dev); kfree(tw_dev); continue; } /* Disable interrupts on the card */ tw_disable_interrupts(tw_dev); tries = 0; while (tries < TW_MAX_RESET_TRIES) { /* Do soft reset */ tw_soft_reset(tw_dev); error = tw_aen_drain_queue(tw_dev); if (error) { printk(KERN_WARNING "3w-xxxx: AEN drain failed for card %d.\n", j); tries++; continue; } /* Check for controller errors */ if (tw_check_errors(tw_dev)) { printk(KERN_WARNING "3w-xxxx: Controller errors found, retrying for card %d.\n", j); tries++; continue; } /* Now the controller is in a good state */ break; } if (tries >= TW_MAX_RESET_TRIES) { printk(KERN_WARNING "3w-xxxx: Controller errors, card not responding, check all cabling for card %d.\n", j); tw_free_device_extension(tw_dev); kfree(tw_dev); continue; } /* Reserve the io address space */ if (!request_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE, TW_DEVICE_NAME)) { printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't get io range 0x%lx-0x%lx for card %d.\n", (tw_dev->tw_pci_dev->resource[0].start), (tw_dev->tw_pci_dev->resource[0].start) + TW_IO_ADDRESS_RANGE, j); tw_free_device_extension(tw_dev); kfree(tw_dev); continue; } error = tw_initialize_units(tw_dev); if (error) { printk(KERN_WARNING "3w-xxxx: No valid units for for card %d.\n", j); } error = tw_initconnection(tw_dev, TW_INIT_MESSAGE_CREDITS); if (error) { printk(KERN_WARNING "3w-xxxx: Connection initialization failed for card %d.\n", j); release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE); tw_free_device_extension(tw_dev); kfree(tw_dev); continue; } /* Set card status as online */ tw_dev->online = 1; tw_dev->free_head = TW_Q_START; tw_dev->free_tail = TW_Q_START; tw_dev->free_wrap = TW_Q_LENGTH - 1; /* Register the card with the kernel SCSI layer */ host = scsi_register(tw_host, sizeof(TW_Device_Extension)); if (host == NULL) { printk(KERN_WARNING "3w-xxxx: tw_findcards(): scsi_register() failed for card %d.\n", j); release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE); tw_free_device_extension(tw_dev); kfree(tw_dev); continue; } /* Set max target id's */ host->max_id = TW_MAX_UNITS; /* Set max cdb size in bytes */ host->max_cmd_len = 16; /* Set max sectors per io */#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,7) host->max_sectors = TW_MAX_SECTORS;#endif#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) scsi_set_device(host, &tw_pci_dev->dev);#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,4) scsi_set_pci_device(host, tw_pci_dev);#endif status_reg_value = inl(tw_dev->registers.status_reg_addr); printk(KERN_NOTICE "scsi%d : Found a 3ware Storage Controller at 0x%x, IRQ: %d, P-chip: %d.%d\n", host->host_no, (u32)(tw_pci_dev->resource[0].start), tw_pci_dev->irq, (status_reg_value & TW_STATUS_MAJOR_VERSION_MASK) >> 28, (status_reg_value & TW_STATUS_MINOR_VERSION_MASK) >> 24); if (host->hostdata) { tw_dev2 = (TW_Device_Extension *)host->hostdata; memcpy(tw_dev2, tw_dev, sizeof(TW_Device_Extension)); /* Need to init the sem/wqueue after the copy */ init_MUTEX(&tw_dev2->ioctl_sem); init_waitqueue_head(&tw_dev2->ioctl_wqueue); tw_device_extension_list[tw_device_extension_count] = tw_dev2; numcards++; tw_device_extension_count = numcards; tw_dev2->host = host; } else { printk(KERN_WARNING "3w-xxxx: tw_findcards(): Bad scsi host data for card %d.\n", j); scsi_unregister(host); release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE); tw_free_device_extension(tw_dev); kfree(tw_dev); continue; } /* Tell the firmware we support shutdown notification*/ error = tw_setfeature(tw_dev2, 2, 1, &c); if (error) { printk(KERN_WARNING "3w-xxxx: Unable to set features for card %d, old firmware or card.\n", j); } /* Now setup the interrupt handler */ error = tw_setup_irq(tw_dev2); if (error) { printk(KERN_WARNING "3w-xxxx: tw_findcards(): Error requesting irq for card %d.\n", j); scsi_unregister(host); release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE); tw_free_device_extension(tw_dev); kfree(tw_dev); numcards--; continue; } /* Re-enable interrupts on the card */ tw_enable_interrupts(tw_dev2); /* Free the temporary device extension */ if (tw_dev) kfree(tw_dev); } } if (numcards == 0) { printk(KERN_WARNING "3w-xxxx: No cards found.\n"); } else { register_reboot_notifier(&tw_notifier); if ((twe_major = register_chrdev (0, "twe", &tw_fops)) < 0) { printk(KERN_WARNING "3w-xxxx: Unable to register \"twe\" character device, error = %d.\n", twe_major); } } return numcards;} /* End tw_findcards() *//* This function will free up device extension resources */void tw_free_device_extension(TW_Device_Extension *tw_dev){ dprintk(KERN_NOTICE "3w-xxxx: tw_free_device_extension()\n"); /* Free command packet and generic buffer memory */ if (tw_dev->command_packet_virtual_address[0]) pci_free_consistent(tw_dev->tw_pci_dev, sizeof(TW_Command)*TW_Q_LENGTH, tw_dev->command_packet_virtual_address[0], tw_dev->command_packet_physical_address[0]); if (tw_dev->alignment_virtual_address[0]) pci_free_consistent(tw_dev->tw_pci_dev, sizeof(TW_Sector)*TW_Q_LENGTH, tw_dev->alignment_virtual_address[0], tw_dev->alignment_physical_address[0]);} /* 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++) { if (tw_device_extension_list[i]->online == 1) { printk(KERN_NOTICE "3w-xxxx: Shutting down card %d.\n", i); tw_shutdown_device(tw_device_extension_list[i]); tw_device_extension_list[i]->online = 0; } } 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) { unsigned long command_que_value; u32 command_que_addr; u32 response_que_addr; TW_Command *command_packet; TW_Response_Queue response_queue; int request_id = 0; dprintk(KERN_NOTICE "3w-xxxx: tw_initconnection()\n"); command_que_addr = tw_dev->registers.command_que_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 */ if (tw_poll_status_gone(tw_dev, TW_STATUS_RESPONSE_QUEUE_EMPTY, 30) == 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 */ tw_decode_sense(tw_dev, request_id, 0); return 1; } } 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, error=0; dprintk(KERN_NOTICE "3w-xxxx: tw_initialize_device_extension()\n"); /* Initialize command packet buffers */ error = tw_allocate_memory(tw_dev, sizeof(TW_Command), 0); if (error) { printk(KERN_WARNING "3w-xxxx: Command packet memory allocation failed.\n"); return 1; } /* Initialize generic buffer */ error = tw_allocate_memory(tw_dev, sizeof(TW_Sector), 1); if (error) { printk(KERN_WARNING "3w-xxxx: Generic memory allocation failed.\n"); return 1; } for (i=0;i<TW_Q_LENGTH;i++) { tw_dev->free_queue[i] = i; tw_dev->state[i] = TW_S_INITIAL; } tw_dev->pending_head = TW_Q_START; tw_dev->pending_tail = TW_Q_START; spin_lock_init(&tw_dev->tw_lock); tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE; 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; unsigned long command_que_value; u32 command_que_addr; u32 response_que_addr; TW_Response_Queue response_queue; unsigned long param_value; unsigned char *is_unit_present; dprintk(KERN_NOTICE "3w-xxxx: tw_initialize_units()\n"); 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);
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -