sgiwd93.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:10k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  * sgiwd93.c: SGI WD93 scsi driver.
  3.  *
  4.  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
  5.  *  1999 Andrew R. Baker (andrewb@uab.edu)
  6.  *       - Support for 2nd SCSI controller on Indigo2
  7.  * 
  8.  * (In all truth, Jed Schimmel wrote all this code.)
  9.  *
  10.  * $Id: sgiwd93.c,v 1.19 2000/02/04 07:40:47 ralf Exp $
  11.  */
  12. #include <linux/init.h>
  13. #include <linux/types.h>
  14. #include <linux/mm.h>
  15. #include <linux/blk.h>
  16. #include <linux/version.h>
  17. #include <linux/delay.h>
  18. #include <linux/spinlock.h>
  19. #include <asm/page.h>
  20. #include <asm/pgtable.h>
  21. #include <asm/sgialib.h>
  22. #include <asm/sgi/sgi.h>
  23. #include <asm/sgi/sgimc.h>
  24. #include <asm/sgi/sgihpc.h>
  25. #include <asm/sgi/sgint23.h>
  26. #include <asm/irq.h>
  27. #include <asm/io.h>
  28. #include "scsi.h"
  29. #include "hosts.h"
  30. #include "wd33c93.h"
  31. #include "sgiwd93.h"
  32. #include <linux/stat.h>
  33. struct hpc_chunk {
  34. struct hpc_dma_desc desc;
  35. unsigned long padding;
  36. };
  37. struct Scsi_Host *sgiwd93_host = NULL;
  38. struct Scsi_Host *sgiwd93_host1 = NULL;
  39. /* Wuff wuff, wuff, wd33c93.c, wuff wuff, object oriented, bow wow. */
  40. static inline void write_wd33c93_count(wd33c93_regs *regp, unsigned long value)
  41. {
  42. regp->SASR = WD_TRANSFER_COUNT_MSB;
  43. regp->SCMD = ((value >> 16) & 0xff);
  44. regp->SCMD = ((value >>  8) & 0xff);
  45. regp->SCMD = ((value >>  0) & 0xff);
  46. }
  47. static inline unsigned long read_wd33c93_count(wd33c93_regs *regp)
  48. {
  49. unsigned long value;
  50. regp->SASR = WD_TRANSFER_COUNT_MSB;
  51. value =  ((regp->SCMD & 0xff) << 16);
  52. value |= ((regp->SCMD & 0xff) <<  8);
  53. value |= ((regp->SCMD & 0xff) <<  0);
  54. return value;
  55. }
  56. /* XXX woof! */
  57. static void sgiwd93_intr(int irq, void *dev_id, struct pt_regs *regs)
  58. {
  59. unsigned long flags;
  60. spin_lock_irqsave(&io_request_lock, flags);
  61. wd33c93_intr((struct Scsi_Host *) dev_id);
  62. spin_unlock_irqrestore(&io_request_lock, flags);
  63. }
  64. #undef DEBUG_DMA
  65. static inline
  66. void fill_hpc_entries (struct hpc_chunk **hcp, char *addr, unsigned long len)
  67. {
  68. unsigned long physaddr;
  69. unsigned long count;
  70. dma_cache_wback_inv((unsigned long)addr,len);
  71. physaddr = PHYSADDR(addr);
  72. while (len) {
  73. /*
  74.  * even cntinfo could be up to 16383, without
  75.  * magic only 8192 works correctly
  76.  */
  77. count = len > 8192 ? 8192 : len;
  78. (*hcp)->desc.pbuf = physaddr;
  79. (*hcp)->desc.cntinfo = count;
  80. (*hcp)++;
  81. len -= count;
  82. physaddr += count;
  83. }
  84. }
  85. static int dma_setup(Scsi_Cmnd *cmd, int datainp)
  86. {
  87. struct WD33C93_hostdata *hdata = (struct WD33C93_hostdata *)cmd->host->hostdata;
  88. wd33c93_regs *regp = hdata->regp;
  89. struct hpc3_scsiregs *hregs = (struct hpc3_scsiregs *) cmd->host->base;
  90. struct hpc_chunk *hcp = (struct hpc_chunk *) hdata->dma_bounce_buffer;
  91. #ifdef DEBUG_DMA
  92. printk("dma_setup: datainp<%d> hcp<%p> ",
  93.        datainp, hcp);
  94. #endif
  95. hdata->dma_dir = datainp;
  96. if(cmd->SCp.buffers_residual) {
  97. struct scatterlist *slp = cmd->SCp.buffer;
  98. int i, totlen = 0;
  99. #ifdef DEBUG_DMA
  100. printk("SCLIST<");
  101. #endif
  102. for(i = 0; i <= cmd->SCp.buffers_residual; i++) {
  103. #ifdef DEBUG_DMA
  104. printk("[%p,%d]", slp[i].address, slp[i].length);
  105. #endif
  106. fill_hpc_entries (&hcp, slp[i].address, slp[i].length);
  107. totlen += slp[i].length;
  108. }
  109. #ifdef DEBUG_DMA
  110. printk(">tlen<%d>", totlen);
  111. #endif
  112. hdata->dma_bounce_len = totlen; /* a trick... */
  113. write_wd33c93_count(regp, totlen);
  114. } else {
  115. /* Non-scattered dma. */
  116. #ifdef DEBUG_DMA
  117. printk("ONEBUF<%p,%d>", cmd->SCp.ptr, cmd->SCp.this_residual);
  118. #endif
  119. /*
  120.  * wd33c93 shouldn't pass us bogus dma_setups, but
  121.  * it does:-( The other wd33c93 drivers deal with
  122.  * it the same way (which isn't that obvious).
  123.  * IMHO a better fix would be, not to do these
  124.  * dma setups in the first place
  125.  */
  126. if (cmd->SCp.ptr == NULL)
  127. return 1;
  128. fill_hpc_entries (&hcp, cmd->SCp.ptr,cmd->SCp.this_residual);
  129. write_wd33c93_count(regp, cmd->SCp.this_residual);
  130. }
  131. /* To make sure, if we trip an HPC bug, that we transfer
  132.  * every single byte, we tag on an extra zero length dma
  133.  * descriptor at the end of the chain.
  134.  */
  135. hcp->desc.pbuf = 0;
  136. hcp->desc.cntinfo = (HPCDMA_EOX);
  137. #ifdef DEBUG_DMA
  138. printk(" HPCGOn");
  139. #endif
  140. /* Start up the HPC. */
  141. hregs->ndptr = PHYSADDR(hdata->dma_bounce_buffer);
  142. if(datainp)
  143. hregs->ctrl = (HPC3_SCTRL_ACTIVE);
  144. else
  145. hregs->ctrl = (HPC3_SCTRL_ACTIVE | HPC3_SCTRL_DIR);
  146. return 0;
  147. }
  148. static void dma_stop(struct Scsi_Host *instance, Scsi_Cmnd *SCpnt,
  149.      int status)
  150. {
  151. struct WD33C93_hostdata *hdata = (struct WD33C93_hostdata *)instance->hostdata;
  152. wd33c93_regs *regp = hdata->regp;
  153. struct hpc3_scsiregs *hregs;
  154. if (!SCpnt)
  155. return;
  156. hregs = (struct hpc3_scsiregs *) SCpnt->host->base;
  157. #ifdef DEBUG_DMA
  158. printk("dma_stop: status<%d> ", status);
  159. #endif
  160. /* First stop the HPC and flush it's FIFO. */
  161. if(hdata->dma_dir) {
  162. hregs->ctrl |= HPC3_SCTRL_FLUSH;
  163. while(hregs->ctrl & HPC3_SCTRL_ACTIVE)
  164. barrier();
  165. }
  166. hregs->ctrl = 0;
  167. /* See how far we got and update scatterlist state if necessary. */
  168. if(SCpnt->SCp.buffers_residual) {
  169. struct scatterlist *slp = SCpnt->SCp.buffer;
  170. int totlen, wd93_residual, transferred, i;
  171. /* Yep, we were doing the scatterlist thang. */
  172. totlen = hdata->dma_bounce_len;
  173. wd93_residual = read_wd33c93_count(regp);
  174. transferred = totlen - wd93_residual;
  175. #ifdef DEBUG_DMA
  176. printk("tlen<%d>resid<%d>transf<%d> ",
  177.        totlen, wd93_residual, transferred);
  178. #endif
  179. /* Avoid long winded partial-transfer search for common case. */
  180. if(transferred != totlen) {
  181. /* This is the nut case. */
  182. #ifdef DEBUG_DMA
  183. printk("Jed was here...");
  184. #endif
  185. for(i = 0; i <= SCpnt->SCp.buffers_residual; i++) {
  186. if(slp[i].length >= transferred)
  187. break;
  188. transferred -= slp[i].length;
  189. }
  190. } else {
  191. /* This is the common case. */
  192. #ifdef DEBUG_DMA
  193. printk("did it all...");
  194. #endif
  195. i = SCpnt->SCp.buffers_residual;
  196. }
  197. SCpnt->SCp.buffer = &slp[i];
  198. SCpnt->SCp.buffers_residual = SCpnt->SCp.buffers_residual - i;
  199. SCpnt->SCp.ptr = (char *) slp[i].address;
  200. SCpnt->SCp.this_residual = slp[i].length;
  201. }
  202. #ifdef DEBUG_DMA
  203. printk("n");
  204. #endif
  205. }
  206. void sgiwd93_reset(unsigned long base)
  207. {
  208. struct hpc3_scsiregs *hregs = (struct hpc3_scsiregs *) base;
  209. hregs->ctrl = HPC3_SCTRL_CRESET;
  210. udelay (50);
  211. hregs->ctrl = 0;
  212. }
  213. static inline void init_hpc_chain(uchar *buf)
  214. {
  215. struct hpc_chunk *hcp = (struct hpc_chunk *) buf;
  216. unsigned long start, end;
  217. start = (unsigned long) buf;
  218. end = start + PAGE_SIZE;
  219. while(start < end) {
  220. hcp->desc.pnext = PHYSADDR((hcp + 1));
  221. hcp->desc.cntinfo = HPCDMA_EOX;
  222. hcp++;
  223. start += sizeof(struct hpc_chunk);
  224. };
  225. hcp--;
  226. hcp->desc.pnext = PHYSADDR(buf);
  227. }
  228. int __init sgiwd93_detect(Scsi_Host_Template *SGIblows)
  229. {
  230. static unsigned char called = 0;
  231. struct hpc3_scsiregs *hregs = &hpc3c0->scsi_chan0;
  232. struct hpc3_scsiregs *hregs1 = &hpc3c0->scsi_chan1;
  233. struct WD33C93_hostdata *hdata;
  234. struct WD33C93_hostdata *hdata1;
  235. uchar *buf;
  236. if(called)
  237. return 0; /* Should bitch on the console about this... */
  238. SGIblows->proc_name = "SGIWD93";
  239. sgiwd93_host = scsi_register(SGIblows, sizeof(struct WD33C93_hostdata));
  240. if(sgiwd93_host == NULL)
  241. return 0;
  242. sgiwd93_host->base = (unsigned long) hregs;
  243. sgiwd93_host->irq = SGI_WD93_0_IRQ;
  244. buf = (uchar *) get_free_page(GFP_KERNEL);
  245. if (!buf) {
  246. printk(KERN_WARNING "sgiwd93: Could not allocate memory for host0 buffer.n");
  247. scsi_unregister(sgiwd93_host);
  248. return 0;
  249. }
  250. init_hpc_chain(buf);
  251. dma_cache_wback_inv((unsigned long) buf, PAGE_SIZE);
  252. /* HPC_SCSI_REG0 | 0x03 | KSEG1 */
  253. wd33c93_init(sgiwd93_host, (wd33c93_regs *) KSEG1ADDR (0x1fbc0003),
  254.      dma_setup, dma_stop, WD33C93_FS_16_20);
  255. hdata = (struct WD33C93_hostdata *)sgiwd93_host->hostdata;
  256. hdata->no_sync = 0;
  257. hdata->dma_bounce_buffer = (uchar *) (KSEG1ADDR(buf));
  258. if (request_irq(SGI_WD93_0_IRQ, sgiwd93_intr, 0, "SGI WD93", (void *) sgiwd93_host)) {
  259. printk(KERN_WARNING "sgiwd93: Could not register IRQ %d (for host 0).n", SGI_WD93_0_IRQ);
  260. #ifdef MODULE
  261. wd33c93_release();
  262. #endif
  263. free_page((unsigned long)buf);
  264. scsi_unregister(sgiwd93_host);
  265. return 0;
  266. }
  267.         /* set up second controller on the Indigo2 */
  268. if(!sgi_guiness) {
  269. sgiwd93_host1 = scsi_register(SGIblows, sizeof(struct WD33C93_hostdata));
  270. if(sgiwd93_host1 != NULL)
  271. {
  272. sgiwd93_host1->base = (unsigned long) hregs1;
  273. sgiwd93_host1->irq = SGI_WD93_1_IRQ;
  274. buf = (uchar *) get_free_page(GFP_KERNEL);
  275. if (!buf) {
  276. printk(KERN_WARNING "sgiwd93: Could not allocate memory for host1 buffer.n");
  277. scsi_unregister(sgiwd93_host1);
  278. called = 1;
  279. return 1; /* We registered host0 so return success*/
  280. }
  281. init_hpc_chain(buf);
  282. dma_cache_wback_inv((unsigned long) buf, PAGE_SIZE);
  283. /* HPC_SCSI_REG1 | 0x03 | KSEG1 */
  284. wd33c93_init(sgiwd93_host1, (wd33c93_regs *) KSEG1ADDR (0x1fbc8003),
  285.      dma_setup, dma_stop, WD33C93_FS_16_20);
  286. hdata1 = (struct WD33C93_hostdata *)sgiwd93_host1->hostdata;
  287. hdata1->no_sync = 0;
  288. hdata1->dma_bounce_buffer = (uchar *) (KSEG1ADDR(buf));
  289. dma_cache_wback_inv((unsigned long) buf, PAGE_SIZE);
  290. if (request_irq(SGI_WD93_1_IRQ, sgiwd93_intr, 0, "SGI WD93", (void *) sgiwd93_host1)) {
  291. printk(KERN_WARNING "sgiwd93: Could not allocate irq %d (for host1).n", SGI_WD93_1_IRQ);
  292. #ifdef MODULE
  293. wd33c93_release();
  294. #endif
  295. free_page((unsigned long)buf);
  296. scsi_unregister(sgiwd93_host1);
  297. /* Fall through since host0 registered OK */
  298. }
  299. }
  300. }
  301. called = 1;
  302. return 1; /* Found one. */
  303. }
  304. #define HOSTS_C
  305. #include "sgiwd93.h"
  306. static Scsi_Host_Template driver_template = SGIWD93_SCSI;
  307. #include "scsi_module.c"
  308. int sgiwd93_release(struct Scsi_Host *instance)
  309. {
  310. #ifdef MODULE
  311. free_irq(SGI_WD93_0_IRQ, sgiwd93_intr);
  312. free_page(KSEG0ADDR(hdata->dma_bounce_buffer));
  313. wd33c93_release();
  314. if(!sgi_guiness) {
  315. free_irq(SGI_WD93_1_IRQ, sgiwd93_intr);
  316. free_page(KSEG0ADDR(hdata1->dma_bounce_buffer));
  317. wd33c93_release();
  318. }
  319. #endif
  320. return 1;
  321. }