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 + -
显示快捷键?