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