📄 aic79xx_osm.c
字号:
" Enable verbose logging\n"" Set tag depth on Controller 2/Target 2 to 10 tags\n"" Shorten the selection timeout to 128ms\n""\n"" options aic79xx='\"verbose.tag_info:{{}.{}.{..10}}.seltime:1\"'\n""\n"" Sample /etc/modules.conf line:\n"" Change Read Streaming for Controller's 2 and 3\n""\n"" options aic79xx='\"rd_strm:{..0xFFF0.0xC0F0}\"'");#endifstatic void ahd_linux_handle_scsi_status(struct ahd_softc *, struct ahd_linux_device *, struct scb *);static void ahd_linux_queue_cmd_complete(struct ahd_softc *ahd, Scsi_Cmnd *cmd);static void ahd_linux_filter_inquiry(struct ahd_softc *ahd, struct ahd_devinfo *devinfo);static void ahd_linux_dev_timed_unfreeze(u_long arg);static void ahd_linux_sem_timeout(u_long arg);static void ahd_linux_initialize_scsi_bus(struct ahd_softc *ahd);static void ahd_linux_thread_run_complete_queue(struct ahd_softc *ahd);static void ahd_linux_start_dv(struct ahd_softc *ahd);static void ahd_linux_dv_timeout(struct scsi_cmnd *cmd);static int ahd_linux_dv_thread(void *data);static void ahd_linux_dv_target(struct ahd_softc *ahd, u_int target);static void ahd_linux_dv_transition(struct ahd_softc *ahd, struct scsi_cmnd *cmd, struct ahd_devinfo *devinfo, struct ahd_linux_target *targ);static void ahd_linux_dv_fill_cmd(struct ahd_softc *ahd, struct scsi_cmnd *cmd, struct ahd_devinfo *devinfo);static void ahd_linux_dv_inq(struct ahd_softc *ahd, struct scsi_cmnd *cmd, struct ahd_devinfo *devinfo, struct ahd_linux_target *targ, u_int request_length);static void ahd_linux_dv_tur(struct ahd_softc *ahd, struct scsi_cmnd *cmd, struct ahd_devinfo *devinfo);static void ahd_linux_dv_rebd(struct ahd_softc *ahd, struct scsi_cmnd *cmd, struct ahd_devinfo *devinfo, struct ahd_linux_target *targ);static void ahd_linux_dv_web(struct ahd_softc *ahd, struct scsi_cmnd *cmd, struct ahd_devinfo *devinfo, struct ahd_linux_target *targ);static void ahd_linux_dv_reb(struct ahd_softc *ahd, struct scsi_cmnd *cmd, struct ahd_devinfo *devinfo, struct ahd_linux_target *targ);static void ahd_linux_dv_su(struct ahd_softc *ahd, struct scsi_cmnd *cmd, struct ahd_devinfo *devinfo, struct ahd_linux_target *targ);static __inline int ahd_linux_dv_fallback(struct ahd_softc *ahd, struct ahd_devinfo *devinfo);static int ahd_linux_fallback(struct ahd_softc *ahd, struct ahd_devinfo *devinfo);static __inline int ahd_linux_dv_fallback(struct ahd_softc *ahd, struct ahd_devinfo *devinfo);static void ahd_linux_dv_complete(Scsi_Cmnd *cmd);static void ahd_linux_generate_dv_pattern(struct ahd_linux_target *targ);static u_int ahd_linux_user_tagdepth(struct ahd_softc *ahd, struct ahd_devinfo *devinfo);static u_int ahd_linux_user_dv_setting(struct ahd_softc *ahd);static void ahd_linux_device_queue_depth(struct ahd_softc *ahd, struct ahd_linux_device *dev);static struct ahd_linux_target* ahd_linux_alloc_target(struct ahd_softc*, u_int, u_int);static void ahd_linux_free_target(struct ahd_softc*, struct ahd_linux_target*);static struct ahd_linux_device* ahd_linux_alloc_device(struct ahd_softc*, struct ahd_linux_target*, u_int);static void ahd_linux_free_device(struct ahd_softc*, struct ahd_linux_device*);static void ahd_linux_run_device_queue(struct ahd_softc*, struct ahd_linux_device*);static void ahd_linux_setup_tag_info(char *p, char *end, char *s);static void ahd_linux_setup_tag_info_global(char *p);static void ahd_linux_setup_rd_strm_info(char *p, char *end, char *s);static void ahd_linux_setup_dv(char *p, char *end, char *s);static void ahd_linux_setup_iocell_info(char *p, char *end, char *s, int index);static int ahd_linux_next_unit(void);static void ahd_runq_tasklet(unsigned long data);static int ahd_linux_halt(struct notifier_block *nb, u_long event, void *buf);static int aic79xx_setup(char *c);/****************************** Inlines ***************************************/static __inline void ahd_schedule_completeq(struct ahd_softc *ahd, struct ahd_cmd *acmd);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, struct ahd_cmd *acmd);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 int ahd_linux_map_seg(struct ahd_softc *ahd, struct scb *scb, struct ahd_dma_seg *sg, bus_addr_t addr, bus_size_t len);static __inline voidahd_schedule_completeq(struct ahd_softc *ahd, struct ahd_cmd *acmd){ while (acmd != NULL) { struct ahd_completeq *completeq; struct ahd_cmd *list_cmd; struct ahd_cmd *next_cmd; next_cmd = TAILQ_NEXT(acmd, acmd_links.tqe); completeq = &ahd->platform_data->completeq; list_cmd = TAILQ_FIRST(completeq); while (list_cmd != NULL && acmd_scsi_cmd(list_cmd).serial_number < acmd_scsi_cmd(acmd).serial_number) list_cmd = TAILQ_NEXT(list_cmd, acmd_links.tqe); if (list_cmd != NULL) TAILQ_INSERT_BEFORE(list_cmd, acmd, acmd_links.tqe); else TAILQ_INSERT_TAIL(completeq, acmd, acmd_links.tqe); acmd = next_cmd; } 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); }}static __inline voidahd_schedule_runq(struct ahd_softc *ahd){#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) tasklet_schedule(&ahd->platform_data->runq_tasklet);#else /* * Tasklets are not available, so run inline. */ ahd_runq_tasklet((unsigned long)ahd);#endif}static __inlinevoid ahd_setup_runq_tasklet(struct ahd_softc *ahd){#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) tasklet_init(&ahd->platform_data->runq_tasklet, ahd_runq_tasklet, (unsigned long)ahd);#endif}static __inline voidahd_teardown_runq_tasklet(struct ahd_softc *ahd){#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) tasklet_kill(&ahd->platform_data->runq_tasklet);#endif}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; ahd_done_lock(ahd, &done_flags); with_errors = 0; while (acmd != NULL) { Scsi_Cmnd *cmd; cmd = &acmd_scsi_cmd(acmd); acmd = TAILQ_NEXT(acmd, acmd_links.tqe); 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); 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" */ break; } } 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 = scsi_to_pci_dma_dir(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); }}static __inline intahd_linux_map_seg(struct ahd_softc *ahd, struct scb *scb, struct ahd_dma_seg *sg, bus_addr_t addr, bus_size_t len){ int consumed; if ((scb->sg_count + 1) > AHD_NSEG) panic("Too few segs for dma mapping. " "Increase AHD_NSEG\n"); consumed = 1; sg->addr = ahd_htole32(addr & 0xFFFFFFFF); scb->platform_data->xfer_len += len; if (sizeof(bus_addr_t) > 4 && (ahd->flags & AHD_39BIT_ADDRESSING) != 0) { /* * Due to DAC restrictions, we can't * cross a 4GB boundary. */ if ((addr ^ (addr + len - 1)) & ~0xFFFFFFFF) { struct ahd_dma_seg *next_sg; uint32_t next_len; printf("Crossed Seg\n"); if ((scb->sg_count + 2) > AHD_NSEG) panic("Too few segs for dma mapping. " "Increase AHD_NSEG\n"); consumed++; next_sg = sg + 1; next_sg->addr = 0; next_len = 0x100000000 - (addr & 0xFFFFFFFF); len -= next_len; next_len |= ((addr >> 8) + 0x1000000) & 0x7F000000; next_sg->len = ahd_htole32(next_len); } len |= (addr >> 8) & 0x7F000000; } sg->len = ahd_htole32(len); return (consumed);}/******************************** 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 int ahd_linux_release(struct Scsi_Host *);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 *);static int ahd_linux_biosparam(struct scsi_device*, struct block_device*, sector_t, int[]);#elsestatic void ahd_linux_select_queue_depth(struct Scsi_Host *host, Scsi_Device *scsi_devs);static int ahd_linux_biosparam(Disk *, kdev_t, int[]);#endifstatic int ahd_linux_bus_reset(Scsi_Cmnd *);static int ahd_linux_dev_reset(Scsi_Cmnd *);static int ahd_linux_abort(Scsi_Cmnd *);/* * Try to detect an Adaptec 79XX controller. */static intahd_linux_detect(Scsi_Host_Template *template){ struct ahd_softc *ahd; int found;#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); }#ifdef MODULE /* * If we've been passed any parameters, process them now. */ if (aic79xx) aic79xx_setup(aic79xx); if (dummy_buffer[0] != 'P') printk(KERN_WARNING"aic79xx: Please read the file /usr/src/linux/drivers/scsi/README.aic79xx\n""aic79xx: to see the proper way to specify options to the aic79xx module\n""aic79xx: Specifically, don't use any commas when passing arguments to\n""aic79xx: insmod or else it might trash certain memory areas.\n");#endif#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0) template->proc_name = "aic79xx";#else template->proc_dir = &proc_scsi_aic79xx;#endif /* * Initialize our softc list lock prior to * probing for any adapters. */ ahd_list_lockinit();#ifdef CONFIG_PCI ahd_linux_pci_probe(template);#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 (found);}/* * 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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -