?? 3w-xxxx.c
字號:
tw_dev->srb[request_id] = NULL; /* Flag chrdev ioctl */ tw_dev->chrdev_request_id = request_id; tw_ioctl->firmware_command.request_id = request_id; /* Load the sg list */ switch (tw_ioctl->firmware_command.byte0.sgl_offset) { case 2: tw_ioctl->firmware_command.byte8.param.sgl[0].address = dma_handle + sizeof(TW_New_Ioctl) - 1; tw_ioctl->firmware_command.byte8.param.sgl[0].length = data_buffer_length_adjusted; break; case 3: tw_ioctl->firmware_command.byte8.io.sgl[0].address = dma_handle + sizeof(TW_New_Ioctl) - 1; tw_ioctl->firmware_command.byte8.io.sgl[0].length = data_buffer_length_adjusted; break; case 5: passthru->sg_list[0].address = dma_handle + sizeof(TW_New_Ioctl) - 1; passthru->sg_list[0].length = data_buffer_length_adjusted; break; } memcpy(tw_dev->command_packet_virtual_address[request_id], &(tw_ioctl->firmware_command), sizeof(TW_Command)); /* Now post the command packet to the controller */ tw_post_command_packet(tw_dev, request_id); spin_unlock_irqrestore(&tw_dev->tw_lock, flags); timeout = TW_IOCTL_CHRDEV_TIMEOUT*HZ; /* Now wait for the 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 == -ERESTARTSYS) { retval = timeout; } else { printk(KERN_WARNING "3w-xxxx: scsi%d: Character ioctl (0x%x) timed out, resetting card.\n", tw_dev->host->host_no, cmd); retval = -EIO; } spin_lock_irqsave(&tw_dev->tw_lock, flags); tw_dev->state[request_id] = TW_S_COMPLETED; tw_state_request_finish(tw_dev, request_id); tw_dev->posted_request_count--; if (tw_reset_device_extension(tw_dev)) { printk(KERN_WARNING "3w-xxxx: tw_chrdev_ioctl(): Reset failed for card %d.\n", tw_dev->host->host_no); } spin_unlock_irqrestore(&tw_dev->tw_lock, flags); goto out2; } /* Now copy in the command packet response */ memcpy(&(tw_ioctl->firmware_command), tw_dev->command_packet_virtual_address[request_id], sizeof(TW_Command)); /* Now complete the io */ spin_lock_irqsave(&tw_dev->tw_lock, flags); tw_dev->posted_request_count--; tw_dev->state[request_id] = TW_S_COMPLETED; tw_state_request_finish(tw_dev, request_id); spin_unlock_irqrestore(&tw_dev->tw_lock, flags); break; default: retval = -ENOTTY; goto out2; } /* Now copy the response to userspace */ error = copy_to_user(argp, tw_ioctl, sizeof(TW_New_Ioctl) + data_buffer_length - 1); if (error == 0) retval = 0;out2: /* Now free ioctl buf memory */ pci_free_consistent(tw_dev->tw_pci_dev, data_buffer_length_adjusted+sizeof(TW_New_Ioctl) - 1, cpu_addr, dma_handle);out: up(&tw_dev->ioctl_sem); return retval;} /* End tw_chrdev_ioctl() *//* This function handles open for the character device */static int tw_chrdev_open(struct inode *inode, struct file *file){ unsigned int minor_number; dprintk(KERN_WARNING "3w-xxxx: tw_ioctl_open()\n"); minor_number = iminor(inode); if (minor_number >= tw_device_extension_count) return -ENODEV; return 0;} /* End tw_chrdev_open() *//* This function handles close for the character device */static int tw_chrdev_release(struct inode *inode, struct file *file){ dprintk(KERN_WARNING "3w-xxxx: tw_ioctl_release()\n"); return 0;} /* End tw_chrdev_release() *//* This function will clear all interrupts on the controller */void tw_clear_all_interrupts(TW_Device_Extension *tw_dev){ u32 control_reg_addr, control_reg_value; control_reg_addr = tw_dev->registers.control_reg_addr; control_reg_value = TW_STATUS_VALID_INTERRUPT; outl(control_reg_value, control_reg_addr);} /* End tw_clear_all_interrupts() *//* This function will clear the attention interrupt */void tw_clear_attention_interrupt(TW_Device_Extension *tw_dev){ u32 control_reg_addr, control_reg_value; control_reg_addr = tw_dev->registers.control_reg_addr; control_reg_value = TW_CONTROL_CLEAR_ATTENTION_INTERRUPT; outl(control_reg_value, control_reg_addr);} /* End tw_clear_attention_interrupt() *//* This function will clear the host interrupt */void tw_clear_host_interrupt(TW_Device_Extension *tw_dev){ u32 control_reg_addr, control_reg_value; control_reg_addr = tw_dev->registers.control_reg_addr; control_reg_value = TW_CONTROL_CLEAR_HOST_INTERRUPT; outl(control_reg_value, control_reg_addr);} /* End tw_clear_host_interrupt() *//* This function is called by tw_scsi_proc_info */static int tw_copy_info(TW_Info *info, char *fmt, ...) { va_list args; char buf[81]; int len; va_start(args, fmt); len = vsprintf(buf, fmt, args); va_end(args); tw_copy_mem_info(info, buf, len); return len;} /* End tw_copy_info() *//* This function is called by tw_scsi_proc_info */static void tw_copy_mem_info(TW_Info *info, char *data, int len){ if (info->position + len > info->length) len = info->length - info->position; if (info->position + len < info->offset) { info->position += len; return; } if (info->position < info->offset) { data += (info->offset - info->position); len -= (info->offset - info->position); } if (len > 0) { memcpy(info->buffer + info->position, data, len); info->position += len; }} /* End tw_copy_mem_info() *//* This function will print readable messages from status register errors */int tw_decode_bits(TW_Device_Extension *tw_dev, u32 status_reg_value, int print_host){ char host[16]; dprintk(KERN_WARNING "3w-xxxx: tw_decode_bits()\n"); if (print_host) sprintf(host, " scsi%d:", tw_dev->host->host_no); else host[0] = '\0'; if (status_reg_value & TW_STATUS_PCI_PARITY_ERROR) { printk(KERN_WARNING "3w-xxxx:%s PCI Parity Error: clearing.\n", host); outl(TW_CONTROL_CLEAR_PARITY_ERROR, tw_dev->registers.control_reg_addr); } if (status_reg_value & TW_STATUS_PCI_ABORT) { printk(KERN_WARNING "3w-xxxx:%s PCI Abort: clearing.\n", host); outl(TW_CONTROL_CLEAR_PCI_ABORT, tw_dev->registers.control_reg_addr); pci_write_config_word(tw_dev->tw_pci_dev, PCI_STATUS, TW_PCI_CLEAR_PCI_ABORT); } if (status_reg_value & TW_STATUS_QUEUE_ERROR) { printk(KERN_WARNING "3w-xxxx:%s Controller Queue Error: clearing.\n", host); outl(TW_CONTROL_CLEAR_QUEUE_ERROR, tw_dev->registers.control_reg_addr); } if (status_reg_value & TW_STATUS_SBUF_WRITE_ERROR) { printk(KERN_WARNING "3w-xxxx:%s SBUF Write Error: clearing.\n", host); outl(TW_CONTROL_CLEAR_SBUF_WRITE_ERROR, tw_dev->registers.control_reg_addr); } if (status_reg_value & TW_STATUS_MICROCONTROLLER_ERROR) { if (tw_dev->reset_print == 0) { printk(KERN_WARNING "3w-xxxx:%s Microcontroller Error: clearing.\n", host); tw_dev->reset_print = 1; } return 1; } return 0;} /* End tw_decode_bits() *//* This function will return valid sense buffer information for failed cmds */int tw_decode_sense(TW_Device_Extension *tw_dev, int request_id, int fill_sense){ int i; TW_Command *command; dprintk(KERN_WARNING "3w-xxxx: tw_decode_sense()\n"); command = (TW_Command *)tw_dev->command_packet_virtual_address[request_id]; printk(KERN_WARNING "3w-xxxx: scsi%d: Command failed: status = 0x%x, flags = 0x%x, unit #%d.\n", tw_dev->host->host_no, command->status, command->flags, command->byte3.unit); /* Attempt to return intelligent sense information */ if (fill_sense) { if ((command->status == 0xc7) || (command->status == 0xcb)) { for (i=0;i<(sizeof(tw_sense_table)/sizeof(tw_sense_table[0]));i++) { if (command->flags == tw_sense_table[i][0]) { /* Valid bit and 'current errors' */ tw_dev->srb[request_id]->sense_buffer[0] = (0x1 << 7 | 0x70); /* Sense key */ tw_dev->srb[request_id]->sense_buffer[2] = tw_sense_table[i][1]; /* Additional sense length */ tw_dev->srb[request_id]->sense_buffer[7] = 0xa; /* 10 bytes */ /* Additional sense code */ tw_dev->srb[request_id]->sense_buffer[12] = tw_sense_table[i][2]; /* Additional sense code qualifier */ tw_dev->srb[request_id]->sense_buffer[13] = tw_sense_table[i][3]; tw_dev->srb[request_id]->result = (DID_OK << 16) | (CHECK_CONDITION << 1); return TW_ISR_DONT_RESULT; /* Special case for isr to not over-write result */ } } } /* If no table match, error so we get a reset */ return 1; } return 0;} /* End tw_decode_sense() *//* This function will disable interrupts on the controller */ void tw_disable_interrupts(TW_Device_Extension *tw_dev) { u32 control_reg_value, control_reg_addr; control_reg_addr = tw_dev->registers.control_reg_addr; control_reg_value = TW_CONTROL_DISABLE_INTERRUPTS; outl(control_reg_value, control_reg_addr);} /* End tw_disable_interrupts() *//* This function will empty the response que */void tw_empty_response_que(TW_Device_Extension *tw_dev) { u32 status_reg_addr, status_reg_value; u32 response_que_addr, response_que_value; 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); while ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) { response_que_value = inl(response_que_addr); status_reg_value = inl(status_reg_addr); }} /* End tw_empty_response_que() *//* This function will enable interrupts on the controller */void tw_enable_interrupts(TW_Device_Extension *tw_dev){ u32 control_reg_value, control_reg_addr; control_reg_addr = tw_dev->registers.control_reg_addr; control_reg_value = (TW_CONTROL_ENABLE_INTERRUPTS | TW_CONTROL_UNMASK_RESPONSE_INTERRUPT); outl(control_reg_value, control_reg_addr);} /* End tw_enable_interrupts() *//* This function will enable interrupts on the controller */void tw_enable_and_clear_interrupts(TW_Device_Extension *tw_dev){ u32 control_reg_value, control_reg_addr; control_reg_addr = tw_dev->registers.control_reg_addr; control_reg_value = (TW_CONTROL_CLEAR_ATTENTION_INTERRUPT | TW_CONTROL_UNMASK_RESPONSE_INTERRUPT | TW_CONTROL_ENABLE_INTERRUPTS); outl(control_reg_value, control_reg_addr);} /* End tw_enable_and_clear_interrupts() *//* This function will find and initialize all cards */int tw_findcards(Scsi_Host_Template *tw_host) { int numcards = 0, tries = 0, error = 0; struct Scsi_Host *host; TW_Device_Extension *tw_dev; TW_Device_Extension *tw_dev2; struct pci_dev *tw_pci_dev = NULL; u32 status_reg_value; unsigned char c = 1; int i, j = -1; u16 device[TW_NUMDEVICES] = { TW_DEVICE_ID, TW_DEVICE_ID2 }; dprintk(KERN_NOTICE "3w-xxxx: tw_findcards()\n"); for (i=0;i<TW_NUMDEVICES;i++) { while ((tw_pci_dev = pci_find_device(TW_VENDOR_ID, device[i], tw_pci_dev))) { j++; if (pci_enable_device(tw_pci_dev)) continue; /* We only need 32-bit addressing for 5,6,7xxx cards */ if (pci_set_dma_mask(tw_pci_dev, 0xffffffff)) { printk(KERN_WARNING "3w-xxxx: No suitable DMA available.\n"); continue; } /* Prepare temporary device extension */ tw_dev=(TW_Device_Extension *)kmalloc(sizeof(TW_Device_Extension), GFP_ATOMIC); if (tw_dev == NULL) { printk(KERN_WARNING "3w-xxxx: tw_findcards(): kmalloc() failed for card %d.\n", j); continue; } memset(tw_dev, 0, sizeof(TW_Device_Extension)); /* Save pci_dev struct to device extension */ tw_dev->tw_pci_dev = tw_pci_dev; error = tw_initialize_device_extension(tw_dev); if (error) { printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't initialize device extension for card %d.\n", j); tw_free_device_extension(tw_dev); kfree(tw_dev); continue; } /* Calculate the cards register addresses */ tw_dev->registers.base_addr = pci_resource_start(tw_pci_dev, 0); tw_dev->registers.control_reg_addr = pci_resource_start(tw_pci_dev, 0); tw_dev->registers.status_reg_addr = pci_resource_start(tw_pci_dev, 0) + 0x4; tw_dev->registers.command_que_addr = pci_resource_start(tw_pci_dev, 0) + 0x8; tw_dev->registers.response_que_addr = pci_resource_start(tw_pci_dev, 0) + 0xC;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -