📄 3w-xxxx.c
字号:
/* Empty the response queue again */ error = tw_empty_response_que(tw_dev); if (error) { printk(KERN_WARNING "3w-xxxx: tw_reset_sequence(): Couldn't empty response queue for card %d.\n", tw_dev->host->host_no); tries++; continue; } /* Now the controller is in a good state */ break; } if (tries >= TW_MAX_RESET_TRIES) { printk(KERN_WARNING "3w-xxxx: tw_reset_sequence(): Controller error or no attention interrupt: giving up for card %d.\n", tw_dev->host->host_no); return 1; } error = tw_initconnection(tw_dev, TW_INIT_MESSAGE_CREDITS); if (error) { printk(KERN_WARNING "3w-xxxx: tw_reset_sequence(): Couldn't initconnection for card %d.\n", tw_dev->host->host_no); return 1; } /* Re-enable interrupts */ tw_enable_interrupts(tw_dev); return 0;} /* End tw_reset_sequence() *//* This funciton returns unit geometry in cylinders/heads/sectors */int tw_scsi_biosparam(Disk *disk, kdev_t dev, int geom[]) { int heads, sectors, cylinders; TW_Device_Extension *tw_dev; dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_biosparam()\n"); tw_dev = (TW_Device_Extension *)disk->device->host->hostdata; heads = 64; sectors = 32; cylinders = disk->capacity / (heads * sectors); if (disk->capacity >= 0x200000) { heads = 255; sectors = 63; cylinders = disk->capacity / (heads * sectors); } dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_biosparam(): heads = %d, sectors = %d, cylinders = %d\n", heads, sectors, cylinders); geom[0] = heads; geom[1] = sectors; geom[2] = cylinders; return 0;} /* End tw_scsi_biosparam() *//* This function will find and initialize any cards */int tw_scsi_detect(Scsi_Host_Template *tw_host){ dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_detect()\n"); /* Check if the kernel has PCI interface compiled in */ if (!pci_present()) { printk(KERN_WARNING "3w-xxxx: tw_scsi_detect(): No pci interface present.\n"); return 0; } return(tw_findcards(tw_host));} /* End tw_scsi_detect() *//* This is the new scsi eh abort function */int tw_scsi_eh_abort(Scsi_Cmnd *SCpnt) { TW_Device_Extension *tw_dev=NULL; int i = 0; dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_eh_abort()\n"); if (!SCpnt) { printk(KERN_WARNING "3w-xxxx: tw_scsi_eh_abort(): Invalid Scsi_Cmnd.\n"); return (FAILED); } tw_dev = (TW_Device_Extension *)SCpnt->host->hostdata; if (tw_dev == NULL) { printk(KERN_WARNING "3w-xxxx: tw_scsi_eh_abort(): Invalid device extension.\n"); return (FAILED); } spin_lock(&tw_dev->tw_lock); tw_dev->num_aborts++; /* If the command hasn't been posted yet, we can do the abort */ for (i=0;i<TW_Q_LENGTH;i++) { if (tw_dev->srb[i] == SCpnt) { if (tw_dev->state[i] == TW_S_STARTED) { printk(KERN_WARNING "3w-xxxx: tw_scsi_eh_abort(): Abort succeeded for started Scsi_Cmnd 0x%x\n", (u32)tw_dev->srb[i]); tw_dev->state[i] = TW_S_COMPLETED; tw_state_request_finish(tw_dev, i); spin_unlock(&tw_dev->tw_lock); return (SUCCESS); } if (tw_dev->state[i] == TW_S_PENDING) { printk(KERN_WARNING "3w-xxxx: tw_scsi_eh_abort(): Abort succeeded for pending Scsi_Cmnd 0x%x\n", (u32)tw_dev->srb[i]); 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--; tw_dev->state[i] = TW_S_COMPLETED; tw_state_request_finish(tw_dev, i); spin_unlock(&tw_dev->tw_lock); return (SUCCESS); } } } /* If the command has already been posted, we have to reset the card */ printk(KERN_WARNING "3w-xxxx: tw_scsi_eh_abort(): Abort failed for unknown Scsi_Cmnd 0x%x, resetting card %d.\n", (u32)SCpnt, tw_dev->host->host_no); if (tw_reset_device_extension(tw_dev)) { printk(KERN_WARNING "3w-xxxx: tw_scsi_eh_abort(): Reset failed for card %d.\n", tw_dev->host->host_no); spin_unlock(&tw_dev->tw_lock); return (FAILED); } spin_unlock(&tw_dev->tw_lock); return (SUCCESS);} /* End tw_scsi_eh_abort() *//* This is the new scsi eh reset function */int tw_scsi_eh_reset(Scsi_Cmnd *SCpnt) { TW_Device_Extension *tw_dev=NULL; dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_eh_reset()\n"); if (!SCpnt) { printk(KERN_WARNING "3w-xxxx: tw_scsi_eh_reset(): Invalid Scsi_Cmnd.\n"); return (FAILED); } tw_dev = (TW_Device_Extension *)SCpnt->host->hostdata; if (tw_dev == NULL) { printk(KERN_WARNING "3w-xxxx: tw_scsi_eh_reset(): Invalid device extension.\n"); return (FAILED); } spin_lock(&tw_dev->tw_lock); tw_dev->num_resets++; /* Now reset the card and some of the device extension data */ if (tw_reset_device_extension(tw_dev)) { printk(KERN_WARNING "3w-xxxx: tw_scsi_eh_reset(): Reset failed for card %d.\n", tw_dev->host->host_no); spin_unlock(&tw_dev->tw_lock); return (FAILED); } printk(KERN_WARNING "3w-xxxx: tw_scsi_eh_reset(): Reset succeeded for card %d.\n", tw_dev->host->host_no); spin_unlock(&tw_dev->tw_lock); return (SUCCESS);} /* End tw_scsi_eh_reset() *//* This function handles input and output from /proc/scsi/3w-xxxx/x */int tw_scsi_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout) { TW_Device_Extension *tw_dev = NULL; TW_Info info; int i; int j; dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_proc_info()\n"); /* Find the correct device extension */ for (i=0;i<tw_device_extension_count;i++) if (tw_device_extension_list[i]->host->host_no == hostno) tw_dev = tw_device_extension_list[i]; if (tw_dev == NULL) { printk(KERN_WARNING "3w-xxxx: tw_scsi_proc_info(): Couldn't locate device extension.\n"); return (-EINVAL); } info.buffer = buffer; info.length = length; info.offset = offset; info.position = 0; if (inout) { /* Write */ if (strncmp(buffer, "debug", 5) == 0) { printk(KERN_INFO "3w-xxxx: Posted commands:\n"); for (j=0;j<TW_Q_LENGTH;j++) { if (tw_dev->state[j] == TW_S_POSTED) { TW_Command *command = (TW_Command *)tw_dev->command_packet_virtual_address[j]; printk(KERN_INFO "3w-xxxx: Request_id: %d\n", j); printk(KERN_INFO "Opcode: 0x%x\n", command->byte0.opcode); printk(KERN_INFO "Block_count: 0x%x\n", command->byte6.block_count); printk(KERN_INFO "LBA: 0x%x\n", (u32)command->byte8.io.lba); printk(KERN_INFO "Physical command packet addr: 0x%x\n", tw_dev->command_packet_physical_address[j]); printk(KERN_INFO "Scsi_Cmnd: 0x%x\n", (u32)tw_dev->srb[j]); } } printk(KERN_INFO "3w-xxxx: Free_head: %3d\n", tw_dev->free_head); printk(KERN_INFO "3w-xxxx: Free_tail: %3d\n", tw_dev->free_tail); } return length; } else { /* Read */ if (start) { *start = buffer; } tw_copy_info(&info, "scsi%d: 3ware Storage Controller\n", hostno); tw_copy_info(&info, "Driver version: %s\n", tw_driver_version); tw_copy_info(&info, "Current commands posted: %3d\n", tw_dev->posted_request_count); tw_copy_info(&info, "Max commands posted: %3d\n", tw_dev->max_posted_request_count); tw_copy_info(&info, "Current pending commands: %3d\n", tw_dev->pending_request_count); tw_copy_info(&info, "Max pending commands: %3d\n", tw_dev->max_pending_request_count); tw_copy_info(&info, "Last sgl length: %3d\n", tw_dev->sgl_entries); tw_copy_info(&info, "Max sgl length: %3d\n", tw_dev->max_sgl_entries); tw_copy_info(&info, "Last sector count: %3d\n", tw_dev->sector_count); tw_copy_info(&info, "Max sector count: %3d\n", tw_dev->max_sector_count); tw_copy_info(&info, "Resets: %3d\n", tw_dev->num_resets); tw_copy_info(&info, "Aborts: %3d\n", tw_dev->num_aborts); } if (info.position > info.offset) { return (info.position - info.offset); } else { return 0; }} /* End tw_scsi_proc_info() *//* This is the main scsi queue function to handle scsi opcodes */int tw_scsi_queue(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) { unsigned char *command = SCpnt->cmnd; int request_id = 0; int error = 0; int flags = 0; TW_Device_Extension *tw_dev = (TW_Device_Extension *)SCpnt->host->hostdata; spin_lock_irqsave(&tw_dev->tw_lock, flags); dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue()\n"); /* Skip scsi command if it isn't for us */ if ((tw_dev->is_unit_present[SCpnt->target] == FALSE) || (SCpnt->lun != 0)) { SCpnt->result = (DID_BAD_TARGET << 16); done(SCpnt); spin_unlock_irqrestore(&tw_dev->tw_lock, flags); return 0; } if (done == NULL) { printk(KERN_WARNING "3w-xxxx: tw_scsi_queue(): Invalid done function.\n"); SCpnt->result = (DID_ERROR << 16); done(SCpnt); spin_unlock_irqrestore(&tw_dev->tw_lock, flags); return 0; } if (tw_dev == NULL) { printk(KERN_WARNING "3w-xxxx: tw_scsi_queue(): Invalid device extension.\n"); SCpnt->result = (DID_ERROR << 16); done(SCpnt); spin_unlock_irqrestore(&tw_dev->tw_lock, flags); return 0; } /* Save done function into Scsi_Cmnd struct */ SCpnt->scsi_done = done; /* Queue the command and get a request id */ tw_state_request_start(tw_dev, &request_id); /* Save the scsi command for use by the ISR */ tw_dev->srb[request_id] = SCpnt; switch (*command) { case READ_10: dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught READ_10.\n"); case READ_6: dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught READ_6.\n"); case WRITE_10: dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught WRITE_10.\n"); case WRITE_6: dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught WRITE_6.\n"); error = tw_scsiop_read_write(tw_dev, request_id); break; case TEST_UNIT_READY: dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught TEST_UNIT_READY.\n"); error = tw_scsiop_test_unit_ready(tw_dev, request_id); break; case INQUIRY: dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught INQUIRY.\n"); error = tw_scsiop_inquiry(tw_dev, request_id); break; case READ_CAPACITY: dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught READ_CAPACITY.\n"); error = tw_scsiop_read_capacity(tw_dev, request_id); break; case TW_IOCTL: dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught TW_SCSI_IOCTL.\n"); error = tw_ioctl(tw_dev, request_id); break; default: printk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): Unknown scsi opcode: 0x%x\n", *command); tw_dev->state[request_id] = TW_S_COMPLETED; tw_state_request_finish(tw_dev, request_id); SCpnt->result = (DID_BAD_TARGET << 16); done(SCpnt); } if (error) { tw_dev->state[request_id] = TW_S_COMPLETED; tw_state_request_finish(tw_dev, request_id); SCpnt->result = (DID_ERROR << 16); done(SCpnt); } spin_unlock_irqrestore(&tw_dev->tw_lock, flags); return 0;} /* End tw_scsi_queue() *//* This function will release the resources on an rmmod call */int tw_scsi_release(struct Scsi_Host *tw_host) { TW_Device_Extension *tw_dev; tw_dev = (TW_Device_Extension *)tw_host->hostdata; dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_release()\n"); /* Free up the IO region */ release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE); /* Free up the IRQ */ free_irq(tw_dev->tw_pci_dev->irq, tw_dev); /* Free up device extension resources */ tw_free_device_extension(tw_dev); /* Tell kernel scsi-layer we are gone */ scsi_unregister(tw_host); /* Fake like we just shut down, so notify the card that * we "shut down cleanly". */ tw_halt(0, 0, 0); // parameters aren't actually used return 0;} /* End tw_scsi_release() *//* This function handles scsi inquiry commands */int tw_scsiop_inquiry(TW_Device_Extension *tw_dev, int request_id){ TW_Param *param; TW_Command *command_packet; u32 command_que_value, command_que_addr; u32 param_value; dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_inquiry()\n"); /* Initialize command packet */ command_que_addr = tw_dev->registers.command_que_addr; command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id]; if (command_packet == NULL) { printk(KERN_WARNING "3w-xxxx: tw_scsiop_inquiry(): 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.parameter_count = 1; /* Now setup the param */ if (tw_dev->alignment_virtual_address[request_id] == NULL) { printk(KERN_WARNING "3w-xxxx: tw_scsiop_in
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -