 ahd_cmd_set_transaction_status(cmd, CAM_REQUEUE_REQ); ahd_linux_queue_cmd_complete(ahd, cmd); ahd_schedule_completeq(ahd); ahd_midlayer_entrypoint_unlock(ahd, &flags); return (0); } 
printf("%s: queue frozen\n", ahd_name(ahd));  return SCSI_MLQUEUE_HOST_BUSY; }  /* * Save the callback on completion function. */ cmd->scsi_done = scsi_done;  
static aic_option_callback_t ahd_linux_setup_iocell_info;static int ahd_linux_next_unit(void);static void ahd_runq_tasklet(unsigned long data);static int aic79xx_setup(char *c);/****************************** Inlines ***************************************/static __inline void ahd_schedule_completeq(struct ahd_softc *ahd);static __inline void ahd_schedule_runq(struct ahd_softc *ahd);static __inline void ahd_setup_runq_tasklet(struct ahd_softc *ahd);static __inline void ahd_teardown_runq_tasklet(struct ahd_softc *ahd);static __inline struct ahd_linux_device*		     ahd_linux_get_device(struct ahd_softc *ahd, u_int channel,					  u_int target, u_int lun, int alloc);static struct ahd_cmd *ahd_linux_run_complete_queue(struct ahd_softc *ahd);static __inline void ahd_linux_check_device_queue(struct ahd_softc *ahd,						  struct ahd_linux_device *dev);static __inline struct ahd_linux_device *		     ahd_linux_next_device_to_run(struct ahd_softc *ahd);static __inline void ahd_linux_run_device_queues(struct ahd_softc *ahd);static __inline void ahd_linux_unmap_scb(struct ahd_softc*, struct scb*);static __inline voidahd_schedule_completeq(struct ahd_softc *ahd){	if ((ahd->platform_data->flags & AHD_RUN_CMPLT_Q_TIMER) == 0) {		ahd->platform_data->flags |= AHD_RUN_CMPLT_Q_TIMER;		ahd->platform_data->completeq_timer.expires = jiffies;		add_timer(&ahd->platform_data->completeq_timer);	}}/* * Must be called with our lock held. */static __inline voidahd_schedule_runq(struct ahd_softc *ahd){	tasklet_schedule(&ahd->platform_data->runq_tasklet);}static __inlinevoid ahd_setup_runq_tasklet(struct ahd_softc *ahd){	tasklet_init(&ahd->platform_data->runq_tasklet, ahd_runq_tasklet,		     (unsigned long)ahd);}static __inline voidahd_teardown_runq_tasklet(struct ahd_softc *ahd){	tasklet_kill(&ahd->platform_data->runq_tasklet);}static __inline struct ahd_linux_device*ahd_linux_get_device(struct ahd_softc *ahd, u_int channel, u_int target,		     u_int lun, int alloc){	struct ahd_linux_target *targ;	struct ahd_linux_device *dev;	u_int target_offset;	target_offset = target;	if (channel != 0)		target_offset += 8;	targ = ahd->platform_data->targets[target_offset];	if (targ == NULL) {		if (alloc != 0) {			targ = ahd_linux_alloc_target(ahd, channel, target);			if (targ == NULL)				return (NULL);		} else			return (NULL);	}	dev = targ->devices[lun];	if (dev == NULL && alloc != 0)		dev = ahd_linux_alloc_device(ahd, targ, lun);	return (dev);}#define AHD_LINUX_MAX_RETURNED_ERRORS 4static struct ahd_cmd *ahd_linux_run_complete_queue(struct ahd_softc *ahd){		struct	ahd_cmd *acmd;	u_long	done_flags;	int	with_errors;	with_errors = 0;	ahd_done_lock(ahd, &done_flags);	while ((acmd = TAILQ_FIRST(&ahd->platform_data->completeq)) != NULL) {		Scsi_Cmnd *cmd;		if (with_errors > AHD_LINUX_MAX_RETURNED_ERRORS) {			/*			 * Linux uses stack recursion to requeue			 * commands that need to be retried.  Avoid			 * blowing out the stack by "spoon feeding"			 * commands that completed with error back			 * the operating system in case they are going			 * to be retried. "ick"			 */			ahd_schedule_completeq(ahd);			break;		}		TAILQ_REMOVE(&ahd->platform_data->completeq,			     acmd, acmd_links.tqe);		cmd = &acmd_scsi_cmd(acmd);		cmd->host_scribble = NULL;		if (ahd_cmd_get_transaction_status(cmd) != DID_OK		 || (cmd->result & 0xFF) != SCSI_STATUS_OK)			with_errors++;		cmd->scsi_done(cmd);	}	ahd_done_unlock(ahd, &done_flags);	return (acmd);}static __inline voidahd_linux_check_device_queue(struct ahd_softc *ahd,			     struct ahd_linux_device *dev){	if ((dev->flags & AHD_DEV_FREEZE_TIL_EMPTY) != 0	 && dev->active == 0) {		dev->flags &= ~AHD_DEV_FREEZE_TIL_EMPTY;		dev->qfrozen--;	}	if (TAILQ_FIRST(&dev->busyq) == NULL	 || dev->openings == 0 || dev->qfrozen != 0)		return;	ahd_linux_run_device_queue(ahd, dev);}static __inline struct ahd_linux_device *ahd_linux_next_device_to_run(struct ahd_softc *ahd){		if ((ahd->flags & AHD_RESOURCE_SHORTAGE) != 0	 || (ahd->platform_data->qfrozen != 0	  && AHD_DV_SIMQ_FROZEN(ahd) == 0))		return (NULL);	return (TAILQ_FIRST(&ahd->platform_data->device_runq));}static __inline voidahd_linux_run_device_queues(struct ahd_softc *ahd){	struct ahd_linux_device *dev;	while ((dev = ahd_linux_next_device_to_run(ahd)) != NULL) {		TAILQ_REMOVE(&ahd->platform_data->device_runq, dev, links);		dev->flags &= ~AHD_DEV_ON_RUN_LIST;		ahd_linux_check_device_queue(ahd, dev);	}}static __inline voidahd_linux_unmap_scb(struct ahd_softc *ahd, struct scb *scb){	Scsi_Cmnd *cmd;	int direction;	cmd = scb->io_ctx;	direction = cmd->sc_data_direction;	ahd_sync_sglist(ahd, scb, BUS_DMASYNC_POSTWRITE);	if (cmd->use_sg != 0) {		struct scatterlist *sg;		sg = (struct scatterlist *)cmd->request_buffer;		pci_unmap_sg(ahd->dev_softc, sg, cmd->use_sg, direction);	} else if (cmd->request_bufflen != 0) {		pci_unmap_single(ahd->dev_softc,				 scb->platform_data->buf_busaddr,				 cmd->request_bufflen, direction);	}}/******************************** Macros **************************************/#define BUILD_SCSIID(ahd, cmd)						\	((((cmd)->device->id << TID_SHIFT) & TID) | (ahd)->our_id)/************************  Host template entry points *************************/static int	   ahd_linux_detect(Scsi_Host_Template *);static const char *ahd_linux_info(struct Scsi_Host *);static int	   ahd_linux_queue(Scsi_Cmnd *, void (*)(Scsi_Cmnd *));#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)static int	   ahd_linux_slave_alloc(Scsi_Device *);static int	   ahd_linux_slave_configure(Scsi_Device *);static void	   ahd_linux_slave_destroy(Scsi_Device *);#if defined(__i386__)static int	   ahd_linux_biosparam(struct scsi_device*,				       struct block_device*, sector_t, int[]);#endif#elsestatic int	   ahd_linux_release(struct Scsi_Host *);static void	   ahd_linux_select_queue_depth(struct Scsi_Host *host,						Scsi_Device *scsi_devs);#if defined(__i386__)static int	   ahd_linux_biosparam(Disk *, kdev_t, int[]);#endif#endifstatic int	   ahd_linux_bus_reset(Scsi_Cmnd *);static int	   ahd_linux_dev_reset(Scsi_Cmnd *);static int	   ahd_linux_abort(Scsi_Cmnd *);/* * Calculate a safe value for AHD_NSEG (as expressed through ahd_linux_nseg). * * In pre-2.5.X... * The midlayer allocates an S/G array dynamically when a command is issued * using SCSI malloc.  This array, which is in an OS dependent format that * must later be copied to our private S/G list, is sized to house just the * number of segments needed for the current transfer.  Since the code that * sizes the SCSI malloc pool does not take into consideration fragmentation * of the pool, executing transactions numbering just a fraction of our * concurrent transaction limit with SG list lengths aproaching AHC_NSEG will * quickly depleat the SCSI malloc pool of usable space.  Unfortunately, the * mid-layer does not properly handle this scsi malloc failures for the S/G * array and the result can be a lockup of the I/O subsystem.  We try to size * our S/G list so that it satisfies our drivers allocation requirements in * addition to avoiding fragmentation of the SCSI malloc pool. */static voidahd_linux_size_nseg(void){#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)	u_int cur_size;	u_int best_size;	/*	 * The SCSI allocator rounds to the nearest 512 bytes	 * an cannot allocate across a page boundary.  Our algorithm	 * is to start at 1K of scsi malloc space per-command and	 * loop through all factors of the PAGE_SIZE and pick the best.	 */	best_size = 0;	for (cur_size = 1024; cur_size <= PAGE_SIZE; cur_size *= 2) {		u_int nseg;		nseg = cur_size / sizeof(struct scatterlist);		if (nseg < AHD_LINUX_MIN_NSEG)			continue;		if (best_size == 0) {			best_size = cur_size;			ahd_linux_nseg = nseg;		} else {			u_int best_rem;			u_int cur_rem;			/*			 * Compare the traits of the current "best_size"			 * with the current size to determine if the			 * current size is a better size.			 */			best_rem = best_size % sizeof(struct scatterlist);			cur_rem = cur_size % sizeof(struct scatterlist);			if (cur_rem < best_rem) {				best_size = cur_size;				ahd_linux_nseg = nseg;			}		}	}#endif}/* * Try to detect an Adaptec 79XX controller. */static intahd_linux_detect(Scsi_Host_Template *template){	struct	ahd_softc *ahd;	int     found;	int	error = 0;#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)	/*	 * It is a bug that the upper layer takes	 * this lock just prior to calling us.	 */	spin_unlock_irq(&io_request_lock);#endif	/*	 * Sanity checking of Linux SCSI data structures so	 * that some of our hacks^H^H^H^H^Hassumptions aren't	 * violated.	 */	if (offsetof(struct ahd_cmd_internal, end)	  > offsetof(struct scsi_cmnd, host_scribble)) {		printf("ahd_linux_detect: SCSI data structures changed.\n");		printf("ahd_linux_detect: Unable to attach\n");		return (0);	}	/*	 * Determine an appropriate size for our Scatter Gatther lists.	 */	ahd_linux_size_nseg();#ifdef MODULE	/*	 * If we've been passed any parameters, process them now.	 */	if (aic79xx)		aic79xx_setup(aic79xx);#endif	template->proc_name = "aic79xx";	/*	 * Initialize our softc list lock prior to	 * probing for any adapters.	 */	ahd_list_lockinit();#ifdef CONFIG_PCI	error = ahd_linux_pci_init();	if (error)		return error;#endif	/*	 * Register with the SCSI layer all	 * controllers we've found.	 */	found = 0;	TAILQ_FOREACH(ahd, &ahd_tailq, links) {		if (ahd_linux_register_host(ahd, template) == 0)			found++;	}#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)	spin_lock_irq(&io_request_lock);#endif	aic79xx_detect_complete++;	return 0;}#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)/* * Free the passed in Scsi_Host memory structures prior to unloading the * module. */static intahd_linux_release(struct Scsi_Host * host){	struct ahd_softc *ahd;	u_long l;	ahd_list_lock(&l);	if (host != NULL) {		/*		 * We should be able to just perform		 * the free directly, but check our		 * list for extra sanity.		 */		ahd = ahd_find_softc(*(struct ahd_softc **)host->hostdata);		if (ahd != NULL) {			u_long s;			ahd_lock(ahd, &s);			ahd_intr_enable(ahd, FALSE);			ahd_unlock(ahd, &s);			ahd_free(ahd);		}	}	ahd_list_unlock(&l);	return (0);}#endif/* * Return a string describing the driver. */static const char *ahd_linux_info(struct Scsi_Host *host){	static char buffer[512];	char	ahd_info[256];	char   *bp;	struct ahd_softc *ahd;	bp = &buffer[0];	ahd = *(struct ahd_softc **)host->hostdata;	memset(bp, 0, sizeof(buffer));	strcpy(bp, "Adaptec AIC79XX PCI-X SCSI HBA DRIVER, Rev ");	strcat(bp, AIC79XX_DRIVER_VERSION);	strcat(bp, "\n");	strcat(bp, "        <");	strcat(bp, ahd->description);	strcat(bp, ">\n");	strcat(bp, "        ");	ahd_controller_info(ahd, ahd_info);	strcat(bp, ahd_info);	strcat(bp, "\n");	return (bp);}/* * Queue an SCB to the controller. */static intahd_linux_queue(Scsi_Cmnd * cmd, void (*scsi_done) (Scsi_Cmnd *)){	struct	 ahd_softc *ahd;	struct	 ahd_linux_device *dev;	u_long	 flags;	ahd = *(struct ahd_softc **)cmd->device->host->hostdata;	/*	 * Save the callback on completion function.	 */	cmd->scsi_done = scsi_done;	ahd_midlayer_entrypoint_lock(ahd, &flags);	/*	 * Close the race of a command that was in the process of	 * being queued to us just as our simq was frozen.  Let	 * DV commands through so long as we are only frozen to	 * perform DV.	 */	if (ahd->platform_data->qfrozen != 0	 && AHD_DV_CMD(cmd) == 0) {		ahd_cmd_set_transaction_status(cmd, CAM_REQUEUE_REQ);		ahd_linux_queue_cmd_complete(ahd, cmd);		ahd_schedule_completeq(ahd);		ahd_midlayer_entrypoint_unlock(ahd, &flags);		return (0);	}	dev = ahd_linux_get_device(ahd, cmd->device->channel,				   cmd->device->id, cmd->device->lun,				   /*alloc*/TRUE);	if (dev == NULL) {		ahd_cmd_set_transaction_status(cmd, CAM_RESRC_UNAVAIL);		ahd_linux_queue_cmd_complete(ahd, cmd);		ahd_schedule_completeq(ahd);		ahd_midlayer_entrypoint_unlock(ahd, &flags);		printf("%s: aic79xx_linux_queue - Unable to allocate device!\n",		       ahd_name(ahd));		return (0);	}	if (cmd->cmd_len > MAX_CDB_LEN)		return (-EINVAL);	cmd->result = CAM_REQ_INPROG << 16;	TAILQ_INSERT_TAIL(&dev->busyq, (struct ahd_cmd *)cmd, acmd_links.tqe);	if ((dev->flags & AHD_DEV_ON_RUN_LIST) == 0) {		TAILQ_INSERT_TAIL(&ahd->platform_data->device_runq, dev, links);		dev->flags |= AHD_DEV_ON_RUN_LIST;		ahd_linux_run_device_queues(ahd);	}	ahd_midlayer_entrypoint_unlock(ahd, &flags);	return (0);}#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)static intahd_linux_slave_alloc(Scsi_Device *device){	struct	ahd_softc *ahd;	ahd = *((struct ahd_softc **)device->host->hostdata);	if (bootverbose)		printf("%s: Slave Alloc %d\n", ahd_name(ahd), device->id);	return (0);}static intahd_linux_slave_configure(Scsi_Device *device){	struct	ahd_softc *ahd;	struct	ahd_linux_device *dev;	u_long	flags;	ahd = *((struct ahd_softc **)device->host->hostdata);	if (bootverbose)		printf("%s: Slave Configure %d\n", ahd_name(ahd), device->id);	ahd_midlayer_entrypoint_lock(ahd, &flags);	/*	 * Since Linux has attached to the device, configure	 * it so we don't free and allocate the device	 * structure on every command.	 */	dev = ahd_linux_get_device(ahd, device->channel,				   device->id, device->lun,				   /*alloc*/TRUE);	if (dev != NULL) {		dev->flags &= ~AHD_DEV_UNCONFIGURED;		dev->flags |= AHD_DEV_SLAVE_CONFIGURED;		dev->scsi_device = device;		ahd_linux_device_queue_depth(ahd, dev);	}	ahd_midlayer_entrypoint_unlock(ahd, &flags);	return (0);}static voidahd_linux_slave_destroy(Scsi_Device *device){	struct	ahd_softc *ahd;	struct	ahd_linux_device *dev;	u_long	flags;	ahd = *((struct ahd_softc **)device->host->hostdata);	if (bootverbose)		printf("%s: Slave Destroy %d\n", ahd_name(ahd), device->id);	ahd_midlayer_entrypoint_lock(ahd, &flags);	dev = ahd_linux_get_device(ahd, device->channel,				   device->id, device->lun,					   /*alloc*/FALSE);	/*	 * Filter out "silly" deletions of real devices by only	 * deleting devices that have had slave_configure()	 * called on them.  All other devices that have not	 * been configured will automatically be deleted by	 * the refcounting process.	 */	if (dev != NULL	 && (dev->flags & AHD_DEV_SLAVE_CONFIGURED) != 0) {		dev->flags |= AHD_DEV_UNCONFIGURED;		if (TAILQ_EMPTY(&dev->busyq)		 && dev->active == 0		 && (dev->flags & AHD_DEV_TIMER_ACTIVE) == 0)			ahd_linux_free_device(ahd, dev);	}	ahd_midlayer_entrypoint_unlock(ahd, &flags);}#else/* * Sets the queue depth for each SCSI device hanging * off the input host adapter. */static voidahd_linux_select_queue_depth(struct Scsi_Host * host,			     Scsi_Device * scsi_devs){	Scsi_Device *device;	Scsi_Device *ldev;	struct	ahd_softc *ahd;	u_long	flags;	ahd = *((struct ahd_softc **)host->hostdata);	ahd_lock(ahd, &flags);	for (device = scsi_devs; device != NULL; device = device->next) {		/*		 * Watch out for duplicate devices.  This works around		 * some quirks in how the SCSI scanning code does its		 * device management.		 */		for (ldev = scsi_devs; ldev != device; ldev = ldev->next) {			if (ldev->host == device->host			 && ldev->channel == device->channel			 && ldev->id == device->id			 && ldev->lun == device->lun)				break;		}		/* Skip duplicate. */		if (ldev != device)			continue;		if (device->host == host) {			struct	 ahd_linux_device *dev;			/*			 * Since Linux has attached to the device, configure			 * it so we don't free and allocate the device			 * structure on every command.			 */			dev = ahd_linux_get_device(ahd, device->channel,						   device->id, device->lun,						   /*alloc*/TRUE);			if (dev != NULL) {				dev->flags &= ~AHD_DEV_UNCONFIGURED;				dev->scsi_device = device;				ahd_linux_device_queue_depth(ahd, dev);				device->queue_depth = dev->openings						    + dev->active;				if ((dev->flags & (AHD_DEV_Q_BASIC						| AHD_DEV_Q_TAGGED)) == 0) {					/*					 * We allow the OS to queue 2 untagged					 * transactions to us at any time even					 * though we can only execute them					 * serially on the controller/device.					 * This should remove some latency.					 */					device->queue_depth = 2;				}			}		}	}	ahd_unlock(ahd, &flags);}#endif#if defined(__i386__)/* * Return the disk geometry for the given SCSI device. */static int#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)ahd_linux_biosparam(struct scsi_device *sdev, struct block_device *bdev,		    sector_t capacity, int geom[]){	uint8_t *bh;#elseahd_linux_biosparam(Disk *disk, kdev_t dev, int geom[]){	struct	scsi_device *sdev = disk->device;	u_long	capacity = disk->capacity;	struct	buffer_head *bh;#endif	int	 heads;	int	 sectors;	int	 cylinders;	int	 ret;	int	 extended;	struct	 ahd_softc *ahd;	ahd = *((struct ahd_softc **)sdev->host->hostdata);#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)	bh = scsi_bios_ptable(bdev);#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,17)	bh = bread(MKDEV(MAJOR(dev), MINOR(dev) & ~0xf), 0, block_size(dev));#else	bh = bread(MKDEV(MAJOR(dev), MINOR(dev) & ~0xf), 0, 1024);#endif	if (bh) {		ret = scsi_partsize(bh, capacity,				    &geom[2], &geom[0], &geom[1]);#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)		kfree(bh);#else		brelse(bh);#endif		if (ret != -1)			return (ret);	}	heads = 64;	sectors = 32;	cylinders = aic_sector_div(capacity, heads, sectors);	if (aic79xx_extended != 0)		extended = 1;	else		extended = (ahd->flags & AHD_EXTENDED_TRANS_A) != 0;	if (extended && cylinders >= 1024) {		heads = 255;		sectors = 63;		cylinders = aic_sector_div(capacity, heads, sectors);	}	geom[0] = heads;	geom[1] = sectors;	geom[2] = cylinders;	return (0);}#endif/* * Abort the current SCSI command(s). */static intahd_linux_abort(Scsi_Cmnd *cmd){	struct ahd_softc *ahd;	struct ahd_cmd *acmd;	struct ahd_cmd *list_acmd;	struct ahd_linux_device *dev;	struct scb *pending_scb;	u_long s;	u_int  saved_scbptr;	u_int  active_scbptr;	u_int  last_phase;	u_int  cdb_byte;	int    retval;	int    was_paused;	int    paused;	int    wait;	int    disconnected;	ahd_mode_state saved_modes;	pending_scb = NULL;	paused = FALSE;	wait = FALSE;	ahd = *(struct ahd_softc **)cmd->device->host->hostdata;	acmd = (struct ahd_cmd *)cmd;	printf("%s:%d:%d:%d: Attempting to abort cmd %p:",	       ahd_name(ahd), cmd->device->channel, cmd->device->id,	       cmd->device->lun, cmd);	for (cdb_byte = 0; cdb_byte < cmd->cmd_len; cdb_byte++)		printf(" 0x%x", cmd->cmnd[cdb_byte]);	printf("\n");	/*	 * In all versions of Linux, we have to work around	 * a major flaw in how the mid-layer is locked down	 * if we are to sleep successfully in our error handler	 * while allowing our interrupt handler to run.  Since	 * the midlayer acquires either the io_request_lock or	 * our lock prior to calling us, we must use the	 * spin_unlock_irq() method for unlocking our lock.	 * This will force interrupts to be enabled on the	 * current CPU.  Since the EH thread should not have	 * been running with CPU interrupts disabled other than	 * by acquiring either the io_request_lock or our own	 * lock, this *should* be safe.	 */	ahd_midlayer_entrypoint_lock(ahd, &s);	/*	 * First determine if we currently own this command.	 * Start by searching the device queue.  If not found	 * there, check the pending_scb list.  If not found	 * at all, and the system wanted us to just abort the	 * command, return success.	 */	dev = ahd_linux_get_device(ahd, cmd->device->channel,				   cmd->device->id, cmd->device->lun,				   /*alloc*/FALSE);	if (dev == NULL) {		/*		 * No target device for this command exists,		 * so we must not still own the command.		 */		printf("%s:%d:%d:%d: Is not an active device\n",		       ahd_name(ahd), cmd->device->channel, cmd->device->id,		       cmd->device->lun);		retval = SUCCESS;		goto no_cmd;	}	TAILQ_FOREACH(list_acmd, &dev->busyq, acmd_links.tqe) {		if (list_acmd == acmd)			break;	}	if (list_acmd != NULL) {		printf("%s:%d:%d:%d: Command found on device queue\n",		       ahd_name(ahd), cmd->device->channel, cmd->device->id,		       cmd->device->lun);		TAILQ_REMOVE(&dev->busyq, list_acmd, acmd_links.tqe);		cmd->result = DID_ABORT << 16;		ahd_linux_queue_cmd_complete(ahd, cmd);		retval = SUCCESS;		goto done;	}	/*	 * See if we can find a matching cmd in the pending list.	 */	LIST_FOREACH(pending_scb, &ahd->pending_scbs, pending_links) {		if (pending_scb->io_ctx == cmd)			break;	}	if (pending_scb == NULL) {		printf("%s:%d:%d:%d: Command not found\n",		       ahd_name(ahd), cmd->device->channel, cmd->device->id,		       cmd->device->lun);		goto no_cmd;	}	if ((pending_scb->flags & SCB_RECOVERY_SCB) != 0) {		/*		 * We can't queue two recovery actions using the same SCB		 */		retval = FAILED;		goto  done;	}	/*	 * Ensure that the card doesn't do anything	 * behind our back.  Also make sure that we	 * didn't "just" miss an interrupt that would	 * affect this cmd.	 */	was_paused = ahd_is_paused(ahd);	ahd_pause_and_flushwork(ahd);	paused = TRUE;	if ((pending_scb->flags & SCB_ACTIVE) == 0) {		printf("%s:%d:%d:%d: Command already completed\n",		       ahd_name(ahd), cmd->device->channel, cmd->device->id,		       cmd->device->lun);		goto no_cmd;	}	printf("%s: At time of recovery, card was %spaused\n",	       ahd_name(ahd), was_paused ? "" : "not ");	ahd_dump_card_state(ahd);	disconnected = TRUE;	if (ahd_search_qinfifo(ahd, cmd->device->id, cmd->device->channel + 'A',			       cmd->device->lun, SCB_GET_TAG(pending_scb),			       ROLE_INITIATOR, CAM_REQ_ABORTED,			       SEARCH_COMPLETE) > 0) {		printf("%s:%d:%d:%d: Cmd aborted from QINFIFO\n",		       ahd_name(ahd), cmd->device->channel, cmd->device->id,				cmd->device->lun);		retval = SUCCESS;		goto done;	}	saved_modes = ahd_save_modes(ahd);	ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);	last_phase = ahd_inb(ahd, LASTPHASE);	saved_scbptr = ahd_get_scbptr(ahd);	active_scbptr = saved_scbptr;	if (disconnected && (ahd_inb(ahd, SEQ_FLAGS) & NOT_IDENTIFIED) == 0) {		struct scb *bus_scb;		bus_scb = ahd_lookup_scb(ahd, active_scbptr);		if (bus_scb == pending_scb)			disconnected = FALSE;	}	/*	 * At this point, pending_scb is the scb associated with the	 * passed in command.  That command is currently active on the	 * bus or is in the disconnected state.	 */	if (last_phase != P_BUSFREE	 && SCB_GET_TAG(pending_scb) == active_scbptr) {		/*		 * We're active on the bus, so assert ATN		 * and hope that the target responds.		 */		pending_scb = ahd_lookup_scb(ahd, active_scbptr);		pending_scb->flags |= SCB_RECOVERY_SCB|SCB_ABORT;		ahd_outb(ahd, MSG_OUT, HOST_MSG);		ahd_outb(ahd, SCSISIGO, last_phase|ATNO);		printf("%s:%d:%d:%d: Device is active, asserting ATN\n",		       ahd_name(ahd), cmd->device->channel,		       cmd->device->id, cmd->device->lun);		wait = TRUE;	} else if (disconnected) {		/*		 * Actually re-queue this SCB in an attempt		 * to select the device before it reconnects.		 */		pending_scb->flags |= SCB_RECOVERY_SCB|SCB_ABORT;		ahd_set_scbptr(ahd, SCB_GET_TAG(pending_scb));		pending_scb->hscb->cdb_len = 0;		pending_scb->hscb->task_attribute = 0;		pending_scb->hscb->task_management = SIU_TASKMGMT_ABORT_TASK;		if ((pending_scb->flags & SCB_PACKETIZED) != 0) {			/*			 * Mark the SCB has having an outstanding			 * task management function.  Should the command			 * complete normally before the task management			 * function can be sent, the host will be notified			 * to abort our requeued SCB.			 */			ahd_outb(ahd, SCB_TASK_MANAGEMENT,				 pending_scb->hscb->task_management);		} else {			/*			 * If non-packetized, set the MK_MESSAGE control			 * bit indicating that we desire to send a message.			 * We also set the disconnected flag since there is			 * no guarantee that our SCB control byte matches			 * the version on the card.  We don't want the			 * sequencer to abort the command thinking an			 * unsolicited reselection occurred.			 */			pending_scb->hscb->control |= MK_MESSAGE|DISCONNECTED;			/*			 * The sequencer will never re-reference the			 * in-core SCB.  To make sure we are notified			 * during reslection, set the MK_MESSAGE flag in			 * the card's copy of the SCB.			 */			ahd_outb(ahd, SCB_CONTROL,				 ahd_inb(ahd, SCB_CONTROL)|MK_MESSAGE);		}		/*		 * Clear out any entries in the QINFIFO first		 * so we are the next SCB for this target		 * to run.		 */		ahd_search_qinfifo(ahd, cmd->device->id,				   cmd->device->channel + 'A', cmd->device->lun,				   SCB_LIST_NULL, ROLE_INITIATOR,				   CAM_REQUEUE_REQ, SEARCH_COMPLETE);		ahd_qinfifo_requeue_tail(ahd, pending_scb);		ahd_set_scbptr(ahd, saved_scbptr);		ahd_print_path(ahd, pending_scb);		printf("Device is disconnected, re-queuing SCB\n");		wait = TRUE;	} else {		printf("%s:%d:%d:%d: Unable to deliver message\n",		       ahd_name(ahd), cmd->device->channel,		       cmd->device->id, cmd->device->lun);		retval = FAILED;		goto done;	}no_cmd:	/*	 * Our assumption is that if we don't have the command, no	 * recovery action was required, so we return success.  Again,	 * the semantics of the mid-layer recovery engine are not	 * well defined, so this may change in time.	 */	retval = SUCCESS;done:	if (paused)		ahd_unpause(ahd);	if (wait) {		struct timer_list timer;		int ret;		pending_scb->platform_data->flags |= AHD_SCB_UP_EH_SEM;		spin_unlock_irq(&ahd->platform_data->spin_lock);		init_timer(&timer);		timer.data = (u_long)pending_scb;		timer.expires = jiffies + (5 * HZ);		timer.function = ahd_linux_sem_timeout;		add_timer(&timer);		printf("Recovery code sleeping\n");		down(&ahd->platform_data->eh_sem);		printf("Recovery code awake\n");        	ret = del_timer_sync(&timer);		if (ret == 0) {			printf("Timer Expired\n");			retval = FAILED;		}		spin_lock_irq(&ahd->platform_data->spin_lock);	}	ahd_schedule_runq(ahd);	ahd_linux_run_complete_queue(ahd);	ahd_midlayer_entrypoint_unlock(ahd, &s);	return (retval);}static voidahd_linux_dev_reset_complete(Scsi_Cmnd *cmd){	free(cmd, M_DEVBUF);}/* * Attempt to send a target reset message to the device that timed out. */static intahd_linux_dev_reset(Scsi_Cmnd *cmd){	struct	ahd_softc *ahd;	struct	scsi_cmnd *recovery_cmd;	struct	ahd_linux_device *dev;	struct	ahd_initiator_tinfo *tinfo;	struct	ahd_tmode_tstate *tstate;	struct	scb *scb;	struct	hardware_scb *hscb;	u_long	s;	struct	timer_list timer;	int	retval;	ahd = *(struct ahd_softc **)cmd->device->host->hostdata;	recovery_cmd = malloc(sizeof(struct scsi_cmnd), M_DEVBUF, M_WAITOK);	if (!recovery_cmd)		return (FAILED);	memset(recovery_cmd, 0, sizeof(struct scsi_cmnd));	recovery_cmd->device = cmd->device;	recovery_cmd->scsi_done = ahd_linux_dev_reset_complete;#ifdef AHD_DEBUG	if ((ahd_debug & AHD_SHOW_RECOVERY) != 0)		printf("%s:%d:%d:%d: Device reset called for cmd %p\n",		       ahd_name(ahd), cmd->device->channel, cmd->device->id,		       cmd->device->lun, cmd);#endif	ahd_lock(ahd, &s);	dev = ahd_linux_get_device(ahd, cmd->device->channel, cmd->device->id,				   cmd->device->lun, /*alloc*/FALSE);	if (dev == NULL) {		ahd_unlock(ahd, &s);		kfree(recovery_cmd);		return (FAILED);	}	if ((scb = ahd_get_scb(ahd, AHD_NEVER_COL_IDX)) == NULL) {		ahd_unlock(ahd, &s);		kfree(recovery_cmd);		return (FAILED);	}	tinfo = ahd_fetch_transinfo(ahd, 'A', ahd->our_id,				    cmd->device->id, &tstate);	recovery_cmd->result = CAM_REQ_INPROG << 16;	recovery_cmd->host_scribble = (char *)scb;	scb->io_ctx = recovery_cmd;	scb->platform_data->dev = dev;	scb->sg_count = 0;	ahd_set_residual(scb, 0);	ahd_set_sense_residual(scb, 0);	hscb = scb->hscb;	hscb->control = 0;	hscb->scsiid = BUILD_SCSIID(ahd, cmd);	hscb->lun = cmd->device->lun;	hscb->cdb_len = 0;	hscb->task_management = SIU_TASKMGMT_LUN_RESET;	scb->flags |= SCB_DEVICE_RESET|SCB_RECOVERY_SCB|SCB_ACTIVE;	if ((tinfo->curr.ppr_options & MSG_EXT_PPR_IU_REQ) != 0) {		scb->flags |= SCB_PACKETIZED;	} else {		hscb->control |= MK_MESSAGE;	}	dev->openings--;	dev->active++;	dev->commands_issued++;	LIST_INSERT_HEAD(&ahd->pending_scbs, scb, pending_links);	ahd_queue_scb(ahd, scb);	scb->platform_data->flags |= AHD_SCB_UP_EH_SEM;	ahd_unlock(ahd, &s);	init_timer(&timer);	timer.data = (u_long)scb;	timer.expires = jiffies + (5 * HZ);	timer.function = ahd_linux_sem_timeout;	add_timer(&timer);	printf("Recovery code sleeping\n");	down(&ahd->platform_data->eh_sem);	printf("Recovery code awake\n");	retval = SUCCESS;	if (del_timer_sync(&timer) == 0) {		printf("Timer Expired\n");		retval = FAILED;	}	ahd_lock(ahd, &s);	ahd_schedule_runq(ahd);	ahd_linux_run_complete_queue(ahd);	ahd_unlock(ahd, &s);	printf("%s: Device reset returning 0x%x\n", ahd_name(ahd), retval);	return (retval);}/* * Reset the SCSI bus. */static intahd_linux_bus_reset(Scsi_Cmnd *cmd){	struct ahd_softc *ahd;	u_long s;	int    found;	ahd = *(struct ahd_softc **)cmd->device->host->hostdata;#ifdef AHD_DEBUG	if ((ahd_debug & AHD_SHOW_RECOVERY) != 0)		printf("%s: Bus reset called for cmd %p\n",		       ahd_name(ahd), cmd);#endif	ahd_lock(ahd, &s);	found = ahd_reset_channel(ahd, cmd->device->channel + 'A',				  /*initiate reset*/TRUE);	ahd_linux_run_complete_queue(ahd);	ahd_unlock(ahd, &s);	if (bootverbose)		printf("%s: SCSI bus reset delivered. "		       "%d SCBs aborted.\n", ahd_name(ahd), found);	return (SUCCESS);}Scsi_Host_Template aic79xx_driver_template = {	.module			= THIS_MODULE,	.name			= "aic79xx",	.proc_info		= ahd_linux_proc_info,	.info			= ahd_linux_info,	.queuecommand		= ahd_linux_queue,	.eh_abort_handler	= ahd_linux_abort,	.eh_device_reset_handler = ahd_linux_dev_reset,	.eh_bus_reset_handler	= ahd_linux_bus_reset,#if defined(__i386__)	.bios_param		= ahd_linux_biosparam,#endif	.can_queue		= AHD_MAX_QUEUE,	.this_id		= -1,	.cmd_per_lun		= 2,	.use_clustering		= ENABLE_CLUSTERING,	.slave_alloc		= ahd_linux_slave_alloc,	.slave_configure	= ahd_linux_slave_configure,	.slave_destroy		= ahd_linux_slave_destroy,};/**************************** Tasklet Handler *********************************//* * In 2.4.X and above, this routine is called from a tasklet, * so we must re-acquire our lock prior to executing this code. * In all prior kernels, ahd_schedule_runq() calls this routine * directly and ahd_schedule_runq() is called with our lock held. */static voidahd_runq_tasklet(unsigned long data){	struct ahd_softc* ahd;	struct ahd_linux_device *dev;	u_long flags;	ahd = (struct ahd_softc *)data;	ahd_lock(ahd, &flags);	while ((dev = ahd_linux_next_device_to_run(ahd)) != NULL) {			TAILQ_REMOVE(&ahd->platform_data->device_runq, dev, links);		dev->flags &= ~AHD_DEV_ON_RUN_LIST;		ahd_linux_check_device_queue(ahd, dev);		/* Yeild to our interrupt handler */		ahd_unlock(ahd, &flags);		ahd_lock(ahd, &flags);	}	ahd_unlock(ahd, &flags);}/******************************** Bus DMA *************************************/intahd_dma_tag_create(struct ahd_softc *ahd, bus_dma_tag_t parent,		   bus_size_t alignment, bus_size_t boundary,		   dma_addr_t lowaddr, dma_addr_t highaddr,		   bus_dma_filter_t *filter, void *filterarg,		   bus_size_t maxsize, int nsegments,		   bus_size_t maxsegsz, int flags, bus_dma_tag_t *ret_tag){	bus_dma_tag_t dmat;	dmat = malloc(sizeof(*dmat), M_DEVBUF, M_NOWAIT);	if (dmat == NULL)		return (ENOMEM);	/*	 * Linux is very simplistic about DMA memory.  For now don't	 * maintain all specification information.  Once Linux supplies	 * better facilities for doing these operations, or the	 * needs of this particular driver change, we might need to do	 * more here.	 */	dmat->alignment = alignment;	dmat->boundary = boundary;	dmat->maxsize = maxsize;	*ret_tag = dmat;	return (0);}voidahd_dma_tag_destroy(struct ahd_softc *ahd, bus_dma_tag_t dmat){	free(dmat, M_DEVBUF);}intahd_dmamem_alloc(struct ahd_softc *ahd, bus_dma_tag_t dmat, void** vaddr,		 int flags, bus_dmamap_t *mapp){	bus_dmamap_t map;	map = malloc(sizeof(*map), M_DEVBUF, M_NOWAIT);	if (map == NULL)		return (ENOMEM);	/*	 * Although we can dma data above 4GB, our	 * "consistent" memory is below 4GB for	 * space efficiency reasons (only need a 4byte	 * address).  For this reason, we have to reset	 * our dma mask when doing allocations.	 */	if (ahd->dev_softc != NULL)		if (pci_set_dma_mask(ahd->dev_softc, 0xFFFFFFFF)) {			printk(KERN_WARNING "aic79xx: No suitable DMA available.\n");			kfree(map);			return (ENODEV);		}	*vaddr = pci_alloc_consistent(ahd->dev_softc,				      dmat->maxsize, &map->bus_addr);	if (ahd->dev_softc != NULL)		if (pci_set_dma_mask(ahd->dev_softc,				     ahd->platform_data->hw_dma_mask)) {			printk(KERN_WARNING "aic79xx: No suitable DMA available.\n");			kfree(map);			return (ENODEV);		}	if (*vaddr == NULL)		return (ENOMEM);	*mapp = map;	return(0);}voidahd_dmamem_free(struct ahd_softc *ahd, bus_dma_tag_t dmat,		void* vaddr, bus_dmamap_t map){	pci_free_consistent(ahd->dev_softc, dmat->maxsize,			    vaddr, map->bus_addr);}intahd_dmamap_load(struct ahd_softc *ahd, bus_dma_tag_t dmat, bus_dmamap_t map,		void *buf, bus_size_t buflen, bus_dmamap_callback_t *cb,		void *cb_arg, int flags){	/*	 * Assume for now that this will only be used during	 * initialization and not for per-transaction buffer mapping.	 */	bus_dma_segment_t stack_sg;	stack_sg.ds_addr = map->bus_addr;	stack_sg.ds_len = dmat->maxsize;	cb(cb_arg, &stack_sg, /*nseg*/1, /*error*/0);	return (0);}voidahd_dmamap_destroy(struct ahd_softc *ahd, bus_dma_tag_t dmat, bus_dmamap_t map){	/*	 * The map may is NULL in our < 2.3.X implementation.	 */	if (map != NULL)		free(map, M_DEVBUF);}intahd_dmamap_unload(struct ahd_softc *ahd, bus_dma_tag_t dmat, bus_dmamap_t map){	/* Nothing to do */	return (0);}/********************* Platform Dependent Functions ***************************//* * Compare "left hand" softc with "right hand" softc, returning: * < 0 - lahd has a lower priority than rahd *   0 - Softcs are equal * > 0 - lahd has a higher priority than rahd */intahd_softc_comp(struct ahd_softc *lahd, struct ahd_softc *rahd){	int	value;	/*	 * Under Linux, cards are ordered as follows:	 *	1) PCI devices that are marked as the boot controller.	 *	2) PCI devices with BIOS enabled sorted by bus/slot/func.	 *	3) All remaining PCI devices sorted by bus/slot/func.	 */#if 0	value = (lahd->flags & AHD_BOOT_CHANNEL)	      - (rahd->flags & AHD_BOOT_CHANNEL);	if (value != 0)		/* Controllers set for boot have a *higher* priority */		return (value);#endif	value = (lahd->flags & AHD_BIOS_ENABLED)	      - (rahd->flags & AHD_BIOS_ENABLED);	if (value != 0)		/* Controllers with BIOS enabled have a *higher* priority */		return (value);	/* Still equal.  Sort by bus/slot/func. */	if (aic79xx_reverse_scan != 0)		value = ahd_get_pci_bus(lahd->dev_softc)		      - ahd_get_pci_bus(rahd->dev_softc);	else		value = ahd_get_pci_bus(rahd->dev_softc)		      - ahd_get_pci_bus(lahd->dev_softc);	if (value != 0)		return (value);	if (aic79xx_reverse_scan != 0)		value = ahd_get_pci_slot(lahd->dev_softc)		      - ahd_get_pci_slot(rahd->dev_softc);	else		value = ahd_get_pci_slot(rahd->dev_softc)		      - ahd_get_pci_slot(lahd->dev_softc);	if (value != 0)		return (value);	value = rahd->channel - lahd->channel;	return (value);}static voidahd_linux_setup_tag_info(u_long arg, int instance, int targ, int32_t value){	if ((instance >= 0) && (targ >= 0)	 && (instance < NUM_ELEMENTS(aic79xx_tag_info))	 && (targ < AHD_NUM_TARGETS)) {		aic79xx_tag_info[instance].tag_commands[targ] = value & 0x1FF;		if (bootverbose)			printf("tag_info[%d:%d] = %d\n", instance, targ, value);	}}static voidahd_linux_setup_rd_strm_info(u_long arg, int instance, int targ, int32_t value){	if ((instance >= 0)	 && (instance < NUM_ELEMENTS(aic79xx_rd_strm_info))) {		aic79xx_rd_strm_info[instance] = value & 0xFFFF;		if (bootverbose)			printf("rd_strm[%d] = 0x%x\n", instance, value);	}}static voidahd_linux_setup_dv(u_long arg, int instance, int targ, int32_t value){	if ((instance >= 0)	 && (instance < NUM_ELEMENTS(aic79xx_dv_settings))) {		aic79xx_dv_settings[instance] = value;		if (bootverbose)			printf("dv[%d] = %d\n", instance, value);	}}static voidahd_linux_setup_iocell_info(u_long index, int instance, int targ, int32_t value){	if ((instance >= 0)	 && (instance < NUM_ELEMENTS(aic79xx_iocell_info))) {		uint8_t *iocell_info;		iocell_info = (uint8_t*)&aic79xx_iocell_info[instance];		iocell_info[index] = value & 0xFFFF;		if (bootverbose)			printf("iocell[%d:%ld] = %d\n", instance, index, value);	}}
10457	/local/tlutelli/issta_data/temp/c/2005_temp/2005/10457/60a13213840296b1e32d6781653a0eaa83d04382/aic79xx_osm.c/buggy/drivers/scsi/aic7xxx/aic79xx_osm.c