3w-9xxx.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,986 行 · 第 1/5 页
C
1,986 行
TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1f, "Microcontroller not ready during reset sequence"); do_soft_reset = 1; tries++; continue; } /* Empty response queue */ if (twa_empty_response_queue(tw_dev)) { TW_PRINTK(tw_dev->host, TW_DRIVER, 0x20, "Response queue empty failed during reset sequence"); do_soft_reset = 1; tries++; continue; } flashed = 0; /* Check for compatibility/flash */ if (twa_check_srl(tw_dev, &flashed)) { TW_PRINTK(tw_dev->host, TW_DRIVER, 0x21, "Compatibility check failed during reset sequence"); do_soft_reset = 1; tries++; continue; } else { if (flashed) { tries++; continue; } } /* Drain the AEN queue */ if (twa_aen_drain_queue(tw_dev, soft_reset)) { TW_PRINTK(tw_dev->host, TW_DRIVER, 0x22, "AEN drain failed during reset sequence"); do_soft_reset = 1; tries++; continue; } /* If we got here, controller is in a good state */ retval = 0; goto out; }out: return retval;} /* End twa_reset_sequence() *//* This funciton returns unit geometry in cylinders/heads/sectors */static int twa_scsi_biosparam(struct scsi_device *sdev, struct block_device *bdev, sector_t capacity, int geom[]){ int heads, sectors, cylinders; TW_Device_Extension *tw_dev; tw_dev = (TW_Device_Extension *)sdev->host->hostdata; if (capacity >= 0x200000) { heads = 255; sectors = 63; cylinders = sector_div(capacity, heads * sectors); } else { heads = 64; sectors = 32; cylinders = sector_div(capacity, heads * sectors); } geom[0] = heads; geom[1] = sectors; geom[2] = cylinders; return 0;} /* End twa_scsi_biosparam() *//* This is the new scsi eh abort function */static int twa_scsi_eh_abort(struct scsi_cmnd *SCpnt){ int i; TW_Device_Extension *tw_dev = NULL; int retval = FAILED; tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata; spin_unlock_irq(tw_dev->host->host_lock); tw_dev->num_aborts++; /* If we find any IO's in process, we have to reset the card */ for (i = 0; i < TW_Q_LENGTH; i++) { if ((tw_dev->state[i] != TW_S_FINISHED) && (tw_dev->state[i] != TW_S_INITIAL)) { printk(KERN_WARNING "3w-9xxx: scsi%d: WARNING: (0x%02X:0x%04X): Unit #%d: Command (0x%x) timed out, resetting card.\n", tw_dev->host->host_no, TW_DRIVER, 0x2c, SCpnt->device->id, SCpnt->cmnd[0]); if (twa_reset_device_extension(tw_dev)) { TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2a, "Controller reset failed during scsi abort"); goto out; } break; } } retval = SUCCESS;out: spin_lock_irq(tw_dev->host->host_lock); return retval;} /* End twa_scsi_eh_abort() *//* This is the new scsi eh reset function */static int twa_scsi_eh_reset(struct scsi_cmnd *SCpnt){ TW_Device_Extension *tw_dev = NULL; int retval = FAILED; tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata; spin_unlock_irq(tw_dev->host->host_lock); tw_dev->num_resets++; printk(KERN_WARNING "3w-9xxx: scsi%d: SCSI host reset started.\n", tw_dev->host->host_no); /* Now reset the card and some of the device extension data */ if (twa_reset_device_extension(tw_dev)) { TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2b, "Controller reset failed during scsi host reset"); goto out; } printk(KERN_WARNING "3w-9xxx: scsi%d: SCSI host reset succeeded.\n", tw_dev->host->host_no); retval = SUCCESS;out: spin_lock_irq(tw_dev->host->host_lock); return retval;} /* End twa_scsi_eh_reset() *//* This is the main scsi queue function to handle scsi opcodes */static int twa_scsi_queue(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)){ int request_id, retval; TW_Device_Extension *tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata; /* Save done function into scsi_cmnd struct */ SCpnt->scsi_done = done; /* Get a free request id */ twa_get_request_id(tw_dev, &request_id); /* Save the scsi command for use by the ISR */ tw_dev->srb[request_id] = SCpnt; /* Initialize phase to zero */ SCpnt->SCp.phase = TW_PHASE_INITIAL; retval = twa_scsiop_execute_scsi(tw_dev, request_id, NULL, 0, NULL); switch (retval) { case SCSI_MLQUEUE_HOST_BUSY: twa_free_request_id(tw_dev, request_id); break; case 1: tw_dev->state[request_id] = TW_S_COMPLETED; twa_free_request_id(tw_dev, request_id); SCpnt->result = (DID_ERROR << 16); done(SCpnt); } return retval;} /* End twa_scsi_queue() *//* This function hands scsi cdb's to the firmware */static int twa_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id, char *cdb, int use_sg, TW_SG_Apache *sglistarg){ TW_Command_Full *full_command_packet; TW_Command_Apache *command_packet; u32 num_sectors = 0x0; int i, sg_count; struct scsi_cmnd *srb = NULL; struct scatterlist *sglist = NULL; u32 buffaddr = 0x0; int retval = 1; if (tw_dev->srb[request_id]) { if (tw_dev->srb[request_id]->request_buffer) { sglist = (struct scatterlist *)tw_dev->srb[request_id]->request_buffer; } srb = tw_dev->srb[request_id]; } /* Initialize command packet */ full_command_packet = tw_dev->command_packet_virt[request_id]; full_command_packet->header.header_desc.size_header = 128; full_command_packet->header.status_block.error = 0; full_command_packet->header.status_block.severity__reserved = 0; command_packet = &full_command_packet->command.newcommand; command_packet->status = 0; command_packet->opcode__reserved = TW_OPRES_IN(0, TW_OP_EXECUTE_SCSI); /* We forced 16 byte cdb use earlier */ if (!cdb) memcpy(command_packet->cdb, srb->cmnd, TW_MAX_CDB_LEN); else memcpy(command_packet->cdb, cdb, TW_MAX_CDB_LEN); if (srb) command_packet->unit = srb->device->id; else command_packet->unit = 0; command_packet->request_id = request_id; command_packet->sgl_offset = 16; if (!sglistarg) { /* Map sglist from scsi layer to cmd packet */ if (tw_dev->srb[request_id]->use_sg == 0) { if (tw_dev->srb[request_id]->request_bufflen < TW_MIN_SGL_LENGTH) { command_packet->sg_list[0].address = tw_dev->generic_buffer_phys[request_id]; command_packet->sg_list[0].length = TW_MIN_SGL_LENGTH; } else { buffaddr = twa_map_scsi_single_data(tw_dev, request_id); if (buffaddr == 0) goto out; command_packet->sg_list[0].address = buffaddr; command_packet->sg_list[0].length = tw_dev->srb[request_id]->request_bufflen; } command_packet->sgl_entries = 1; if (command_packet->sg_list[0].address & TW_ALIGNMENT_9000_SGL) { TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2d, "Found unaligned address during execute scsi"); goto out; } } if (tw_dev->srb[request_id]->use_sg > 0) { sg_count = twa_map_scsi_sg_data(tw_dev, request_id); if (sg_count == 0) goto out; for (i = 0; i < sg_count; i++) { command_packet->sg_list[i].address = sg_dma_address(&sglist[i]); command_packet->sg_list[i].length = sg_dma_len(&sglist[i]); if (command_packet->sg_list[i].address & TW_ALIGNMENT_9000_SGL) { TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2e, "Found unaligned sgl address during execute scsi"); goto out; } } command_packet->sgl_entries = tw_dev->srb[request_id]->use_sg; } } else { /* Internal cdb post */ for (i = 0; i < use_sg; i++) { command_packet->sg_list[i].address = sglistarg[i].address; command_packet->sg_list[i].length = sglistarg[i].length; if (command_packet->sg_list[i].address & TW_ALIGNMENT_9000_SGL) { TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2f, "Found unaligned sgl address during internal post"); goto out; } } command_packet->sgl_entries = use_sg; } if (srb) { if (srb->cmnd[0] == READ_6 || srb->cmnd[0] == WRITE_6) num_sectors = (u32)srb->cmnd[4]; if (srb->cmnd[0] == READ_10 || srb->cmnd[0] == WRITE_10) num_sectors = (u32)srb->cmnd[8] | ((u32)srb->cmnd[7] << 8); } /* Update sector statistic */ tw_dev->sector_count = num_sectors; if (tw_dev->sector_count > tw_dev->max_sector_count) tw_dev->max_sector_count = tw_dev->sector_count; /* Update SG statistics */ if (srb) { tw_dev->sgl_entries = tw_dev->srb[request_id]->use_sg; if (tw_dev->sgl_entries > tw_dev->max_sgl_entries) tw_dev->max_sgl_entries = tw_dev->sgl_entries; } /* Now post the command to the board */ if (srb) { retval = twa_post_command_packet(tw_dev, request_id, 0); } else { twa_post_command_packet(tw_dev, request_id, 1); retval = 0; }out: return retval;} /* End twa_scsiop_execute_scsi() *//* This function completes an execute scsi operation */static void twa_scsiop_execute_scsi_complete(TW_Device_Extension *tw_dev, int request_id){ /* Copy the response if too small */ if ((tw_dev->srb[request_id]->request_buffer) && (tw_dev->srb[request_id]->request_bufflen < TW_MIN_SGL_LENGTH)) { memcpy(tw_dev->srb[request_id]->request_buffer, tw_dev->generic_buffer_virt[request_id], tw_dev->srb[request_id]->request_bufflen); }} /* End twa_scsiop_execute_scsi_complete() *//* This function tells the controller to shut down */static void __twa_shutdown(TW_Device_Extension *tw_dev){ /* Disable interrupts */ TW_DISABLE_INTERRUPTS(tw_dev); printk(KERN_WARNING "3w-9xxx: Shutting down host %d.\n", tw_dev->host->host_no); /* Tell the card we are shutting down */ if (twa_initconnection(tw_dev, 1, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL)) { TW_PRINTK(tw_dev->host, TW_DRIVER, 0x31, "Connection shutdown failed"); } else { printk(KERN_WARNING "3w-9xxx: Shutdown complete.\n"); } /* Clear all interrupts just before exit */ TW_ENABLE_AND_CLEAR_INTERRUPTS(tw_dev);} /* End __twa_shutdown() *//* Wrapper for __twa_shutdown */static void twa_shutdown(struct device *dev){ struct Scsi_Host *host = pci_get_drvdata(to_pci_dev(dev)); TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata; __twa_shutdown(tw_dev);} /* End twa_shutdown() *//* This function will look up a string */static char *twa_string_lookup(twa_message_type *table, unsigned int code){ int index; for (index = 0; ((code != table[index].code) && (table[index].text != (char *)0)); index++); return(table[index].text);} /* End twa_string_lookup() *//* This function will perform a pci-dma unmap */static void twa_unmap_scsi_data(TW_Device_Extension *tw_dev, int request_id){ struct scsi_cmnd *cmd = tw_dev->srb[request_id]; struct pci_dev *pdev = tw_dev->tw_pci_dev; switch(cmd->SCp.phase) { case TW_PHASE_SINGLE: pci_unmap_single(pdev, cmd->SCp.have_data_in, cmd->request_bufflen, DMA_BIDIRECTIONAL); break; case TW_PHASE_SGLIST: pci_unmap_sg(pdev, cmd->request_buffer, cmd->use_sg, DMA_BIDIRECTIONAL); break; }} /* End twa_unmap_scsi_data() *//* scsi_host_template initializer */static struct scsi_host_template driver_template = { .module = THIS_MODULE, .name = "3ware 9000 Storage Controller", .queuecommand = twa_scsi_queue, .eh_abort_handler = twa_scsi_eh_abort, .eh_host_reset_handler = twa_scsi_eh_reset, .bios_param = twa_scsi_biosparam, .can_queue = TW_Q_LENGTH-2, .this_id = -1, .sg_tablesize = TW_APACHE_MAX_SGL_LENGTH, .max_sectors = TW_MAX_SECTORS, .cmd_per_lun = TW_MAX_CMDS_PER_LUN, .use_clustering = ENABLE_CLUSTERING, .shost_attrs = twa_host_attrs, .sdev_attrs = twa_dev_attrs, .emulated = 1};/* This function will probe and initialize a card */static int __devinit twa_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id){ struct Scsi_Host *host = NULL; TW_Device_Extension *tw_dev; u32 mem_addr; int retval = -ENODEV; retval = pci_enable_device(pdev); if (retval) { TW_PRINTK(host, TW_DRIVER, 0x34, "Failed to enable pci device"); goto out_disable_device; } pci_set_master(pdev); retval = pci_set_dma_mask(pdev, TW_DMA_MASK); if (retval) { TW_PRINTK(host, TW_DRIVER, 0x23, "Failed to set dma mask"); goto out_disable_device; } host = scsi_host_alloc(&driver_template, sizeof(TW_Device_Extension)); if (!host) { T
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?