Annotation of qemu/hw/esp.c, revision 1.1.1.4
1.1 root 1: /*
2: * QEMU ESP emulation
3: *
1.1.1.3 root 4: * Copyright (c) 2005-2006 Fabrice Bellard
1.1 root 5: *
6: * Permission is hereby granted, free of charge, to any person obtaining a copy
7: * of this software and associated documentation files (the "Software"), to deal
8: * in the Software without restriction, including without limitation the rights
9: * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10: * copies of the Software, and to permit persons to whom the Software is
11: * furnished to do so, subject to the following conditions:
12: *
13: * The above copyright notice and this permission notice shall be included in
14: * all copies or substantial portions of the Software.
15: *
16: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19: * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21: * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22: * THE SOFTWARE.
23: */
24: #include "vl.h"
25:
26: /* debug ESP card */
27: //#define DEBUG_ESP
28:
29: #ifdef DEBUG_ESP
30: #define DPRINTF(fmt, args...) \
31: do { printf("ESP: " fmt , ##args); } while (0)
1.1.1.2 root 32: #define pic_set_irq(irq, level) \
33: do { printf("ESP: set_irq(%d): %d\n", (irq), (level)); pic_set_irq((irq),(level));} while (0)
1.1 root 34: #else
35: #define DPRINTF(fmt, args...)
36: #endif
37:
38: #define ESPDMA_REGS 4
39: #define ESPDMA_MAXADDR (ESPDMA_REGS * 4 - 1)
40: #define ESP_MAXREG 0x3f
1.1.1.4 ! root 41: #define TI_BUFSZ 32
1.1.1.2 root 42: #define DMA_VER 0xa0000000
43: #define DMA_INTR 1
44: #define DMA_INTREN 0x10
1.1.1.4 ! root 45: #define DMA_WRITE_MEM 0x100
1.1.1.2 root 46: #define DMA_LOADED 0x04000000
1.1.1.3 root 47: typedef struct ESPState ESPState;
1.1 root 48:
1.1.1.3 root 49: struct ESPState {
1.1 root 50: BlockDriverState **bd;
51: uint8_t rregs[ESP_MAXREG];
52: uint8_t wregs[ESP_MAXREG];
53: int irq;
54: uint32_t espdmaregs[ESPDMA_REGS];
55: uint32_t ti_size;
1.1.1.2 root 56: uint32_t ti_rptr, ti_wptr;
57: uint8_t ti_buf[TI_BUFSZ];
1.1.1.4 ! root 58: int sense;
1.1.1.2 root 59: int dma;
1.1.1.4 ! root 60: SCSIDevice *scsi_dev[MAX_DISKS];
! 61: SCSIDevice *current_dev;
! 62: uint8_t cmdbuf[TI_BUFSZ];
! 63: int cmdlen;
! 64: int do_cmd;
1.1.1.3 root 65: };
1.1 root 66:
67: #define STAT_DO 0x00
68: #define STAT_DI 0x01
69: #define STAT_CD 0x02
70: #define STAT_ST 0x03
71: #define STAT_MI 0x06
72: #define STAT_MO 0x07
73:
74: #define STAT_TC 0x10
75: #define STAT_IN 0x80
76:
77: #define INTR_FC 0x08
78: #define INTR_BS 0x10
79: #define INTR_DC 0x20
1.1.1.2 root 80: #define INTR_RST 0x80
1.1 root 81:
82: #define SEQ_0 0x0
83: #define SEQ_CD 0x4
84:
1.1.1.4 ! root 85: static int get_cmd(ESPState *s, uint8_t *buf)
1.1 root 86: {
87: uint32_t dmaptr, dmalen;
88: int target;
89:
90: dmalen = s->wregs[0] | (s->wregs[1] << 8);
1.1.1.2 root 91: target = s->wregs[4] & 7;
1.1.1.4 ! root 92: DPRINTF("get_cmd: len %d target %d\n", dmalen, target);
1.1.1.2 root 93: if (s->dma) {
94: dmaptr = iommu_translate(s->espdmaregs[1]);
1.1.1.4 ! root 95: DPRINTF("DMA Direction: %c, addr 0x%8.8x\n",
! 96: s->espdmaregs[0] & DMA_WRITE_MEM ? 'w': 'r', dmaptr);
1.1.1.2 root 97: cpu_physical_memory_read(dmaptr, buf, dmalen);
98: } else {
99: buf[0] = 0;
100: memcpy(&buf[1], s->ti_buf, dmalen);
101: dmalen++;
102: }
1.1.1.4 ! root 103:
1.1 root 104: s->ti_size = 0;
1.1.1.2 root 105: s->ti_rptr = 0;
106: s->ti_wptr = 0;
1.1 root 107:
1.1.1.4 ! root 108: if (target >= 4 || !s->scsi_dev[target]) {
! 109: // No such drive
1.1 root 110: s->rregs[4] = STAT_IN;
111: s->rregs[5] = INTR_DC;
112: s->rregs[6] = SEQ_0;
1.1.1.2 root 113: s->espdmaregs[0] |= DMA_INTR;
1.1 root 114: pic_set_irq(s->irq, 1);
1.1.1.4 ! root 115: return 0;
1.1 root 116: }
1.1.1.4 ! root 117: s->current_dev = s->scsi_dev[target];
! 118: return dmalen;
! 119: }
! 120:
! 121: static void do_cmd(ESPState *s, uint8_t *buf)
! 122: {
! 123: int32_t datalen;
! 124: int lun;
! 125:
! 126: DPRINTF("do_cmd: busid 0x%x\n", buf[0]);
! 127: lun = buf[0] & 7;
! 128: datalen = scsi_send_command(s->current_dev, 0, &buf[1], lun);
! 129: if (datalen == 0) {
! 130: s->ti_size = 0;
! 131: } else {
! 132: s->rregs[4] = STAT_IN | STAT_TC;
! 133: if (datalen > 0) {
! 134: s->rregs[4] |= STAT_DI;
! 135: s->ti_size = datalen;
! 136: } else {
! 137: s->rregs[4] |= STAT_DO;
! 138: s->ti_size = -datalen;
1.1.1.2 root 139: }
1.1 root 140: }
141: s->rregs[5] = INTR_BS | INTR_FC;
142: s->rregs[6] = SEQ_CD;
1.1.1.2 root 143: s->espdmaregs[0] |= DMA_INTR;
1.1 root 144: pic_set_irq(s->irq, 1);
145: }
146:
1.1.1.4 ! root 147: static void handle_satn(ESPState *s)
! 148: {
! 149: uint8_t buf[32];
! 150: int len;
! 151:
! 152: len = get_cmd(s, buf);
! 153: if (len)
! 154: do_cmd(s, buf);
! 155: }
! 156:
! 157: static void handle_satn_stop(ESPState *s)
1.1 root 158: {
1.1.1.4 ! root 159: s->cmdlen = get_cmd(s, s->cmdbuf);
! 160: if (s->cmdlen) {
! 161: DPRINTF("Set ATN & Stop: cmdlen %d\n", s->cmdlen);
! 162: s->do_cmd = 1;
! 163: s->espdmaregs[1] += s->cmdlen;
! 164: s->rregs[4] = STAT_IN | STAT_TC | STAT_CD;
! 165: s->rregs[5] = INTR_BS | INTR_FC;
! 166: s->rregs[6] = SEQ_CD;
! 167: s->espdmaregs[0] |= DMA_INTR;
! 168: pic_set_irq(s->irq, 1);
! 169: }
! 170: }
1.1 root 171:
1.1.1.4 ! root 172: static void write_response(ESPState *s)
! 173: {
! 174: uint32_t dmaptr;
! 175:
! 176: DPRINTF("Transfer status (sense=%d)\n", s->sense);
! 177: s->ti_buf[0] = s->sense;
! 178: s->ti_buf[1] = 0;
1.1.1.2 root 179: if (s->dma) {
180: dmaptr = iommu_translate(s->espdmaregs[1]);
1.1.1.4 ! root 181: DPRINTF("DMA Direction: %c\n",
! 182: s->espdmaregs[0] & DMA_WRITE_MEM ? 'w': 'r');
! 183: cpu_physical_memory_write(dmaptr, s->ti_buf, 2);
1.1.1.2 root 184: s->rregs[4] = STAT_IN | STAT_TC | STAT_ST;
185: s->rregs[5] = INTR_BS | INTR_FC;
186: s->rregs[6] = SEQ_CD;
187: } else {
1.1.1.4 ! root 188: s->ti_size = 2;
1.1.1.2 root 189: s->ti_rptr = 0;
190: s->ti_wptr = 0;
1.1.1.4 ! root 191: s->rregs[7] = 2;
1.1.1.2 root 192: }
193: s->espdmaregs[0] |= DMA_INTR;
1.1 root 194: pic_set_irq(s->irq, 1);
195:
196: }
1.1.1.2 root 197:
1.1.1.4 ! root 198: static void esp_command_complete(void *opaque, uint32_t tag, int sense)
! 199: {
! 200: ESPState *s = (ESPState *)opaque;
! 201:
! 202: DPRINTF("SCSI Command complete\n");
! 203: if (s->ti_size != 0)
! 204: DPRINTF("SCSI command completed unexpectedly\n");
! 205: s->ti_size = 0;
! 206: if (sense)
! 207: DPRINTF("Command failed\n");
! 208: s->sense = sense;
! 209: s->rregs[4] = STAT_IN | STAT_TC | STAT_ST;
! 210: }
1.1 root 211:
212: static void handle_ti(ESPState *s)
213: {
1.1.1.4 ! root 214: uint32_t dmaptr, dmalen, minlen, len, from, to;
1.1 root 215: unsigned int i;
1.1.1.4 ! root 216: int to_device;
! 217: uint8_t buf[TARGET_PAGE_SIZE];
1.1 root 218:
219: dmalen = s->wregs[0] | (s->wregs[1] << 8);
1.1.1.4 ! root 220: if (dmalen==0) {
! 221: dmalen=0x10000;
! 222: }
! 223:
! 224: if (s->do_cmd)
! 225: minlen = (dmalen < 32) ? dmalen : 32;
! 226: else
! 227: minlen = (dmalen < s->ti_size) ? dmalen : s->ti_size;
! 228: DPRINTF("Transfer Information len %d\n", minlen);
1.1.1.2 root 229: if (s->dma) {
230: dmaptr = iommu_translate(s->espdmaregs[1]);
1.1.1.4 ! root 231: /* Check if the transfer writes to to reads from the device. */
! 232: to_device = (s->espdmaregs[0] & DMA_WRITE_MEM) == 0;
! 233: DPRINTF("DMA Direction: %c, addr 0x%8.8x %08x\n",
! 234: to_device ? 'r': 'w', dmaptr, s->ti_size);
! 235: from = s->espdmaregs[1];
! 236: to = from + minlen;
! 237: for (i = 0; i < minlen; i += len, from += len) {
1.1.1.2 root 238: dmaptr = iommu_translate(s->espdmaregs[1] + i);
1.1.1.4 ! root 239: if ((from & TARGET_PAGE_MASK) != (to & TARGET_PAGE_MASK)) {
! 240: len = TARGET_PAGE_SIZE - (from & ~TARGET_PAGE_MASK);
! 241: } else {
! 242: len = to - from;
! 243: }
! 244: DPRINTF("DMA address p %08x v %08x len %08x, from %08x, to %08x\n", dmaptr, s->espdmaregs[1] + i, len, from, to);
! 245: s->ti_size -= len;
! 246: if (s->do_cmd) {
! 247: DPRINTF("command len %d + %d\n", s->cmdlen, len);
! 248: cpu_physical_memory_read(dmaptr, &s->cmdbuf[s->cmdlen], len);
! 249: s->ti_size = 0;
! 250: s->cmdlen = 0;
! 251: s->do_cmd = 0;
! 252: do_cmd(s, s->cmdbuf);
! 253: return;
! 254: } else {
! 255: if (to_device) {
! 256: cpu_physical_memory_read(dmaptr, buf, len);
! 257: scsi_write_data(s->current_dev, buf, len);
! 258: } else {
! 259: scsi_read_data(s->current_dev, buf, len);
! 260: cpu_physical_memory_write(dmaptr, buf, len);
! 261: }
! 262: }
1.1.1.3 root 263: }
1.1.1.4 ! root 264: if (s->ti_size) {
! 265: s->rregs[4] = STAT_IN | STAT_TC | (to_device ? STAT_DO : STAT_DI);
! 266: }
! 267: s->rregs[5] = INTR_BS;
1.1.1.2 root 268: s->rregs[6] = 0;
1.1.1.4 ! root 269: s->rregs[7] = 0;
1.1.1.2 root 270: s->espdmaregs[0] |= DMA_INTR;
1.1.1.4 ! root 271: } else if (s->do_cmd) {
! 272: DPRINTF("command len %d\n", s->cmdlen);
! 273: s->ti_size = 0;
! 274: s->cmdlen = 0;
! 275: s->do_cmd = 0;
! 276: do_cmd(s, s->cmdbuf);
! 277: return;
! 278: }
1.1 root 279: pic_set_irq(s->irq, 1);
280: }
281:
282: static void esp_reset(void *opaque)
283: {
284: ESPState *s = opaque;
285: memset(s->rregs, 0, ESP_MAXREG);
1.1.1.3 root 286: memset(s->wregs, 0, ESP_MAXREG);
1.1 root 287: s->rregs[0x0e] = 0x4; // Indicate fas100a
288: memset(s->espdmaregs, 0, ESPDMA_REGS * 4);
1.1.1.3 root 289: s->ti_size = 0;
290: s->ti_rptr = 0;
291: s->ti_wptr = 0;
292: s->dma = 0;
1.1.1.4 ! root 293: s->do_cmd = 0;
1.1 root 294: }
295:
296: static uint32_t esp_mem_readb(void *opaque, target_phys_addr_t addr)
297: {
298: ESPState *s = opaque;
299: uint32_t saddr;
300:
301: saddr = (addr & ESP_MAXREG) >> 2;
1.1.1.2 root 302: DPRINTF("read reg[%d]: 0x%2.2x\n", saddr, s->rregs[saddr]);
1.1 root 303: switch (saddr) {
1.1.1.2 root 304: case 2:
305: // FIFO
306: if (s->ti_size > 0) {
307: s->ti_size--;
1.1.1.4 ! root 308: if ((s->rregs[4] & 6) == 0) {
! 309: /* Data in/out. */
! 310: scsi_read_data(s->current_dev, &s->rregs[2], 0);
! 311: } else {
! 312: s->rregs[2] = s->ti_buf[s->ti_rptr++];
! 313: }
1.1.1.2 root 314: pic_set_irq(s->irq, 1);
315: }
316: if (s->ti_size == 0) {
317: s->ti_rptr = 0;
318: s->ti_wptr = 0;
319: }
320: break;
321: case 5:
322: // interrupt
323: // Clear status bits except TC
324: s->rregs[4] &= STAT_TC;
325: pic_set_irq(s->irq, 0);
326: s->espdmaregs[0] &= ~DMA_INTR;
327: break;
1.1 root 328: default:
329: break;
330: }
331: return s->rregs[saddr];
332: }
333:
334: static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
335: {
336: ESPState *s = opaque;
337: uint32_t saddr;
338:
339: saddr = (addr & ESP_MAXREG) >> 2;
340: DPRINTF("write reg[%d]: 0x%2.2x -> 0x%2.2x\n", saddr, s->wregs[saddr], val);
341: switch (saddr) {
1.1.1.2 root 342: case 0:
343: case 1:
344: s->rregs[saddr] = val;
345: break;
346: case 2:
347: // FIFO
1.1.1.4 ! root 348: if (s->do_cmd) {
! 349: s->cmdbuf[s->cmdlen++] = val & 0xff;
! 350: } else if ((s->rregs[4] & 6) == 0) {
! 351: uint8_t buf;
! 352: buf = val & 0xff;
! 353: s->ti_size--;
! 354: scsi_write_data(s->current_dev, &buf, 0);
! 355: } else {
! 356: s->ti_size++;
! 357: s->ti_buf[s->ti_wptr++] = val & 0xff;
! 358: }
1.1.1.2 root 359: break;
1.1 root 360: case 3:
1.1.1.2 root 361: s->rregs[saddr] = val;
1.1 root 362: // Command
1.1.1.2 root 363: if (val & 0x80) {
364: s->dma = 1;
365: } else {
366: s->dma = 0;
367: }
1.1 root 368: switch(val & 0x7f) {
369: case 0:
370: DPRINTF("NOP (%2.2x)\n", val);
371: break;
372: case 1:
373: DPRINTF("Flush FIFO (%2.2x)\n", val);
1.1.1.2 root 374: //s->ti_size = 0;
1.1 root 375: s->rregs[5] = INTR_FC;
1.1.1.2 root 376: s->rregs[6] = 0;
1.1 root 377: break;
378: case 2:
379: DPRINTF("Chip reset (%2.2x)\n", val);
380: esp_reset(s);
381: break;
382: case 3:
383: DPRINTF("Bus reset (%2.2x)\n", val);
1.1.1.2 root 384: s->rregs[5] = INTR_RST;
385: if (!(s->wregs[8] & 0x40)) {
386: s->espdmaregs[0] |= DMA_INTR;
387: pic_set_irq(s->irq, 1);
388: }
1.1 root 389: break;
390: case 0x10:
391: handle_ti(s);
392: break;
393: case 0x11:
394: DPRINTF("Initiator Command Complete Sequence (%2.2x)\n", val);
1.1.1.4 ! root 395: write_response(s);
1.1 root 396: break;
397: case 0x12:
398: DPRINTF("Message Accepted (%2.2x)\n", val);
1.1.1.4 ! root 399: write_response(s);
1.1 root 400: s->rregs[5] = INTR_DC;
401: s->rregs[6] = 0;
402: break;
403: case 0x1a:
404: DPRINTF("Set ATN (%2.2x)\n", val);
405: break;
406: case 0x42:
1.1.1.4 ! root 407: DPRINTF("Set ATN (%2.2x)\n", val);
1.1 root 408: handle_satn(s);
409: break;
410: case 0x43:
411: DPRINTF("Set ATN & stop (%2.2x)\n", val);
1.1.1.4 ! root 412: handle_satn_stop(s);
1.1 root 413: break;
414: default:
1.1.1.2 root 415: DPRINTF("Unhandled ESP command (%2.2x)\n", val);
1.1 root 416: break;
417: }
418: break;
419: case 4 ... 7:
420: break;
1.1.1.2 root 421: case 8:
422: s->rregs[saddr] = val;
423: break;
424: case 9 ... 10:
425: break;
426: case 11:
427: s->rregs[saddr] = val & 0x15;
428: break;
429: case 12 ... 15:
430: s->rregs[saddr] = val;
431: break;
1.1 root 432: default:
433: break;
434: }
435: s->wregs[saddr] = val;
436: }
437:
438: static CPUReadMemoryFunc *esp_mem_read[3] = {
439: esp_mem_readb,
440: esp_mem_readb,
441: esp_mem_readb,
442: };
443:
444: static CPUWriteMemoryFunc *esp_mem_write[3] = {
445: esp_mem_writeb,
446: esp_mem_writeb,
447: esp_mem_writeb,
448: };
449:
450: static uint32_t espdma_mem_readl(void *opaque, target_phys_addr_t addr)
451: {
452: ESPState *s = opaque;
453: uint32_t saddr;
454:
455: saddr = (addr & ESPDMA_MAXADDR) >> 2;
1.1.1.2 root 456: DPRINTF("read dmareg[%d]: 0x%8.8x\n", saddr, s->espdmaregs[saddr]);
457:
1.1 root 458: return s->espdmaregs[saddr];
459: }
460:
461: static void espdma_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
462: {
463: ESPState *s = opaque;
464: uint32_t saddr;
465:
466: saddr = (addr & ESPDMA_MAXADDR) >> 2;
1.1.1.2 root 467: DPRINTF("write dmareg[%d]: 0x%8.8x -> 0x%8.8x\n", saddr, s->espdmaregs[saddr], val);
1.1 root 468: switch (saddr) {
469: case 0:
1.1.1.2 root 470: if (!(val & DMA_INTREN))
1.1 root 471: pic_set_irq(s->irq, 0);
1.1.1.2 root 472: if (val & 0x80) {
473: esp_reset(s);
474: } else if (val & 0x40) {
475: val &= ~0x40;
476: } else if (val == 0)
477: val = 0x40;
478: val &= 0x0fffffff;
479: val |= DMA_VER;
480: break;
481: case 1:
1.1.1.4 ! root 482: s->espdmaregs[0] |= DMA_LOADED;
1.1.1.2 root 483: break;
1.1 root 484: default:
485: break;
486: }
487: s->espdmaregs[saddr] = val;
488: }
489:
490: static CPUReadMemoryFunc *espdma_mem_read[3] = {
491: espdma_mem_readl,
492: espdma_mem_readl,
493: espdma_mem_readl,
494: };
495:
496: static CPUWriteMemoryFunc *espdma_mem_write[3] = {
497: espdma_mem_writel,
498: espdma_mem_writel,
499: espdma_mem_writel,
500: };
501:
502: static void esp_save(QEMUFile *f, void *opaque)
503: {
504: ESPState *s = opaque;
505: unsigned int i;
506:
507: qemu_put_buffer(f, s->rregs, ESP_MAXREG);
508: qemu_put_buffer(f, s->wregs, ESP_MAXREG);
509: qemu_put_be32s(f, &s->irq);
510: for (i = 0; i < ESPDMA_REGS; i++)
511: qemu_put_be32s(f, &s->espdmaregs[i]);
1.1.1.2 root 512: qemu_put_be32s(f, &s->ti_size);
513: qemu_put_be32s(f, &s->ti_rptr);
514: qemu_put_be32s(f, &s->ti_wptr);
515: qemu_put_buffer(f, s->ti_buf, TI_BUFSZ);
516: qemu_put_be32s(f, &s->dma);
1.1 root 517: }
518:
519: static int esp_load(QEMUFile *f, void *opaque, int version_id)
520: {
521: ESPState *s = opaque;
522: unsigned int i;
523:
524: if (version_id != 1)
525: return -EINVAL;
526:
527: qemu_get_buffer(f, s->rregs, ESP_MAXREG);
528: qemu_get_buffer(f, s->wregs, ESP_MAXREG);
529: qemu_get_be32s(f, &s->irq);
530: for (i = 0; i < ESPDMA_REGS; i++)
531: qemu_get_be32s(f, &s->espdmaregs[i]);
1.1.1.2 root 532: qemu_get_be32s(f, &s->ti_size);
533: qemu_get_be32s(f, &s->ti_rptr);
534: qemu_get_be32s(f, &s->ti_wptr);
535: qemu_get_buffer(f, s->ti_buf, TI_BUFSZ);
536: qemu_get_be32s(f, &s->dma);
1.1 root 537:
538: return 0;
539: }
540:
541: void esp_init(BlockDriverState **bd, int irq, uint32_t espaddr, uint32_t espdaddr)
542: {
543: ESPState *s;
544: int esp_io_memory, espdma_io_memory;
1.1.1.4 ! root 545: int i;
1.1 root 546:
547: s = qemu_mallocz(sizeof(ESPState));
548: if (!s)
549: return;
550:
551: s->bd = bd;
552: s->irq = irq;
553:
554: esp_io_memory = cpu_register_io_memory(0, esp_mem_read, esp_mem_write, s);
555: cpu_register_physical_memory(espaddr, ESP_MAXREG*4, esp_io_memory);
556:
557: espdma_io_memory = cpu_register_io_memory(0, espdma_mem_read, espdma_mem_write, s);
558: cpu_register_physical_memory(espdaddr, 16, espdma_io_memory);
559:
560: esp_reset(s);
561:
562: register_savevm("esp", espaddr, 1, esp_save, esp_load, s);
563: qemu_register_reset(esp_reset, s);
1.1.1.4 ! root 564: for (i = 0; i < MAX_DISKS; i++) {
! 565: if (bs_table[i]) {
! 566: s->scsi_dev[i] =
! 567: scsi_disk_init(bs_table[i], esp_command_complete, s);
! 568: }
! 569: }
1.1 root 570: }
571:
unix.superglobalmegacorp.com