3w-9xxx.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,986 行 · 第 1/5 页
C
1,986 行
tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_AEN_CLOBBER; tw_dev->aen_clobber = 0; } start_index = tw_dev->error_index; } else { if (!tw_dev->error_index) { tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NO_MORE_EVENTS; break; } start_index = 0; } event_index = (start_index + sequence_id - tw_dev->event_queue[start_index]->sequence_id - 1) % TW_Q_LENGTH; if (!(tw_dev->event_queue[event_index]->sequence_id < sequence_id)) { if (tw_ioctl->driver_command.status == TW_IOCTL_ERROR_STATUS_AEN_CLOBBER) tw_dev->aen_clobber = 1; tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NO_MORE_EVENTS; break; } memcpy(tw_ioctl->data_buffer, tw_dev->event_queue[event_index], sizeof(TW_Event)); tw_dev->event_queue[event_index]->retrieved = TW_AEN_RETRIEVED; break; case TW_IOCTL_GET_LOCK: tw_lock = (TW_Lock *)tw_ioctl->data_buffer; do_gettimeofday(¤t_time); current_time_ms = (current_time.tv_sec * 1000) + (current_time.tv_usec / 1000); if ((tw_lock->force_flag == 1) || (tw_dev->ioctl_sem_lock == 0) || (current_time_ms >= tw_dev->ioctl_msec)) { tw_dev->ioctl_sem_lock = 1; tw_dev->ioctl_msec = current_time_ms + tw_lock->timeout_msec; tw_ioctl->driver_command.status = 0; tw_lock->time_remaining_msec = tw_lock->timeout_msec; } else { tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_LOCKED; tw_lock->time_remaining_msec = tw_dev->ioctl_msec - current_time_ms; } break; case TW_IOCTL_RELEASE_LOCK: if (tw_dev->ioctl_sem_lock == 1) { tw_dev->ioctl_sem_lock = 0; tw_ioctl->driver_command.status = 0; } else { tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NOT_LOCKED; } break; default: retval = TW_IOCTL_ERROR_OS_ENOTTY; goto out3; } /* Now copy the entire response to userspace */ if (copy_to_user(argp, tw_ioctl, sizeof(TW_Ioctl_Buf_Apache) + driver_command.buffer_length - 1) == 0) retval = 0;out3: /* Now free ioctl buf memory */ pci_free_consistent(tw_dev->tw_pci_dev, data_buffer_length_adjusted+sizeof(TW_Ioctl_Buf_Apache) - 1, cpu_addr, dma_handle);out2: up(&tw_dev->ioctl_sem);out: return retval;} /* End twa_chrdev_ioctl() *//* This function handles open for the character device */static int twa_chrdev_open(struct inode *inode, struct file *file){ unsigned int minor_number; int retval = TW_IOCTL_ERROR_OS_ENODEV; minor_number = iminor(inode); if (minor_number >= twa_device_extension_count) goto out; retval = 0;out: return retval;} /* End twa_chrdev_open() *//* This function will print readable messages from status register errors */static int twa_decode_bits(TW_Device_Extension *tw_dev, u32 status_reg_value){ int retval = 1; /* Check for various error conditions and handle them appropriately */ if (status_reg_value & TW_STATUS_PCI_PARITY_ERROR) { TW_PRINTK(tw_dev->host, TW_DRIVER, 0xc, "PCI Parity Error: clearing"); writel(TW_CONTROL_CLEAR_PARITY_ERROR, TW_CONTROL_REG_ADDR(tw_dev)); } if (status_reg_value & TW_STATUS_PCI_ABORT) { TW_PRINTK(tw_dev->host, TW_DRIVER, 0xd, "PCI Abort: clearing"); writel(TW_CONTROL_CLEAR_PCI_ABORT, TW_CONTROL_REG_ADDR(tw_dev)); pci_write_config_word(tw_dev->tw_pci_dev, PCI_STATUS, TW_PCI_CLEAR_PCI_ABORT); } if (status_reg_value & TW_STATUS_QUEUE_ERROR) { TW_PRINTK(tw_dev->host, TW_DRIVER, 0xe, "Controller Queue Error: clearing"); writel(TW_CONTROL_CLEAR_QUEUE_ERROR, TW_CONTROL_REG_ADDR(tw_dev)); } if (status_reg_value & TW_STATUS_SBUF_WRITE_ERROR) { TW_PRINTK(tw_dev->host, TW_DRIVER, 0xf, "SBUF Write Error: clearing"); writel(TW_CONTROL_CLEAR_SBUF_WRITE_ERROR, TW_CONTROL_REG_ADDR(tw_dev)); } if (status_reg_value & TW_STATUS_MICROCONTROLLER_ERROR) { if (tw_dev->reset_print == 0) { TW_PRINTK(tw_dev->host, TW_DRIVER, 0x10, "Microcontroller Error: clearing"); tw_dev->reset_print = 1; } goto out; } retval = 0;out: return retval;} /* End twa_decode_bits() *//* This function will empty the response queue */static int twa_empty_response_queue(TW_Device_Extension *tw_dev){ u32 status_reg_value, response_que_value; int count = 0, retval = 1; status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev)); while (((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) && (count < TW_MAX_RESPONSE_DRAIN)) { response_que_value = readl(TW_RESPONSE_QUEUE_REG_ADDR(tw_dev)); status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev)); count++; } if (count == TW_MAX_RESPONSE_DRAIN) goto out; retval = 0;out: return retval;} /* End twa_empty_response_queue() *//* This function passes sense keys from firmware to scsi layer */static int twa_fill_sense(TW_Device_Extension *tw_dev, int request_id, int copy_sense, int print_host){ TW_Command_Full *full_command_packet; unsigned short error; int retval = 1; full_command_packet = tw_dev->command_packet_virt[request_id]; /* Don't print error for Logical unit not supported during rollcall */ error = full_command_packet->header.status_block.error; if ((error != TW_ERROR_LOGICAL_UNIT_NOT_SUPPORTED) && (error != TW_ERROR_UNIT_OFFLINE)) { if (print_host) printk(KERN_WARNING "3w-9xxx: scsi%d: ERROR: (0x%02X:0x%04X): %s:%s.\n", tw_dev->host->host_no, TW_MESSAGE_SOURCE_CONTROLLER_ERROR, full_command_packet->header.status_block.error, twa_string_lookup(twa_error_table, full_command_packet->header.status_block.error), full_command_packet->header.err_specific_desc); else printk(KERN_WARNING "3w-9xxx: ERROR: (0x%02X:0x%04X): %s:%s.\n", TW_MESSAGE_SOURCE_CONTROLLER_ERROR, full_command_packet->header.status_block.error, twa_string_lookup(twa_error_table, full_command_packet->header.status_block.error), full_command_packet->header.err_specific_desc); } if (copy_sense) { memcpy(tw_dev->srb[request_id]->sense_buffer, full_command_packet->header.sense_data, TW_SENSE_DATA_LENGTH); tw_dev->srb[request_id]->result = (full_command_packet->command.newcommand.status << 1); retval = TW_ISR_DONT_RESULT; goto out; } retval = 0;out: return retval;} /* End twa_fill_sense() *//* This function will free up device extension resources */static void twa_free_device_extension(TW_Device_Extension *tw_dev){ if (tw_dev->command_packet_virt[0]) pci_free_consistent(tw_dev->tw_pci_dev, sizeof(TW_Command_Full)*TW_Q_LENGTH, tw_dev->command_packet_virt[0], tw_dev->command_packet_phys[0]); if (tw_dev->generic_buffer_virt[0]) pci_free_consistent(tw_dev->tw_pci_dev, TW_SECTOR_SIZE*TW_Q_LENGTH, tw_dev->generic_buffer_virt[0], tw_dev->generic_buffer_phys[0]); if (tw_dev->event_queue[0]) kfree(tw_dev->event_queue[0]);} /* End twa_free_device_extension() *//* This function will free a request id */static void twa_free_request_id(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 twa_free_request_id() *//* This function will get parameter table entires from the firmware */static void *twa_get_param(TW_Device_Extension *tw_dev, int request_id, int table_id, int parameter_id, int parameter_size_bytes){ TW_Command_Full *full_command_packet; TW_Command *command_packet; TW_Param_Apache *param; unsigned long param_value; void *retval = NULL; /* Setup the command packet */ full_command_packet = tw_dev->command_packet_virt[request_id]; memset(full_command_packet, 0, sizeof(TW_Command_Full)); command_packet = &full_command_packet->command.oldcommand; command_packet->opcode__sgloffset = TW_OPSGL_IN(2, TW_OP_GET_PARAM); command_packet->size = TW_COMMAND_SIZE; command_packet->request_id = request_id; command_packet->byte6_offset.block_count = 1; /* Now setup the param */ param = (TW_Param_Apache *)tw_dev->generic_buffer_virt[request_id]; memset(param, 0, TW_SECTOR_SIZE); param->table_id = table_id | 0x8000; param->parameter_id = parameter_id; param->parameter_size_bytes = parameter_size_bytes; param_value = tw_dev->generic_buffer_phys[request_id]; command_packet->byte8_offset.param.sgl[0].address = param_value; command_packet->byte8_offset.param.sgl[0].length = TW_SECTOR_SIZE; /* Post the command packet to the board */ twa_post_command_packet(tw_dev, request_id, 1); /* Poll for completion */ if (twa_poll_response(tw_dev, request_id, 30)) TW_PRINTK(tw_dev->host, TW_DRIVER, 0x13, "No valid response during get param") else retval = (void *)&(param->data[0]); tw_dev->posted_request_count--; tw_dev->state[request_id] = TW_S_INITIAL; return retval;} /* End twa_get_param() *//* This function will assign an available request id */static void twa_get_request_id(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 twa_get_request_id() *//* This function will send an initconnection command to controller */static int twa_initconnection(TW_Device_Extension *tw_dev, int message_credits, u32 set_features, unsigned short current_fw_srl, unsigned short current_fw_arch_id, unsigned short current_fw_branch, unsigned short current_fw_build, unsigned short *fw_on_ctlr_srl, unsigned short *fw_on_ctlr_arch_id, unsigned short *fw_on_ctlr_branch, unsigned short *fw_on_ctlr_build, u32 *init_connect_result){ TW_Command_Full *full_command_packet; TW_Initconnect *tw_initconnect; int request_id = 0, retval = 1; /* Initialize InitConnection command packet */ full_command_packet = tw_dev->command_packet_virt[request_id]; memset(full_command_packet, 0, sizeof(TW_Command_Full)); full_command_packet->header.header_desc.size_header = 128; tw_initconnect = (TW_Initconnect *)&full_command_packet->command.oldcommand; tw_initconnect->opcode__reserved = TW_OPRES_IN(0, TW_OP_INIT_CONNECTION); tw_initconnect->request_id = request_id; tw_initconnect->message_credits = message_credits; tw_initconnect->features = set_features;#if BITS_PER_LONG > 32 /* Turn on 64-bit sgl support */ tw_initconnect->features |= 1;#endif if (set_features & TW_EXTENDED_INIT_CONNECT) { tw_initconnect->size = TW_INIT_COMMAND_PACKET_SIZE_EXTENDED; tw_initconnect->fw_srl = current_fw_srl; tw_initconnect->fw_arch_id = current_fw_arch_id; tw_initconnect->fw_branch = current_fw_branch; tw_initconnect->fw_build = current_fw_build; } else tw_initconnect->size = TW_INIT_COMMAND_PACKET_SIZE; /* Send command packet to the board */ twa_post_command_packet(tw_dev, request_id, 1); /* Poll for completion */ if (twa_poll_response(tw_dev, request_id, 30)) { TW_PRINTK(tw_dev->host, TW_DRIVER, 0x15, "No valid response during init connection"); } else { if (set_features & TW_EXTENDED_INIT_CONNECT) { *fw_on_ctlr_srl = tw_initconnect->fw_srl; *fw_on_ctlr_arch_id = tw_initconnect->fw_arch_id; *fw_on_ctlr_branch = tw_initconnect->fw_branch; *fw_on_ctlr_build = tw_initconnect->fw_build; *init_connect_result = tw_initconnect->result; } retval = 0; } tw_dev->posted_request_count--; tw_dev->state[request_id] = TW_S_INITIAL; return retval;} /* End twa_initconnection() *//* This function will initialize the fields of a device extension */static int twa_initialize_device_extension(TW_Device_Extension *tw_dev){ int i, retval = 1; /* Initialize command packet buffers */ if (twa_allocate_memory(tw_dev, sizeof(TW_Command_Full), 0)) { TW_PRINTK(tw_dev->host, TW_DRIVER, 0x16, "Command packet memory allocation failed"); goto out; } /* Initialize generic buffer */ if (twa_allocate_memory(tw_dev, TW_SECTOR_SIZE, 1)) { TW_PRINTK(tw_dev->host, TW_DRIVER, 0x17, "Generic memory allocation failed"); goto out; } /* Allocate event info space */ tw_dev->event_queue[0] = kmalloc(sizeof(TW_Event) * TW_Q_LENGTH, GFP_KERNEL); if (!tw_dev->event_queue[0]) { TW_PRINTK(tw_dev->host, TW_DRIVER, 0x18, "Event info memory allocation failed"); goto out; } memset(tw_dev->event_queue[0], 0, sizeof(TW_Event) * TW_Q_LENGTH); for (i = 0; i < TW_Q_LENGTH; i++) { tw_dev->event_queue[i] = (TW_Event *)((unsigned char *)tw_dev->event_queue[0] + (i * sizeof(TW_Event))); 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; tw_dev->free_head = TW_Q_START; tw_dev->free_tail = TW_Q_START; tw_dev->error_sequence_id = 1; tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE; init_MUTEX(&tw_dev->ioctl_sem); init_waitqueue_head(&tw_dev->ioctl_wqueue); retval = 0;out: return retval;} /* End twa_initialize_device_extension() *//* This function is the interrupt service routine */static irqreturn_t twa_interrupt(int irq, void *dev_instance, struct pt_regs *regs){ int request_id, error = 0; u32 status_reg_value; TW_Response_Queue response_que; TW_Command_Full *full_command_packet; TW_Command *command_packet; TW_Device_Extension *tw_dev = (TW_Device_Extension *)dev_instance; int handled = 0; /* Get the per adapter lock */ spin_lock(tw_dev->host->host_lock); /* See if the interrupt matches this instance */ if (tw_dev->tw_pci_dev->irq == (unsigned int)irq) { handled = 1; /* Read the registers */ status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev)); /* Check if this is our interrupt, otherwise bail */ if (!(status_reg_value & TW_STATUS_VALID_INTERRUPT)) goto twa_interrupt_bail; /* Check controller for errors */ if (twa_check_bits(status_reg_value)) { if (twa_decode_bits(tw_dev, status_reg_value)) { TW_CLEAR_ALL_INTERRUPTS(tw_dev); goto twa_interrupt_bail; } }
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?