ips.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,776 行 · 第 1/5 页
C
1,776 行
ips_intr_morpheus(ips_ha_t * ha){ ips_stat_t *sp; ips_scb_t *scb; IPS_STATUS cstatus; int intrstatus; METHOD_TRACE("ips_intr_morpheus", 2); if (!ha) return 0; if (!ha->active) return 0; intrstatus = (*ha->func.isintr) (ha); if (!intrstatus) { /* * Unexpected/Shared interrupt */ return 0; } while (TRUE) { sp = &ha->sp; intrstatus = (*ha->func.isintr) (ha); if (!intrstatus) break; else cstatus.value = (*ha->func.statupd) (ha); if (cstatus.value == 0xffffffff) /* No more to process */ break; if (cstatus.fields.command_id > (IPS_MAX_CMDS - 1)) { IPS_PRINTK(KERN_WARNING, ha->pcidev, "Spurious interrupt; no ccb.\n"); continue; } ips_chkstatus(ha, &cstatus); scb = (ips_scb_t *) sp->scb_addr; /* * use the callback function to finish things up * NOTE: interrupts are OFF for this */ (*scb->callback) (ha, scb); } /* end while */ return 1;}/****************************************************************************//* *//* Routine Name: ips_info *//* *//* Routine Description: *//* *//* Return info about the driver *//* *//****************************************************************************/const char *ips_info(struct Scsi_Host *SH){ static char buffer[256]; char *bp; ips_ha_t *ha; METHOD_TRACE("ips_info", 1); ha = IPS_HA(SH); if (!ha) return (NULL); bp = &buffer[0]; memset(bp, 0, sizeof (buffer)); sprintf(bp, "%s%s%s Build %d", "IBM PCI ServeRAID ", IPS_VERSION_HIGH, IPS_VERSION_LOW, IPS_BUILD_IDENT); if (ha->ad_type > 0 && ha->ad_type <= MAX_ADAPTER_NAME) { strcat(bp, " <"); strcat(bp, ips_adapter_name[ha->ad_type - 1]); strcat(bp, ">"); } return (bp);}/****************************************************************************//* *//* Routine Name: ips_proc_info *//* *//* Routine Description: *//* *//* The passthru interface for the driver *//* *//****************************************************************************/intips_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, int length, int func){ int i; int ret; ips_ha_t *ha = NULL; METHOD_TRACE("ips_proc_info", 1); /* Find our host structure */ for (i = 0; i < ips_next_controller; i++) { if (ips_sh[i]) { if (ips_sh[i] == host) { ha = (ips_ha_t *) ips_sh[i]->hostdata; break; } } } if (!ha) return (-EINVAL); if (func) { /* write */ return (0); } else { /* read */ if (start) *start = buffer; ret = ips_host_info(ha, buffer, offset, length); return (ret); }}/*--------------------------------------------------------------------------*//* Helper Functions *//*--------------------------------------------------------------------------*//****************************************************************************//* *//* Routine Name: ips_is_passthru *//* *//* Routine Description: *//* *//* Determine if the specified SCSI command is really a passthru command *//* *//****************************************************************************/static intips_is_passthru(Scsi_Cmnd * SC){ METHOD_TRACE("ips_is_passthru", 1); if (!SC) return (0); if ((SC->cmnd[0] == IPS_IOCTL_COMMAND) && (SC->device->channel == 0) && (SC->device->id == IPS_ADAPTER_ID) && (SC->device->lun == 0) && SC->request_buffer) { if ((!SC->use_sg) && SC->request_bufflen && (((char *) SC->request_buffer)[0] == 'C') && (((char *) SC->request_buffer)[1] == 'O') && (((char *) SC->request_buffer)[2] == 'P') && (((char *) SC->request_buffer)[3] == 'P')) return 1; else if (SC->use_sg) { struct scatterlist *sg = SC->request_buffer; char *buffer = IPS_SG_ADDRESS(sg); if (buffer && buffer[0] == 'C' && buffer[1] == 'O' && buffer[2] == 'P' && buffer[3] == 'P') return 1; } } return 0;}/****************************************************************************//* *//* Routine Name: ips_alloc_passthru_buffer *//* *//* Routine Description: *//* allocate a buffer large enough for the ioctl data if the ioctl buffer *//* is too small or doesn't exist *//****************************************************************************/static intips_alloc_passthru_buffer(ips_ha_t * ha, int length){ void *bigger_buf; dma_addr_t dma_busaddr; if (ha->ioctl_data && length <= ha->ioctl_len) return 0; /* there is no buffer or it's not big enough, allocate a new one */ bigger_buf = pci_alloc_consistent(ha->pcidev, length, &dma_busaddr); if (bigger_buf) { /* free the old memory */ pci_free_consistent(ha->pcidev, ha->ioctl_len, ha->ioctl_data, ha->ioctl_busaddr); /* use the new memory */ ha->ioctl_data = (char *) bigger_buf; ha->ioctl_len = length; ha->ioctl_busaddr = dma_busaddr; } else { return -1; } return 0;}/****************************************************************************//* *//* Routine Name: ips_make_passthru *//* *//* Routine Description: *//* *//* Make a passthru command out of the info in the Scsi block *//* *//****************************************************************************/static intips_make_passthru(ips_ha_t * ha, Scsi_Cmnd * SC, ips_scb_t * scb, int intr){ ips_passthru_t *pt; int length = 0; int ret; METHOD_TRACE("ips_make_passthru", 1); if (!SC->use_sg) { length = SC->request_bufflen; } else { struct scatterlist *sg = SC->request_buffer; int i; for (i = 0; i < SC->use_sg; i++) length += sg[i].length; } if (length < sizeof (ips_passthru_t)) { /* wrong size */ DEBUG_VAR(1, "(%s%d) Passthru structure wrong size", ips_name, ha->host_num); return (IPS_FAILURE); } if (ips_alloc_passthru_buffer(ha, length)) { /* allocation failure! If ha->ioctl_data exists, use it to return some error codes. Return a failed command to the scsi layer. */ if (ha->ioctl_data) { pt = (ips_passthru_t *) ha->ioctl_data; ips_scmd_buf_read(SC, pt, sizeof (ips_passthru_t)); pt->BasicStatus = 0x0B; pt->ExtendedStatus = 0x00; ips_scmd_buf_write(SC, pt, sizeof (ips_passthru_t)); } return IPS_FAILURE; } ha->ioctl_datasize = length; ips_scmd_buf_read(SC, ha->ioctl_data, ha->ioctl_datasize); pt = (ips_passthru_t *) ha->ioctl_data; /* * Some notes about the passthru interface used * * IF the scsi op_code == 0x0d then we assume * that the data came along with/goes with the * packet we received from the sg driver. In this * case the CmdBSize field of the pt structure is * used for the size of the buffer. */ switch (pt->CoppCmd) { case IPS_NUMCTRLS: memcpy(ha->ioctl_data + sizeof (ips_passthru_t), &ips_num_controllers, sizeof (int)); ips_scmd_buf_write(SC, ha->ioctl_data, sizeof (ips_passthru_t) + sizeof (int)); SC->result = DID_OK << 16; return (IPS_SUCCESS_IMM); case IPS_COPPUSRCMD: case IPS_COPPIOCCMD: if (SC->cmnd[0] == IPS_IOCTL_COMMAND) { if (length < (sizeof (ips_passthru_t) + pt->CmdBSize)) { /* wrong size */ DEBUG_VAR(1, "(%s%d) Passthru structure wrong size", ips_name, ha->host_num); return (IPS_FAILURE); } if (ha->device_id == IPS_DEVICEID_COPPERHEAD && pt->CoppCP.cmd.flashfw.op_code == IPS_CMD_RW_BIOSFW) { ret = ips_flash_copperhead(ha, pt, scb); ips_scmd_buf_write(SC, ha->ioctl_data, sizeof (ips_passthru_t)); return ret; } if (ips_usrcmd(ha, pt, scb)) return (IPS_SUCCESS); else return (IPS_FAILURE); } break; } /* end switch */ return (IPS_FAILURE);}/****************************************************************************//* Routine Name: ips_flash_copperhead *//* Routine Description: *//* Flash the BIOS/FW on a Copperhead style controller *//****************************************************************************/static intips_flash_copperhead(ips_ha_t * ha, ips_passthru_t * pt, ips_scb_t * scb){ int datasize; /* Trombone is the only copperhead that can do packet flash, but only * for firmware. No one said it had to make sence. */ if (IPS_IS_TROMBONE(ha) && pt->CoppCP.cmd.flashfw.type == IPS_FW_IMAGE) { if (ips_usrcmd(ha, pt, scb)) return IPS_SUCCESS; else return IPS_FAILURE; } pt->BasicStatus = 0x0B; pt->ExtendedStatus = 0; scb->scsi_cmd->result = DID_OK << 16; /* IF it's OK to Use the "CD BOOT" Flash Buffer, then you can */ /* avoid allocating a huge buffer per adapter ( which can fail ). */ if (pt->CoppCP.cmd.flashfw.type == IPS_BIOS_IMAGE && pt->CoppCP.cmd.flashfw.direction == IPS_ERASE_BIOS) { pt->BasicStatus = 0; return ips_flash_bios(ha, pt, scb); } else if (pt->CoppCP.cmd.flashfw.packet_num == 0) { if (ips_FlashData && !test_and_set_bit(0, &ips_FlashDataInUse)){ ha->flash_data = ips_FlashData; ha->flash_busaddr = ips_flashbusaddr; ha->flash_len = PAGE_SIZE << 7; ha->flash_datasize = 0; } else if (!ha->fla
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?