3w-9xxx.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,986 行 · 第 1/5 页
C
1,986 行
tw_dev->aen_count--; if ((tw_dev->error_index + 1) == TW_Q_LENGTH) tw_dev->event_queue_wrapped = 1; tw_dev->error_index = (tw_dev->error_index + 1 ) % TW_Q_LENGTH;} /* End twa_aen_queue_event() *//* This function will read the aen queue from the isr */static int twa_aen_read_queue(TW_Device_Extension *tw_dev, int request_id){ char cdb[TW_MAX_CDB_LEN]; TW_SG_Apache sglist[1]; TW_Command_Full *full_command_packet; int retval = 1; full_command_packet = tw_dev->command_packet_virt[request_id]; memset(full_command_packet, 0, sizeof(TW_Command_Full)); /* Initialize cdb */ memset(&cdb, 0, TW_MAX_CDB_LEN); cdb[0] = REQUEST_SENSE; /* opcode */ cdb[4] = TW_ALLOCATION_LENGTH; /* allocation length */ /* Initialize sglist */ memset(&sglist, 0, sizeof(TW_SG_Apache)); sglist[0].length = TW_SECTOR_SIZE; sglist[0].address = tw_dev->generic_buffer_phys[request_id]; /* Mark internal command */ tw_dev->srb[request_id] = NULL; /* Now post the command packet */ if (twa_scsiop_execute_scsi(tw_dev, request_id, cdb, 1, sglist)) { TW_PRINTK(tw_dev->host, TW_DRIVER, 0x4, "Post failed while reading AEN queue"); goto out; } retval = 0;out: return retval;} /* End twa_aen_read_queue() *//* This function will look up an AEN severity string */static char *twa_aen_severity_lookup(unsigned char severity_code){ char *retval = NULL; if ((severity_code < (unsigned char) TW_AEN_SEVERITY_ERROR) || (severity_code > (unsigned char) TW_AEN_SEVERITY_DEBUG)) goto out; retval = twa_aen_severity_table[severity_code];out: return retval;} /* End twa_aen_severity_lookup() *//* This function will sync firmware time with the host time */static void twa_aen_sync_time(TW_Device_Extension *tw_dev, int request_id){ u32 schedulertime; struct timeval utc; TW_Command_Full *full_command_packet; TW_Command *command_packet; TW_Param_Apache *param; u32 local_time; /* Fill out 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_SET_PARAM); command_packet->request_id = request_id; command_packet->byte8_offset.param.sgl[0].address = tw_dev->generic_buffer_phys[request_id]; command_packet->byte8_offset.param.sgl[0].length = TW_SECTOR_SIZE; command_packet->size = TW_COMMAND_SIZE; command_packet->byte6_offset.parameter_count = 1; /* Setup the param */ param = (TW_Param_Apache *)tw_dev->generic_buffer_virt[request_id]; memset(param, 0, TW_SECTOR_SIZE); param->table_id = TW_TIMEKEEP_TABLE | 0x8000; /* Controller time keep table */ param->parameter_id = 0x3; /* SchedulerTime */ param->parameter_size_bytes = 4; /* Convert system time in UTC to local time seconds since last Sunday 12:00AM */ do_gettimeofday(&utc); local_time = (u32)(utc.tv_sec - (sys_tz.tz_minuteswest * 60)); schedulertime = local_time - (3 * 86400); schedulertime = schedulertime % 604800; memcpy(param->data, &schedulertime, sizeof(u32)); /* Mark internal command */ tw_dev->srb[request_id] = NULL; /* Now post the command */ twa_post_command_packet(tw_dev, request_id, 1);} /* End twa_aen_sync_time() *//* This function will allocate memory and check if it is correctly aligned */static int twa_allocate_memory(TW_Device_Extension *tw_dev, int size, int which){ int i; dma_addr_t dma_handle; unsigned long *cpu_addr; int retval = 1; cpu_addr = pci_alloc_consistent(tw_dev->tw_pci_dev, size*TW_Q_LENGTH, &dma_handle); if (!cpu_addr) { TW_PRINTK(tw_dev->host, TW_DRIVER, 0x5, "Memory allocation failed"); goto out; } if ((unsigned long)cpu_addr % (TW_ALIGNMENT_9000)) { TW_PRINTK(tw_dev->host, TW_DRIVER, 0x6, "Failed to allocate correctly aligned memory"); pci_free_consistent(tw_dev->tw_pci_dev, size*TW_Q_LENGTH, cpu_addr, dma_handle); goto out; } memset(cpu_addr, 0, size*TW_Q_LENGTH); for (i = 0; i < TW_Q_LENGTH; i++) { switch(which) { case 0: tw_dev->command_packet_phys[i] = dma_handle+(i*size); tw_dev->command_packet_virt[i] = (TW_Command_Full *)((unsigned char *)cpu_addr + (i*size)); break; case 1: tw_dev->generic_buffer_phys[i] = dma_handle+(i*size); tw_dev->generic_buffer_virt[i] = (unsigned long *)((unsigned char *)cpu_addr + (i*size)); break; } } retval = 0;out: return retval;} /* End twa_allocate_memory() *//* This function will check the status register for unexpected bits */static int twa_check_bits(u32 status_reg_value){ int retval = 1; if ((status_reg_value & TW_STATUS_EXPECTED_BITS) != TW_STATUS_EXPECTED_BITS) goto out; if ((status_reg_value & TW_STATUS_UNEXPECTED_BITS) != 0) goto out; retval = 0;out: return retval;} /* End twa_check_bits() *//* This function will check the srl and decide if we are compatible */static int twa_check_srl(TW_Device_Extension *tw_dev, int *flashed){ int retval = 1; unsigned short fw_on_ctlr_srl = 0, fw_on_ctlr_arch_id = 0; unsigned short fw_on_ctlr_branch = 0, fw_on_ctlr_build = 0; u32 init_connect_result = 0; if (twa_initconnection(tw_dev, TW_INIT_MESSAGE_CREDITS, TW_EXTENDED_INIT_CONNECT, TW_CURRENT_FW_SRL, TW_9000_ARCH_ID, TW_CURRENT_FW_BRANCH, TW_CURRENT_FW_BUILD, &fw_on_ctlr_srl, &fw_on_ctlr_arch_id, &fw_on_ctlr_branch, &fw_on_ctlr_build, &init_connect_result)) { TW_PRINTK(tw_dev->host, TW_DRIVER, 0x7, "Initconnection failed while checking SRL"); goto out; } tw_dev->working_srl = TW_CURRENT_FW_SRL; tw_dev->working_branch = TW_CURRENT_FW_BRANCH; tw_dev->working_build = TW_CURRENT_FW_BUILD; /* Try base mode compatibility */ if (!(init_connect_result & TW_CTLR_FW_COMPATIBLE)) { if (twa_initconnection(tw_dev, TW_INIT_MESSAGE_CREDITS, TW_EXTENDED_INIT_CONNECT, TW_BASE_FW_SRL, TW_9000_ARCH_ID, TW_BASE_FW_BRANCH, TW_BASE_FW_BUILD, &fw_on_ctlr_srl, &fw_on_ctlr_arch_id, &fw_on_ctlr_branch, &fw_on_ctlr_build, &init_connect_result)) { TW_PRINTK(tw_dev->host, TW_DRIVER, 0xa, "Initconnection (base mode) failed while checking SRL"); goto out; } if (!(init_connect_result & TW_CTLR_FW_COMPATIBLE)) { if (TW_CURRENT_FW_SRL > fw_on_ctlr_srl) { TW_PRINTK(tw_dev->host, TW_DRIVER, 0x32, "Firmware and driver incompatibility: please upgrade firmware"); } else { TW_PRINTK(tw_dev->host, TW_DRIVER, 0x33, "Firmware and driver incompatibility: please upgrade driver"); } goto out; } tw_dev->working_srl = TW_BASE_FW_SRL; tw_dev->working_branch = TW_BASE_FW_BRANCH; tw_dev->working_build = TW_BASE_FW_BUILD; } retval = 0;out: return retval;} /* End twa_check_srl() *//* This function handles ioctl for the character device */static int twa_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ long timeout; unsigned long *cpu_addr, data_buffer_length_adjusted = 0, flags = 0; dma_addr_t dma_handle; int request_id = 0; unsigned int sequence_id = 0; unsigned char event_index, start_index; TW_Ioctl_Driver_Command driver_command; TW_Ioctl_Buf_Apache *tw_ioctl; TW_Lock *tw_lock; TW_Command_Full *full_command_packet; TW_Compatibility_Info *tw_compat_info; TW_Event *event; struct timeval current_time; u32 current_time_ms; TW_Device_Extension *tw_dev = twa_device_extension_list[iminor(inode)]; int retval = TW_IOCTL_ERROR_OS_EFAULT; void __user *argp = (void __user *)arg; /* Only let one of these through at a time */ if (down_interruptible(&tw_dev->ioctl_sem)) { retval = TW_IOCTL_ERROR_OS_EINTR; goto out; } /* First copy down the driver command */ if (copy_from_user(&driver_command, argp, sizeof(TW_Ioctl_Driver_Command))) goto out2; /* Check data buffer size */ if (driver_command.buffer_length > TW_MAX_SECTORS * 512) { retval = TW_IOCTL_ERROR_OS_EINVAL; goto out2; } /* Hardware can only do multiple of 512 byte transfers */ data_buffer_length_adjusted = (driver_command.buffer_length + 511) & ~511; /* Now allocate ioctl buf memory */ cpu_addr = pci_alloc_consistent(tw_dev->tw_pci_dev, data_buffer_length_adjusted+sizeof(TW_Ioctl_Buf_Apache) - 1, &dma_handle); if (!cpu_addr) { retval = TW_IOCTL_ERROR_OS_ENOMEM; goto out2; } tw_ioctl = (TW_Ioctl_Buf_Apache *)cpu_addr; /* Now copy down the entire ioctl */ if (copy_from_user(tw_ioctl, argp, driver_command.buffer_length + sizeof(TW_Ioctl_Buf_Apache) - 1)) goto out3; /* See which ioctl we are doing */ switch (cmd) { case TW_IOCTL_FIRMWARE_PASS_THROUGH: spin_lock_irqsave(tw_dev->host->host_lock, flags); twa_get_request_id(tw_dev, &request_id); /* Flag internal command */ tw_dev->srb[request_id] = NULL; /* Flag chrdev ioctl */ tw_dev->chrdev_request_id = request_id; full_command_packet = &tw_ioctl->firmware_command; /* Load request id and sglist for both command types */ twa_load_sgl(full_command_packet, request_id, dma_handle, data_buffer_length_adjusted); memcpy(tw_dev->command_packet_virt[request_id], &(tw_ioctl->firmware_command), sizeof(TW_Command_Full)); /* Now post the command packet to the controller */ twa_post_command_packet(tw_dev, request_id, 1); spin_unlock_irqrestore(tw_dev->host->host_lock, flags); timeout = TW_IOCTL_CHRDEV_TIMEOUT*HZ; /* Now wait for command to complete */ timeout = wait_event_interruptible_timeout(tw_dev->ioctl_wqueue, tw_dev->chrdev_request_id == TW_IOCTL_CHRDEV_FREE, timeout); /* Check if we timed out, got a signal, or didn't get an interrupt */ if ((timeout <= 0) && (tw_dev->chrdev_request_id != TW_IOCTL_CHRDEV_FREE)) { /* Now we need to reset the board */ if (timeout == TW_IOCTL_ERROR_OS_ERESTARTSYS) { retval = timeout; } else { printk(KERN_WARNING "3w-9xxx: scsi%d: WARNING: (0x%02X:0x%04X): Character ioctl (0x%x) timed out, resetting card.\n", tw_dev->host->host_no, TW_DRIVER, 0xc, cmd); retval = TW_IOCTL_ERROR_OS_EIO; } spin_lock_irqsave(tw_dev->host->host_lock, flags); tw_dev->state[request_id] = TW_S_COMPLETED; twa_free_request_id(tw_dev, request_id); tw_dev->posted_request_count--; twa_reset_device_extension(tw_dev); spin_unlock_irqrestore(tw_dev->host->host_lock, flags); goto out3; } /* Now copy in the command packet response */ memcpy(&(tw_ioctl->firmware_command), tw_dev->command_packet_virt[request_id], sizeof(TW_Command_Full)); /* Now complete the io */ spin_lock_irqsave(tw_dev->host->host_lock, flags); tw_dev->posted_request_count--; tw_dev->state[request_id] = TW_S_COMPLETED; twa_free_request_id(tw_dev, request_id); spin_unlock_irqrestore(tw_dev->host->host_lock, flags); break; case TW_IOCTL_GET_COMPATIBILITY_INFO: tw_ioctl->driver_command.status = 0; /* Copy compatiblity struct into ioctl data buffer */ tw_compat_info = (TW_Compatibility_Info *)tw_ioctl->data_buffer; strncpy(tw_compat_info->driver_version, twa_driver_version, strlen(twa_driver_version)); tw_compat_info->working_srl = tw_dev->working_srl; tw_compat_info->working_branch = tw_dev->working_branch; tw_compat_info->working_build = tw_dev->working_build; break; case TW_IOCTL_GET_LAST_EVENT: if (tw_dev->event_queue_wrapped) { if (tw_dev->aen_clobber) { tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_AEN_CLOBBER; tw_dev->aen_clobber = 0; } else tw_ioctl->driver_command.status = 0; } else { if (!tw_dev->error_index) { tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NO_MORE_EVENTS; break; } tw_ioctl->driver_command.status = 0; } event_index = (tw_dev->error_index - 1 + TW_Q_LENGTH) % TW_Q_LENGTH; 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_FIRST_EVENT: if (tw_dev->event_queue_wrapped) { if (tw_dev->aen_clobber) { tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_AEN_CLOBBER; tw_dev->aen_clobber = 0; } else tw_ioctl->driver_command.status = 0; event_index = tw_dev->error_index; } else { if (!tw_dev->error_index) { tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NO_MORE_EVENTS; break; } tw_ioctl->driver_command.status = 0; event_index = 0; } 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_NEXT_EVENT: event = (TW_Event *)tw_ioctl->data_buffer; sequence_id = event->sequence_id; tw_ioctl->driver_command.status = 0; if (tw_dev->event_queue_wrapped) { if (tw_dev->aen_clobber) { 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_PREVIOUS_EVENT: event = (TW_Event *)tw_ioctl->data_buffer; sequence_id = event->sequence_id; tw_ioctl->driver_command.status = 0; if (tw_dev->event_queue_wrapped) { if (tw_dev->aen_clobber) {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?