Wed Jan 9 13:35:45 CET 2002 Index: cardbus/fwohci_cardbus.c =================================================================== RCS file: /cvsroot/syssrc/sys/dev/cardbus/fwohci_cardbus.c,v retrieving revision 1.4 diff -w -u -r1.4 fwohci_cardbus.c --- fwohci_cardbus.c 2001/12/29 12:26:32 1.4 +++ fwohci_cardbus.c 2002/01/09 12:26:39 @@ -46,9 +46,7 @@ #include -#if defined pciinc #include -#endif #include #include @@ -64,6 +62,7 @@ cardbus_function_tag_t sc_cf; cardbus_devfunc_t sc_ct; void *sc_ih; + bus_addr_t sc_base_reg; }; static int fwohci_cardbus_match(struct device *, struct cfdata *, void *); @@ -113,7 +112,7 @@ if (Cardbus_mapreg_map(ct, CARDBUS_OHCI_MAP_REGISTER, CARDBUS_MAPREG_TYPE_MEM, 0, &sc->sc_sc.sc_memt, &sc->sc_sc.sc_memh, - NULL, &sc->sc_sc.sc_memsize)) { + &sc->sc_base_reg, &sc->sc_sc.sc_memsize)) { printf("%s: can't map OCHI register space\n", devname); return; } @@ -154,11 +153,21 @@ return; } printf("%s: interrupting at %d\n", devname, ca->ca_intrline); + + /* XXX this might be neccery for PCI card too ? */ + if (PCI_VENDOR(ca->ca_id) == PCI_VENDOR_VIATECH) { + switch (PCI_PRODUCT(ca->ca_id)) { + case PCI_PRODUCT_VIATECH_VT6306: + sc->sc_sc.sc_quirks |= FWOHCI_QUIRK_WAIT_SETTLE; + break; + } + } - /* XXX NULL should be replaced by some call to Cardbus coed */ + /* XXX NULL should be replaced by some call to Cardbus code */ if (fwohci_init(&sc->sc_sc, NULL) != 0) { cardbus_intr_disestablish(cc, cf, sc->sc_ih); - bus_space_unmap(sc->sc_sc.sc_memt, sc->sc_sc.sc_memh, + Cardbus_mapreg_unmap(sc->sc_ct, sc->sc_base_reg, + sc->sc_sc.sc_memt, sc->sc_sc.sc_memh, sc->sc_sc.sc_memsize); } } Index: ieee1394/TODO =================================================================== RCS file: /cvsroot/syssrc/sys/dev/ieee1394/TODO,v retrieving revision 1.7 diff -w -u -r1.7 TODO --- TODO 2001/12/29 12:28:05 1.7 +++ TODO 2002/01/09 12:26:39 @@ -39,3 +39,6 @@ init/see all devices on resets sometimes. done - Make fwohci detach correctly (for cardbus/etc type interfaces) + +Add hooks so fwnode and its children knows there there have been a bus +reset. Needed for SBP2 and reconnect. Index: ieee1394/files.ieee1394 =================================================================== RCS file: /cvsroot/syssrc/sys/dev/ieee1394/files.ieee1394,v retrieving revision 1.5 diff -w -u -r1.5 files.ieee1394 --- files.ieee1394 2001/05/13 05:01:43 1.5 +++ files.ieee1394 2002/01/09 12:26:39 @@ -3,6 +3,11 @@ file dev/ieee1394/fwlynx.c fwlynx file dev/ieee1394/fwohci.c fwohci +device fwctl { } +attach fwctl at fwbus + +file dev/ieee1394/fwctldev.c fwctl + device fwnode { } attach fwnode at fwbus Index: ieee1394/fwctldev.c =================================================================== RCS file: fwctldev.c diff -N fwctldev.c --- /dev/null Sun May 20 17:40:04 2001 +++ fwctldev.c Wed Jan 9 04:26:39 2002 @@ -0,0 +1,194 @@ +#include +#include +#include +#include +#include +#include +#include + + +#include +#include + +#include "ioconf.h" + +cdev_decl(fwctl); + +struct fwctldev_softc; + +/* XXX */ +struct fwohci_softc; +void fwohci_phy_busreset(struct fwohci_softc *); + + +LIST_HEAD(,fwctldev_softc) fwctldevs; + + +struct fwctldev_softc { + struct device sc_device; + int sc_flags; +#define FWCTLDEV_OPEN 1 +}; + +int fwctldev_match(struct device *, struct cfdata *, void *); +void fwctldev_attach(struct device *, struct device *, void *); +int fwctldev_detach(struct device *, int); + +static struct fwctldev_softc * fwctl_find(dev_t); + + +struct cfattach fwctl_ca = { + sizeof(struct fwctldev_softc), fwctldev_match, fwctldev_attach, + fwctldev_detach +}; + + +int +fwctldev_match(struct device *parent, struct cfdata *match, void *aux) +{ + struct ieee1394_attach_args *fwa = aux; + + if (strcmp(fwa->name, "fwctl") == 0) + return 1; + return 0; +} + +void +fwctldev_attach(struct device *parent, struct device *self, void *aux) +{ + /* struct fwctldev_softc *sc = (struct fwctldev_softc *)self; */ + printf("\n"); +} + +int +fwctldev_detach(struct device *self, int flags) +{ + int maj, mn; + + /* locate the major number */ + for (maj = 0; maj < nchrdev; maj++) + if (cdevsw[maj].d_open == fwctlopen) + break; + + if (maj == nchrdev) { +#if 0 + panic("fwctl: failed to find major numer for device"); +#endif + return 0; + } + + mn = self->dv_unit; + vdevgone(maj, mn, mn, VCHR); + + return 0; +} + +static struct fwctldev_softc * +fwctl_find(dev_t dev) +{ + struct fwctldev_softc *sc; + + if (minor(dev) >= fwctl_cd.cd_ndevs) + return NULL; + sc = fwctl_cd.cd_devs[minor(dev)]; + if (sc == NULL) + return NULL; + + return sc; +} + +int +fwctlopen(dev_t dev, int oflags, int devtype, struct proc *p) +{ + struct fwctldev_softc *sc; + + if ((sc = fwctl_find(dev)) == NULL) + return ENODEV; + + sc->sc_flags |= FWCTLDEV_OPEN; + + return 0; +} + +int +fwctlclose(dev_t dev, int fflag, int devtype, struct proc *p) +{ + struct fwctldev_softc *sc; + + if ((sc = fwctl_find(dev)) == NULL) + panic("fwctl dev doesn't exist when closing ?"); + + if ((sc->sc_flags & FWCTLDEV_OPEN) == 0) + panic("fwctl dev never opened ?"); + + sc->sc_flags &= ~FWCTLDEV_OPEN; + + return 0; +} + +int +fwctlread(dev_t dev, struct uio *uio, int ioflag) +{ + return EOPNOTSUPP; +} + +int +fwctlwrite(dev_t dev, struct uio *uio, int ioflag) +{ + return EOPNOTSUPP; +} + +int +fwctlioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct proc *p) +{ + /* XXX gross hack */ + + struct ieee1394_softc *parent_sc; + struct fwctldev_softc *sc; + + if ((sc = fwctl_find(dev)) == NULL) + panic("ioctl on unopened device ?"); + + switch (cmd) { + case FWCTL_GET_GUID: { + struct fwctl_guid *guid = (struct fwctl_guid *)data; + + memcpy(&guid->guid, parent_sc->sc1394_guid, + sizeof(parent_sc->sc1394_guid)); + + break; + } + case FWCTL_FORCE_RESET: { + fwohci_phy_busreset((struct fwohci_softc *)parent_sc); + break; + } + default: + return EOPNOTSUPP; + } + + return 0; +} + +void +fwctlstop(struct tty *tp, int rw) +{ + return; +} + +struct tty * +fwctltty(dev_t dev) +{ + return NULL; +} + +int +fwctlpoll(dev_t dev, int events, struct proc *p) +{ + return 0; +} + +paddr_t +fwctlmmap (dev_t dev, off_t off, int flag) +{ + return NULL; +} Index: ieee1394/fwctldev.h =================================================================== RCS file: fwctldev.h diff -N fwctldev.h --- /dev/null Sun May 20 17:40:04 2001 +++ fwctldev.h Wed Jan 9 04:26:39 2002 @@ -0,0 +1,10 @@ + + +struct fwctl_guid { + u_int8_t guid[8]; +}; + + +#define FWCTL_GET_GUID _IOR ('F', 0, struct fwctl_guid) +#define FWCTL_FORCE_RESET _IOR ('F', 0, int) + Index: ieee1394/fwnode.c =================================================================== RCS file: /cvsroot/syssrc/sys/dev/ieee1394/fwnode.c,v retrieving revision 1.7 diff -w -u -r1.7 fwnode.c --- fwnode.c 2001/11/15 09:48:08 1.7 +++ fwnode.c 2002/01/09 12:26:39 @@ -63,25 +63,22 @@ int fwnode_match(struct device *, struct cfdata *, void *); void fwnode_attach(struct device *, struct device *, void *); int fwnode_detach(struct device *, int); + static void fwnode_configrom_input(struct ieee1394_abuf *, int); -static u_int16_t calc_crc(u_int32_t, u_int32_t *, int, int); static int fwnode_parse_configrom (struct fwnode_softc *); static int fwnode_parse_directory(struct fwnode_softc *, u_int32_t *, struct configrom_dir *); -static void fwnode_print_configrom_tree(struct fwnode_softc *, - struct configrom_dir *, int); +static void fwnode_config_tree(struct fwnode_softc *, + struct configrom_dir *); static int fwnode_parse_leaf(u_int32_t *, struct configrom_data *); -static int fwnode_match_dev_type(struct fwnode_softc *, - struct configrom_data *); -static int sbp2_print_data(struct configrom_data *); -static int sbp2_print_dir(u_int8_t); -static void sbp2_init(struct fwnode_softc *, struct fwnode_device_cap *); static int fwnode_print(void *, const char *); -static void fwnode_match_subdevs(struct fwnode_softc *); -static void sbp2_login(struct ieee1394_abuf *, int); -static void sbp2_login_resp(struct ieee1394_abuf *, int); +static u_int16_t + calc_crc(u_int32_t, u_int32_t *, int, int); #ifdef FW_DEBUG +static void fwnode_print_configrom_tree(struct fwnode_softc *, + struct configrom_dir *, int); + #define DPRINTF(x) if (fwnodedebug) printf x #define DPRINTFN(n,x) if (fwnodedebug>(n)) printf x int fwnodedebug = 1; @@ -125,7 +122,8 @@ sc->sc1394_inreg = fwa->inreg; TAILQ_INIT(&sc->sc_configrom_root); - TAILQ_INIT(&sc->sc_dev_cap_head); + + LIST_INIT(&sc->sc_children); /* XXX. Fix the fw code to use the generic routines. */ sc->sc_sc1394.sc1394_ifinreg = psc->sc1394_ifinreg; @@ -150,10 +148,11 @@ fwnode_detach(struct device *self, int flags) { struct fwnode_softc *sc = (struct fwnode_softc *)self; + struct fwnode_child_softc *child; struct configrom_dir *dir, *sdir; struct configrom_data *data; - struct fwnode_device_cap *devcap; + if (sc->sc_sc1394.sc1394_configrom && sc->sc_sc1394.sc1394_configrom_len) free(sc->sc_sc1394.sc1394_configrom, M_1394DATA); @@ -196,12 +195,14 @@ dir = NULL; free(sdir, M_1394DATA); } - while ((devcap = TAILQ_FIRST(&sc->sc_dev_cap_head))) { - TAILQ_REMOVE(&sc->sc_dev_cap_head, devcap, dev_list); - if (devcap->dev_data) - free(devcap->dev_data, M_1394DATA); - free(devcap, M_1394DATA); + + + while(LIST_FIRST(&sc->sc_children) != NULL) { + child = LIST_FIRST(&sc->sc_children); + LIST_REMOVE(child, sc_node); + config_detach(&child->sc_device, DETACH_FORCE); } + return 0; } @@ -226,6 +227,9 @@ dirs = NULL; + DPRINTF(("fwnode_configrom_input: %d rcode: %d\n", + (int)ab->ab_cbarg, rcode)); + if (rcode != IEEE1394_RCODE_COMPLETE) { DPRINTF(("Aborting configrom input, rcode: %d\n", rcode)); goto fail; @@ -288,6 +292,9 @@ * later. */ + DPRINTF(("fwnode_configrom_input: fetching rom: %d\n", + newlen)); + sc->sc_sc1394.sc1394_configrom = ab->ab_data; sc->sc_sc1394.sc1394_configrom_len = 0; memset(ab->ab_data, 0, crclen); @@ -597,7 +604,7 @@ #ifdef FW_DEBUG fwnode_print_configrom_tree(sc, root, 0); #endif - fwnode_match_subdevs(sc); + fwnode_config_tree(sc, root); } else return 1; return 0; @@ -658,9 +665,6 @@ data->leafdata = NULL; TAILQ_INSERT_TAIL(&head->data_root, data, data); - if (type != P1212_KEYTYPE_Leaf) - if (fwnode_match_dev_type(sc, data)) - return 1; if (type == P1212_KEYTYPE_Leaf) { crclen = P1212_DIRENT_GET_LEN((ntohl(addr[i + data->val]))); @@ -792,71 +796,7 @@ return 0; } -static int -fwnode_match_dev_type(struct fwnode_softc *sc, struct configrom_data *data) -{ - /* XXX: This whole structure needs to be gut'd and redone. - Only after reading in the whole tree should sections of the tree - be passed along to config_found. */ - - struct fwnode_device_cap *devcap; - int done, found_sbp2; - - done = found_sbp2 = 0; - - switch (data->key_value) { - case P1212_KEYVALUE_Unit_Spec_Id: - if (data->val == SBP2_UNIT_SPEC_ID) - found_sbp2 = 1; - break; - case P1212_KEYVALUE_Unit_Sw_Version: - if (data->val == SBP2_UNIT_SW_VERSION) - found_sbp2 = 1; - break; - case P1212_KEYVALUE_Unit_Dependent_Info: - if (data->key_type == P1212_KEYTYPE_Offset) - found_sbp2 = 1; - default: - break; - } - if (found_sbp2) { - TAILQ_FOREACH(devcap, &sc->sc_dev_cap_head, dev_list) { - - if ((devcap->dev_type == DEVTYPE_SBP2) && found_sbp2) { - if (!devcap->dev_valid) { - done = 1; - devcap->dev_valid = 1; - } else { - DPRINTF(("found_sbp2: 0x%08x\n", - data->val)); - devcap->dev_data = - malloc(4, M_1394DATA, M_WAITOK); - ((u_int32_t *)devcap->dev_data)[0] = - data->val; - done = 1; - } - } - } - - /* If one wasn't found get a struct started. */ - if (!done) { - devcap = malloc(sizeof(*devcap), M_1394DATA, M_WAITOK); - devcap->dev_valid = 0; - devcap->dev_spec = 0; - devcap->dev_info = 0; - devcap->dev_data = NULL; - if (found_sbp2) { - devcap->dev_type = DEVTYPE_SBP2; - devcap->dev_print_data = sbp2_print_data; - devcap->dev_print_dir = sbp2_print_dir; - devcap->dev_init = sbp2_init; - } - TAILQ_INSERT_TAIL(&sc->sc_dev_cap_head, devcap, - dev_list); - } - } - return 0; -} +#ifdef FW_DEBUG static void fwnode_print_configrom_tree(struct fwnode_softc *sc, struct configrom_dir *dir, @@ -866,7 +806,7 @@ struct configrom_data *data; struct configrom_dir *subdir; struct configrom_leafdata *leaf; - struct fwnode_device_cap *devcap; + u_int32_t unit_spec; char *space; /* Set the indent string up. 4 spaces per level. */ @@ -875,38 +815,69 @@ space[i] = 0x20; space[indent * 4] = 0; - if (dir->dir_type) { - found = 0; - TAILQ_FOREACH(devcap, &sc->sc_dev_cap_head, dev_list) { - if (devcap->dev_print_dir(dir->dir_type)) { - found = 1; - break; - } - } - if (!found) { + if (dir->dir_type) printf("%sUnit ", space); - } - } else + else printf("Root "); printf("directory:\n\n"); + + unit_spec = 0; + TAILQ_FOREACH(data, &dir->data_root, data) { - found = 0; printf("%s", space); - /* - * Try any capable devices first. - * If none match just give up and print out the value. - * - */ - - TAILQ_FOREACH(devcap, &sc->sc_dev_cap_head, dev_list) { - if (devcap->dev_print_data(data)) { found = 1; + + if (data->key_value == P1212_KEYVALUE_Unit_Spec_Id) + unit_spec = data->val; + +#define KV_PRINT(key,str) case key: printf(str, data->val); break + + switch (data->key_value) { + case SBP2_KEYVALUE_Command_Set: + printf("SBP2 Command Set: "); + if (data->val == 0x104d8) + printf("SCSI 2\n"); + else + printf("0x%08x\n", data->val); break; + KV_PRINT(SBP2_KEYVALUE_Unit_Characteristics, + "SBP2 Unit Characteristics: 0x%08x\n"); + KV_PRINT(SBP2_KEYVALUE_Command_Set_Revision, + "SBP2 Command Set Revision: 0x%08x\n"); + KV_PRINT(SBP2_KEYVALUE_Command_Set_Spec_Id, + "SBP2 Command Set Spec Id: 0x%08x\n"); + KV_PRINT(SBP2_KEYVALUE_Firmware_Revision, + "SBP2 Firmware Revision: 0x%08x\n"); + KV_PRINT(SBP2_KEYVALUE_Reconnect_Timeout, + "SBP2 Reconnect Timeout: 0x%08x\n"); + KV_PRINT(SBP2_KEYVALUE_Unit_Unique_Id, + "SBP2 Unit Unique Id: 0x%08x\n"); + + case P1212_KEYVALUE_Unit_Dependent_Info: + if (unit_spec == SBP2_UNIT_SPEC_ID) { + switch (data->key_type) { + KV_PRINT(P1212_KEYTYPE_Immediate, + "SBP2 Logical Unit Number: 0x%08x\n"); + KV_PRINT(P1212_KEYTYPE_Offset, + "SBP2 Management Agent: 0x%08x\n"); + default: + found = 0; + break; } + } else { + found = 0; } + break; +#undef KV_PRINT + default: + found = 0; + break; + } + if (found) continue; + if (data->key_value >= (sizeof(p1212_keyvalue_strings) / sizeof(char *))) printf("Unknown type 0x%04hx: ", @@ -948,221 +919,86 @@ } free(space, M_1394DATA); } +#endif /* FW_DEBUG */ -/* XXX: All the sbp2 routines are a complete hack simply to probe a device for - the moment to make sure all the other code is good. This should all be gutted - out to it's own file and properly abstracted. -*/ - -static int -sbp2_print_data(struct configrom_data *data) +static void +fwnode_config_tree(struct fwnode_softc *sc, struct configrom_dir *dir) { + struct fwnode_match_arg arg; + struct configrom_dir *subdir; + struct configrom_data *data; + + arg.fwma_valid = 0; + arg.fwma_dir = dir; + arg.fwma_fwnode = sc; + + TAILQ_FOREACH(data, &dir->data_root, data) { switch (data->key_value) { - case SBP2_KEYVALUE_Command_Set: - printf("SBP2 Command Set: "); - if (data->val == 0x104d8) - printf("SCSI 2\n"); - else - printf("0x%08x\n", data->val); - break; - case SBP2_KEYVALUE_Unit_Characteristics: - printf("SBP2 Unit Characteristics: 0x%08x\n", data->val); - break; - case SBP2_KEYVALUE_Command_Set_Revision: - printf("SBP2 Command Set Revision: 0x%08x\n", data->val); - break; - case SBP2_KEYVALUE_Command_Set_Spec_Id: - printf("SBP2 Command Set Spec Id: 0x%08x\n", data->val); - break; - case SBP2_KEYVALUE_Firmware_Revision: - printf("SBP2 Firmware Revision: 0x%08x\n", data->val); - break; - case SBP2_KEYVALUE_Reconnect_Timeout: - printf("SBP2 Reconnect Timeout: 0x%08x\n", data->val); - break; - case SBP2_KEYVALUE_Unit_Unique_Id: - printf("SBP2 Unit Unique Id: 0x%08x\n", data->val); + case P1212_KEYVALUE_Unit_Spec_Id: + arg.fwma_valid |= FWMA_SPEC_ID; + arg.fwma_spec_id = data->val; break; - case P1212_KEYVALUE_Unit_Dependent_Info: - if (data->key_type == P1212_KEYTYPE_Immediate) - printf("SBP2 Logical Unit Number: 0x%08x\n", data->val); - else if (data->key_type == P1212_KEYTYPE_Offset) - printf("SBP2 Management Agent: 0x%08x\n", data->val); + case P1212_KEYVALUE_Unit_Sw_Version: + arg.fwma_valid |= FWMA_SW_VERSION; + arg.fwma_sw_version = data->val; break; - default: - return 0; - } - return 1; -} + case P1212_KEYVALUE_Textual_Descriptor: { + struct configrom_leafdata *l; -static int -sbp2_print_dir(u_int8_t dir_type) -{ - switch(dir_type) { - case SBP2_KEYVALUE_Logical_Unit_Directory: - printf("Logical Unit "); + if (data->key_type != P1212_KEYTYPE_Leaf || + data->leafdata == NULL) break; - default: - return 0; - } - return 1; -} -static void -sbp2_init(struct fwnode_softc *sc, struct fwnode_device_cap *devcap) -{ - struct ieee1394_abuf *ab, *ab2; - u_int32_t loc = ((int32_t *)devcap->dev_data)[0]; - - ab = malloc(sizeof(struct ieee1394_abuf), M_1394DATA, M_WAITOK); - memset(ab, 0, sizeof(struct ieee1394_abuf)); - ab->ab_data = malloc(8, M_1394DATA, M_WAITOK); - memset(ab->ab_data, 0, 8); - ab2 = malloc(sizeof(struct ieee1394_abuf), M_1394DATA, M_WAITOK); - memset(ab2, 0, sizeof(struct ieee1394_abuf)); - - loc *= 4; - ab->ab_length = 8; - ab->ab_req = (struct ieee1394_softc *)sc; - ab->ab_retlen = 0; - ab->ab_cb = NULL; - ab->ab_cbarg = NULL; - ab->ab_csr = CSR_BASE + loc; - ab->ab_data[0] = htonl(0x4000); - ab->ab_data[1] = 0; - ab->ab_tcode = IEEE1394_TCODE_WRITE_REQ_BLOCK; - - ab2->ab_length = 32; - ab2->ab_tcode = IEEE1394_TCODE_READ_REQ_BLOCK; - ab2->ab_retlen = 0; - ab2->ab_data = NULL; - ab2->ab_csr = 0x0000400000000000; - ab2->ab_cb = sbp2_login; - ab2->ab_cbarg = devcap; - ab2->ab_req = (struct ieee1394_softc *)sc; - - sc->sc1394_inreg(ab2, FALSE); - sc->sc1394_write(ab); - return; -} + l = data->leafdata; -static void -sbp2_login(struct ieee1394_abuf *ab, int rcode) -{ - struct fwnode_softc *sc = (struct fwnode_softc *)ab->ab_req; - /* struct fwnode_device_cap *devcap = ab->ab_cbarg;*/ - struct ieee1394_abuf *statab, *respab; + /* not text */ + if (l->desc_type != 0) + break; - /* Got a read so allocate the buffer and write out the response. */ + /* not ASCII */ + if (l->char_width || l->char_set || l->char_lang) + break; - if (rcode) { -#ifdef FW_DEBUG - printf ("sbp2_login: Bad return code: %d\n", rcode); -#endif - if (ab->ab_data) - free (ab->ab_data, M_1394DATA); - free(ab, M_1394DATA); + arg.fwma_valid |= FWMA_TEXT_DESC; + arg.fwma_text_desc = l->text; } - - ab->ab_data = malloc(32, M_1394DATA, M_WAITOK); - respab = malloc(sizeof(struct ieee1394_abuf), M_1394DATA, M_WAITOK); - statab = malloc(sizeof(struct ieee1394_abuf), M_1394DATA, M_WAITOK); - memset(respab, 0, sizeof(struct ieee1394_abuf)); - memset(statab, 0, sizeof(struct ieee1394_abuf)); - - statab->ab_length = 32; - statab->ab_tcode = IEEE1394_TCODE_WRITE_REQ_BLOCK; - statab->ab_retlen = 0; - statab->ab_data = NULL; - statab->ab_csr = 0x0000400000000030; - statab->ab_cb = sbp2_login_resp; - statab->ab_cbarg = ab->ab_cbarg; - statab->ab_req = ab->ab_req; - - sc->sc1394_inreg(statab, TRUE); - - respab->ab_length = 16; - respab->ab_tcode = IEEE1394_TCODE_WRITE_REQ_BLOCK; - respab->ab_retlen = 0; - respab->ab_data = NULL; - respab->ab_csr = 0x0000400000000020; - respab->ab_cb = sbp2_login_resp; - respab->ab_cbarg = ab->ab_cbarg; - respab->ab_req = ab->ab_req; - - sc->sc1394_inreg(respab, TRUE); - - memset(ab->ab_data, 0, 32); - ab->ab_data[2] = htonl(0x4000); - ab->ab_data[3] = htonl(0x20); - ab->ab_data[4] = htonl(0x90000000); - ab->ab_data[5] = htonl(0x00000010); - ab->ab_data[6] = htonl(0x4000); - ab->ab_data[7] = htonl(0x30); - ab->ab_retlen = 0; - ab->ab_cb = NULL; - ab->ab_cbarg = NULL; - ab->ab_tcode = IEEE1394_TCODE_READ_RESP_BLOCK; - ab->ab_length = 32; - - sc->sc1394_write(ab); + default: + break; } - -static void -sbp2_login_resp(struct ieee1394_abuf *ab, int rcode) -{ - /* struct fwnode_device_cap *devcap = (struct fwnode_device_cap *)ab->ab_cbarg;*/ -#ifdef FW_DEBUG - int i; -#endif - - if (rcode) { - DPRINTF(("Bad return code: %d\n", rcode)); - if (ab->ab_data) - free(ab->ab_data, M_1394DATA); - free(ab, M_1394DATA); } - DPRINTF(("csr: 0x%016qx\n", ab->ab_csr)); -#ifdef FW_DEBUG - for (i = 0; i < (ab->ab_retlen / 4); i++) - printf("%d: 0x%08x\n", i, ntohl(ab->ab_data[i])); -#endif + /* Did we find something interesting ? */ + if ((arg.fwma_valid & (FWMA_SPEC_ID|FWMA_SW_VERSION)) != 0) { + struct fwnode_child_softc *child; - free(ab->ab_data, M_1394DATA); - free(ab, M_1394DATA); + child = (struct fwnode_child_softc *) + config_found_sm(&sc->sc_sc1394.sc1394_dev, + &arg, fwnode_print, NULL); + if (child) + LIST_INSERT_HEAD(&sc->sc_children, child, sc_node); } -static void -fwnode_match_subdevs(struct fwnode_softc *sc) -{ - struct fwnode_device_cap *devcap; - - TAILQ_FOREACH(devcap, &sc->sc_dev_cap_head, dev_list) { - switch(devcap->dev_type) { - case DEVTYPE_UNKNOWN: - DPRINTF(("%s: Unknown device %d\n", - sc->sc_sc1394.sc1394_dev.dv_xname, - devcap->dev_spec)); - break; - case DEVTYPE_SBP2: - devcap->dev_init(sc, devcap); - break; - default: - panic("Unknown devcap type: %d", devcap->dev_type); - fwnode_print(NULL, NULL); - break; - } - } + /* + * XXX how deep can the tree be (in reality), we can overrun + * the kernel stack + */ + TAILQ_FOREACH(subdir, &dir->subdir_root, dir) + fwnode_config_tree(sc, subdir); } static int fwnode_print(void *aux, const char *pnp) { - char *name = aux; + struct fwnode_match_arg *arg = aux; + + if (pnp) { + printf("unknown at %s:", pnp); + if (arg->fwma_valid & FWMA_TEXT_DESC) + printf(" %s:", arg->fwma_text_desc); + printf(" specid %d sw version %d", + arg->fwma_spec_id, arg->fwma_sw_version); + } - if (pnp) - printf("%s at %s", name, pnp); return UNCONF; } Index: ieee1394/fwnodevar.h =================================================================== RCS file: /cvsroot/syssrc/sys/dev/ieee1394/fwnodevar.h,v retrieving revision 1.3 diff -w -u -r1.3 fwnodevar.h --- fwnodevar.h 2001/05/11 06:07:40 1.3 +++ fwnodevar.h 2002/01/09 12:26:39 @@ -70,19 +70,19 @@ u_int32_t refs; }; -struct fwnode_device_cap { - int (*dev_print_data)(struct configrom_data *); - int (*dev_print_dir)(u_int8_t); - void (*dev_init)(struct fwnode_softc *, struct fwnode_device_cap *); - void *dev_data; - int dev_type; - int dev_spec; - int dev_info; /* Lun, etc. */ - int dev_valid; - struct device *dev_subdev; - TAILQ_ENTRY(fwnode_device_cap) dev_list; +struct fwnode_match_arg { + int fwma_valid; +#define FWMA_SPEC_ID 0x01 +#define FWMA_SW_VERSION 0x02 +#define FWMA_TEXT_DESC 0x04 + u_int32_t fwma_spec_id; + u_int32_t fwma_sw_version; + char *fwma_text_desc; + struct configrom_dir *fwma_dir; + struct fwnode_softc *fwma_fwnode; }; + struct fwnode_softc { struct ieee1394_softc sc_sc1394; @@ -92,8 +92,15 @@ int (*sc1394_write)(struct ieee1394_abuf *); int (*sc1394_inreg)(struct ieee1394_abuf *, int); - TAILQ_HEAD(, fwnode_device_cap) sc_dev_cap_head; TAILQ_HEAD(, configrom_dir) sc_configrom_root; + + LIST_HEAD(, fwnode_child_softc) sc_children; +}; + +struct fwnode_child_softc { + struct device sc_device; + struct fwnode_softc *sc_fwnode; + LIST_ENTRY(fwnode_child_softc) sc_node; }; #endif /* _DEV_IEEE1394_FWNODEVAR_H */ Index: ieee1394/fwohci.c =================================================================== RCS file: /cvsroot/syssrc/sys/dev/ieee1394/fwohci.c,v retrieving revision 1.47 diff -w -u -r1.47 fwohci.c --- fwohci.c 2001/12/29 12:26:31 1.47 +++ fwohci.c 2002/01/09 12:26:41 @@ -120,7 +120,7 @@ static u_int8_t fwohci_phy_read(struct fwohci_softc *, u_int8_t); static void fwohci_phy_write(struct fwohci_softc *, u_int8_t, u_int8_t); -static void fwohci_phy_busreset(struct fwohci_softc *); +void fwohci_phy_busreset(struct fwohci_softc *); static void fwohci_phy_input(struct fwohci_softc *, struct fwohci_pkt *); static int fwohci_handler_set(struct fwohci_softc *, int, u_int32_t, u_int32_t, @@ -133,6 +133,8 @@ static int fwohci_at_output(struct fwohci_softc *, struct fwohci_ctx *, struct fwohci_pkt *); static void fwohci_at_done(struct fwohci_softc *, struct fwohci_ctx *, int); +#define FWOHCI_AT_DONE_FORCE 0x1 +#define FWOHCI_AT_DONE_NO_WRITE 0x2 static void fwohci_atrs_output(struct fwohci_softc *, int, struct fwohci_pkt *, struct fwohci_pkt *); @@ -181,7 +183,7 @@ #define DPRINTF(x) if (fwdebug) printf x #define DPRINTFN(n,x) if (fwdebug>(n)) printf x -int fwdebug = 0; +int fwdebug = 1; #else #define DPRINTF(x) #define DPRINTFN(n,x) @@ -319,6 +321,9 @@ for (;;) { intmask = OHCI_CSR_READ(sc, OHCI_REG_IntEventClear); + if (intmask == 0xffffffff) /* XXX card removed */ + return 1; + /* * On a bus reset, everything except bus reset gets * cleared. That can't get cleared until the selfid @@ -434,12 +439,6 @@ } /* - * Enable Link Power - */ - - OHCI_CSR_WRITE(sc, OHCI_REG_HCControlSet, OHCI_HCControl_LPS); - - /* * Allocate DMA Context */ fwohci_ctx_alloc(sc, &sc->sc_ctx_arrq, OHCI_BUF_ARRQ_CNT, @@ -476,13 +475,24 @@ sc->sc_sc1394.sc1394_if = config_found(&sc->sc_sc1394.sc1394_dev, "fw", fwohci_print); + sc->sc_sc1394.sc1394_ctl = config_found(&sc->sc_sc1394.sc1394_dev, + "fwctl", fwohci_print); + /* Main loop. It's not coming back normally. */ fwohci_event_thread(sc); + /* Wakeup parent if needed */ + sc->sc_dying = 2; + wakeup(sc); + kthread_exit(0); } +#ifndef FWOHCI_DELAY +#define FWOHCI_DELAY 1 +#endif + static void fwohci_event_thread(struct fwohci_softc *sc) { @@ -496,10 +506,21 @@ */ fwohci_hw_init(sc); + splx(s); + + if (sc->sc_quirks & FWOHCI_QUIRK_WAIT_SETTLE) { + printf("%s: waiting %d seconds for device to settle\n", + sc->sc_sc1394.sc1394_dev.dv_xname, FWOHCI_DELAY); + tsleep(fwohci_event_thread, PRIBIO, "fwohciset", + FWOHCI_DELAY * hz); + /* we sleep and the hardware went away under our feet */ + if (sc->sc_dying) + return; + } + /* Initial Bus Reset */ fwohci_phy_busreset(sc); - splx(s); while (!sc->sc_dying) { s = splbio(); @@ -632,7 +653,35 @@ DELAY(10); } +#ifdef FW_DEBUG + val = OHCI_CSR_READ(sc, OHCI_REG_HCControlSet); + if (val & OHCI_HCControl_LPS) + printf("%s: HCControl_LPS is there after reset\n", + sc->sc_sc1394.sc1394_dev.dv_xname); +#endif + + /* + * Wait for LPS turns on, this means the SCLK from the phy is + * present (OHCI1.1: sec 4). Linux driver claims that some + * turn on LPS directly (apprently without waiting for + * SCLK/readyness). If this is the case with your chip, a + * quirk should be added for it. + */ + OHCI_CSR_WRITE(sc, OHCI_REG_HCControlSet, OHCI_HCControl_LPS); + /* wait up to 2 seconds for LPS to wake up */ + for (i = 0; i < OHCI_LOOP_LONG; i++) { + val = OHCI_CSR_READ(sc, OHCI_REG_HCControlSet); + if (val & OHCI_HCControl_LPS) + break; + DELAY(100); + } + if (i == OHCI_LOOP_LONG) + printf("%s: waited forever for LPS\n", + sc->sc_sc1394.sc1394_dev.dv_xname); + else + printf("%s: waited %d interations for LPS\n", + sc->sc_sc1394.sc1394_dev.dv_xname, i); /* * First, initilize CSRs with undefined value to default settings. @@ -690,6 +739,19 @@ OHCI_CSR_WRITE(sc, OHCI_REG_IntMaskSet, OHCI_Int_MasterEnable); OHCI_CSR_WRITE(sc, OHCI_REG_HCControlSet, OHCI_HCControl_LinkEnable); + /* wait up to 2 seconds for LinkEnable to wake up */ + for (i = 0; i < OHCI_LOOP_LONG; i++) { + val = OHCI_CSR_READ(sc, OHCI_REG_HCControlSet); + if (val & OHCI_HCControl_LinkEnable) + break; + DELAY(100); + } + if (i == OHCI_LOOP_LONG) + printf("%s: waited forever for LinkEnable\n", + sc->sc_sc1394.sc1394_dev.dv_xname); + else + printf("%s: waited %d interations for LinkEnable\n", + sc->sc_sc1394.sc1394_dev.dv_xname, i); /* * Start the receivers @@ -737,6 +799,7 @@ OHCI_BusOptions_CMC | OHCI_BusOptions_IRMC); OHCI_CSR_WRITE(sc, OHCI_REG_BusOptions, val); fwohci_phy_busreset(sc); + /* XXX not permited to clear LPS or LinkEnable from software !!! */ OHCI_CSR_WRITE(sc, OHCI_REG_HCControlClear, OHCI_HCControl_LinkEnable); OHCI_CSR_WRITE(sc, OHCI_REG_HCControlClear, OHCI_HCControl_LPS); OHCI_CSR_WRITE(sc, OHCI_REG_HCControlSet, OHCI_HCControl_SoftReset); @@ -789,7 +852,7 @@ /* * Initiate Bus Reset */ -static void +void fwohci_phy_busreset(struct fwohci_softc *sc) { int s; @@ -1237,8 +1300,8 @@ /* * Initialize for Asynchronous Transmit Queue. */ - fwohci_at_done(sc, sc->sc_ctx_atrq, 1); - fwohci_at_done(sc, sc->sc_ctx_atrs, 1); + fwohci_at_done(sc, sc->sc_ctx_atrq, FWOHCI_AT_DONE_FORCE); + fwohci_at_done(sc, sc->sc_ctx_atrs, FWOHCI_AT_DONE_FORCE); } static void @@ -1984,7 +2047,7 @@ } static void -fwohci_at_done(struct fwohci_softc *sc, struct fwohci_ctx *fc, int force) +fwohci_at_done(struct fwohci_softc *sc, struct fwohci_ctx *fc, int flags) { struct fwohci_buf *fb; struct fwohci_desc *fd; @@ -1994,8 +2057,10 @@ while ((fb = TAILQ_FIRST(&fc->fc_buf)) != NULL) { fd = fb->fb_desc; #ifdef FW_DEBUG - DPRINTFN(1, ("fwohci_at_done: %sdesc %ld (%d)", - force ? "force " : "", (long)(fd - sc->sc_desc), + DPRINTFN(1, ("fwohci_at_done: %sdesc %s %ld (%d)", + (flags & FWOHCI_AT_DONE_FORCE) ? "force " : "", + (flags & FWOHCI_AT_DONE_NO_WRITE) ? "nowrite " : "", + (long)(fd - sc->sc_desc), fb->fb_nseg)); for (i = 0; i < fb->fb_nseg * 4; i++) DPRINTFN(2, ("%s%08x", i&7?" ":"\n ", @@ -2004,10 +2069,12 @@ #endif if (fb->fb_nseg > 2) fd += fb->fb_nseg - 1; - if (!force && !(fd->fd_status & OHCI_CTXCTL_ACTIVE)) + if ((flags & FWOHCI_AT_DONE_FORCE) == 0 && + !(fd->fd_status & OHCI_CTXCTL_ACTIVE)) break; TAILQ_REMOVE(&fc->fc_buf, fb, fb_list); - if (fc->fc_branch == &fd->fd_branch) { + if ((flags & FWOHCI_AT_DONE_NO_WRITE) == 0 && + (fc->fc_branch == &fd->fd_branch)) { OHCI_ASYNC_DMA_WRITE(sc, fc->fc_ctx, OHCI_SUBREG_ContextControlClear, OHCI_CTXCTL_RUN); fc->fc_branch = NULL; @@ -3263,6 +3330,10 @@ u_int32_t *cur, high, lo; int i, tcode, rcode, status, rv; + DPRINTF(("fwohci_read_resp: tcode: %d status: %d valid: %d\n", + pkt->fp_tcode, pkt->fp_status & OHCI_DESC_STATUS_ACK_MASK, + fcb->abuf_valid)); + /* * Both the ACK handling and normal response callbacks are handled here. * The main reason for this is the various error conditions that can @@ -3340,6 +3411,7 @@ ab->ab_req->sc1394_node_id, sc->sc_tlabel, fwohci_read_multi_resp, fcb); if (rv) { + DPRINTF(("fwohci_read_resp: failed to set r_m_r\b")); (*ab->ab_cb)(ab, -1); goto cleanup; } @@ -3350,11 +3422,13 @@ fwohci_handler_set(sc, IEEE1394_TCODE_READ_RESP_QUAD, ab->ab_req->sc1394_node_id, sc->sc_tlabel, NULL, NULL); + DPRINTF(("fwohci_read_resp: failed to set at_output")); (*ab->ab_cb)(ab, -1); goto cleanup; } fcb->count++; sc->sc_tlabel = (sc->sc_tlabel + 1) & 0x3f; + DPRINTF(("read: new packet in queue: %d\n", fcb->count)); return IEEE1394_RCODE_COMPLETE; } else if ((rcode != -1) || ((status != -1) && (status != OHCI_CTXCTL_EVENT_ACK_COMPLETE) && @@ -3416,18 +3490,25 @@ u_int32_t high, lo; int rcode, rv; + DPRINTF(("fwochi_read_multi_resp: tcode: %d status: %d rcode: %d\n", + pkt->fp_tcode, pkt->fp_status, + (pkt->fp_hdr[1] & 0x0000f000) >> 12)); + /* * Bad return codes from the wire, just return what's already in the * buf. */ /* Make sure a response packet didn't arrive after a bad ACK. */ - if (fcb->abuf_valid == 0) + if (fcb->abuf_valid == 0) { + DPRINTF(("read_multi_resp: buf not valid")); return IEEE1394_RCODE_COMPLETE; + } rcode = (pkt->fp_hdr[1] & 0x0000f000) >> 12; if (rcode) { + DPRINTF(("read_multi_resp: rcode = %d", rcode)); (*ab->ab_cb)(ab, rcode); goto cleanup; } @@ -3441,6 +3522,10 @@ pkt->fp_iov[0].iov_base, 4); ab->ab_retlen += 4; } + + DPRINTF(("read_multi_resp: retlen: %d len: %d\n", + ab->ab_retlen, ab->ab_length)); + /* Still more, loop and read 4 more bytes. */ if (ab->ab_retlen < ab->ab_length) { memset(&newpkt, 0, sizeof(newpkt)); @@ -3467,11 +3552,13 @@ rv = fwohci_handler_set(sc, IEEE1394_TCODE_READ_RESP_QUAD, ab->ab_req->sc1394_node_id, sc->sc_tlabel, fwohci_read_multi_resp, fcb); - if (rv) + if (rv) { + DPRINTF(("read_multi_r: failed to output handler\n")); (*ab->ab_cb)(ab, -1); - else { + } else { rv = fwohci_at_output(sc, sc->sc_ctx_atrq, &newpkt); if (rv) { + DPRINTF(("read_multi_r: failed at_output\n")); fwohci_handler_set(sc, IEEE1394_TCODE_READ_RESP_QUAD, ab->ab_req->sc1394_node_id, sc->sc_tlabel, @@ -3480,6 +3567,8 @@ } else { sc->sc_tlabel = (sc->sc_tlabel + 1) & 0x3f; fcb->count++; + DPRINTF(("multi: new packet in queue: %d\n", + fcb->count)); return IEEE1394_RCODE_COMPLETE; } } @@ -3665,21 +3754,64 @@ int fwohci_detach(struct fwohci_softc *sc, int flags) { - int rv = 0; + struct ieee1394_softc *iea; + int rv; - if (sc->sc_sc1394.sc1394_if != NULL) - rv = config_detach(sc->sc_sc1394.sc1394_if, flags); - if (rv != 0) - return (rv); + /* + * The children is killed first, this is because they might + * hang the event thread in some event. Hope that the + * children's detach function will un-hang the even thread. + */ + sc->sc_dying = 1; + callout_stop(&sc->sc_selfid_callout); + + LIST_FOREACH(iea, &sc->sc_nodelist, sc1394_node) + iea->sc1394_node_id = 0xffff; + fwohci_check_nodes(sc); + + if ((rv = config_detach(sc->sc_sc1394.sc1394_if, flags)) != 0) + return rv; + sc->sc_sc1394.sc1394_if = NULL; + if ((rv = config_detach(sc->sc_sc1394.sc1394_ctl, flags)) != 0) + return rv; + sc->sc_sc1394.sc1394_ctl = NULL; + + if (sc->sc_dying != 2) { + wakeup(fwohci_event_thread); + if (tsleep(sc, PWAIT, "fwohcidet", hz * 60)) { + if (sc->sc_dying == 2) + panic("%s: fw event thread died " + "but didn't wake us up", + sc->sc_sc1394.sc1394_dev.dv_xname); + printf("%s: fw event thread didn't die\n", + sc->sc_sc1394.sc1394_dev.dv_xname); + } + } - if (sc->sc_powerhook != NULL) + fwohci_at_done(sc, sc->sc_ctx_atrq, + FWOHCI_AT_DONE_FORCE|FWOHCI_AT_DONE_NO_WRITE); + fwohci_at_done(sc, sc->sc_ctx_atrs, + FWOHCI_AT_DONE_FORCE|FWOHCI_AT_DONE_NO_WRITE); + + fwohci_ctx_free(sc, sc->sc_ctx_arrq); + fwohci_ctx_free(sc, sc->sc_ctx_arrs); + fwohci_ctx_free(sc, sc->sc_ctx_atrq); + fwohci_ctx_free(sc, sc->sc_ctx_atrs); + free(sc->sc_ctx_ir, M_DEVBUF); + + fwohci_buf_free(sc, &sc->sc_buf_cnfrom); + fwohci_buf_free(sc, &sc->sc_buf_selfid); + powerhook_disestablish(sc->sc_powerhook); - if (sc->sc_shutdownhook != NULL) shutdownhook_disestablish(sc->sc_shutdownhook); - return (rv); + evcnt_detach(&sc->sc_intrcnt); + evcnt_detach(&sc->sc_isocnt); + evcnt_detach(&sc->sc_isopktcnt); + + return 0; } int Index: ieee1394/fwohcivar.h =================================================================== RCS file: /cvsroot/syssrc/sys/dev/ieee1394/fwohcivar.h,v retrieving revision 1.16 diff -w -u -r1.16 fwohcivar.h --- fwohcivar.h 2001/12/29 12:26:32 1.16 +++ fwohcivar.h 2002/01/09 12:26:41 @@ -56,6 +56,7 @@ OHCI_BUF_ATRS_CNT + OHCI_BUF_IR_CNT + 1 + 1) #define OHCI_LOOP 1000 +#define OHCI_LOOP_LONG 20000 #define OHCI_SELFID_TIMEOUT (hz * 3) #define OHCI_ASYNC_STREAM 0x40 @@ -174,6 +175,9 @@ struct proc *sc_event_thread; int sc_dying; + u_int32_t sc_quirks; +#define FWOHCI_QUIRK_WAIT_SETTLE 0x00000001 + u_int32_t sc_intmask; u_int32_t sc_iso; Index: ieee1394/fwscsi.c =================================================================== RCS file: /cvsroot/syssrc/sys/dev/ieee1394/fwscsi.c,v retrieving revision 1.4 diff -w -u -r1.4 fwscsi.c --- fwscsi.c 2001/11/15 09:48:08 1.4 +++ fwscsi.c 2002/01/09 12:26:42 @@ -1,12 +1,9 @@ -/* $NetBSD: fwscsi.c,v 1.4 2001/11/15 09:48:08 lukem Exp $ */ +/* $NetBSD$ */ /* - * Copyright (c) 2000 The NetBSD Foundation, Inc. + * Copyright (c) 2002 Love Hörnquist-Åstrand * All rights reserved. * - * This code is derived from software contributed to The NetBSD Foundation - * by James Chacon. - * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -15,68 +12,983 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the NetBSD - * Foundation, Inc. and its contributors. - * 4. Neither the name of The NetBSD Foundation nor the names of its + * 3. Neither the name of The NetBSD Foundation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * THIS SOFTWARE IS PROVIDED BY THE Love Hörnquist-Åstrand AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Love Hörnquist-Åstrand OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * TODO: + * - locking (spl) + * - fix fifo (use `src' and `resp') + * - make sure we don't tsleep in the fw `interrupt' thread */ #include __KERNEL_RCSID(0, "$NetBSD: fwscsi.c,v 1.4 2001/11/15 09:48:08 lukem Exp $"); #include +#include #include #include #include #include +#include +#include +#include +#include #include +#include +#include +#include + +#include +#include +#include +#include + #include #include +#define FWSCSI_DEBUG 1 + +#ifdef FWSCSI_DEBUG +static int fwscsi_debug = 1; +#define DPRINTF(x) if (fwscsi_debug) { printf x ; } +#else +#define DPRINTF(x) +#endif + +struct fwscsi_softc; + static int fwscsi_match(struct device *, struct cfdata *, void *); static void fwscsi_attach(struct device *, struct device *, void *); static int fwscsi_detach(struct device *, int); +static void sbp2_init(struct fwscsi_softc *); +static void sbp2_login(struct ieee1394_abuf *, int); +static void sbp2_login_resp(struct ieee1394_abuf *, int); +static void sbp2_fifo(struct ieee1394_abuf *, int); + +/* scsipi interface */ +static void sbp2_attach_scsi(void *); +static struct sbp2_cmdorb * + sbp2_get_cmdorb(struct fwscsi_softc *); +static void sbp2_send_orb(struct sbp2_cmdorb *); +static void sbp2_free_orb(struct sbp2_cmdorb *); +static void sbp2_cmd_req(struct ieee1394_abuf *, int); +static void sbp2_data_req(struct ieee1394_abuf *, int); +static void sbp2_orb_sent(struct ieee1394_abuf *, int); +static void sbp2_minphys(struct buf *bp); +static int sbp2_ioctl(struct scsipi_channel *, u_long, caddr_t, int, + struct proc *); +static void sbp2_kill_orbs(struct fwscsi_softc *); +static void sbp2_target_reset(struct fwscsi_softc *); +static void sbp2_attach_thread(void *arg); + + +typedef enum { SBP2_ATTACH, + SBP2_LOGIN, + SBP2_RECONNECT, + SBP2_ATTACHED, + SBP2_DETACHED, + SBP2_INVALID_DIR, +} sbp2_state; + +struct sbp2_cmdorb; + struct fwscsi_softc { - struct device sc_dev; + struct fwnode_child_softc sc_node_dev; + + struct scsipi_adapter sc_adapter; + struct scsipi_channel sc_channel; + + struct proc *sc_attach_thread; + + struct device *sc_scsidev; + + struct extent *sc_cmds; + struct extent *sc_datas; + + sbp2_state sc_state; + + u_int32_t sc_spec_id; + u_int32_t sc_sw_ver; + + /* directory data */ + u_int32_t sc_reconnect_timeout; + u_int32_t sc_fw_ver; + u_int32_t sc_cmd_set; + u_int32_t sc_cmd_set_rev; + u_int32_t sc_cmd_set_spec_id; + u_int32_t sc_lun; + u_int32_t sc_uniq_id; + u_int32_t sc_unit_char; + u_int32_t sc_mgt_addr; + + /* scsi data */ + + /* connection data */ + u_int16_t sc_login_id; + u_int16_t sc_pad1; + u_int64_t sc_cmd_addr; + + LIST_HEAD(,sbp2_cmdorb) sc_cmdorbs; +}; + +#define SC_DEVNAME(sc) (sc->sc_node_dev.sc_device.dv_xname) +#define SC_FWNODE(sc) (sc->sc_node_dev.sc_fwnode) +#define SC_INREG(sc) (*sc->sc_node_dev.sc_fwnode->sc1394_inreg) +#define SC_WRITE(sc) (*sc->sc_node_dev.sc_fwnode->sc1394_write) + +#define SBP2_MAX_PGS 8 /* XXX I just made this up */ + /* XXX 64k * 8 == 0.5 MB */ + +struct sbp2_cmdorb { + struct fwscsi_softc *sco_sc; + struct scsipi_xfer *sco_xs; + u_int64_t sco_cmd_addr; + u_int64_t sco_data_addr; + size_t sco_data_len; + struct cmd_orb sco_orb; + struct sbp2_pte_u sco_page[SBP2_MAX_PGS]; + struct ieee1394_abuf sco_ccb_req; + struct ieee1394_abuf sco_ccb_resp; + + /* XXX need to support `sco_num_data' if we want to + * read/write larger then 64K */ + + /* int sco_num_data; */ + struct ieee1394_abuf sco_data_req; /* [SBP2_MAX_PGS] */ + struct ieee1394_abuf sco_data_resp; /* [SBP2_MAX_PGS] */ +#define SBP2_MAX_BUFSIZE (64 * 1024) /* XXX fix with page table */ + + size_t sco_scsi_cmd_len; + int sco_flags; +#define SCO_INUSE 0x01 +#define SCO_LISTENING 0x02 +#define SCO_SENT 0x04 + LIST_ENTRY(sbp2_cmdorb) sco_requests; }; struct cfattach fwscsi_ca = { sizeof(struct fwscsi_softc), fwscsi_match, fwscsi_attach, fwscsi_detach }; -/* Place holders for the moment. */ - static int fwscsi_match(struct device *parent, struct cfdata *match, void *aux) { + + struct fwnode_match_arg *fma = (struct fwnode_match_arg *)aux; + + if ((fma->fwma_valid & (FWMA_SPEC_ID|FWMA_SW_VERSION)) == (FWMA_SPEC_ID|FWMA_SW_VERSION)) + if (fma->fwma_spec_id == SBP2_UNIT_SPEC_ID && + fma->fwma_sw_version == SBP2_UNIT_SW_VERSION) + return 1; + return 0; } static void fwscsi_attach(struct device *parent, struct device *self, void *aux) { + + struct fwnode_match_arg *fma = (struct fwnode_match_arg *)aux; + struct fwscsi_softc *sc = (struct fwscsi_softc *) self; + struct configrom_data *data; + + sc->sc_node_dev.sc_fwnode = fma->fwma_fwnode; + + sc->sc_spec_id = fma->fwma_spec_id; + sc->sc_sw_ver = fma->fwma_sw_version; + + sc->sc_state = SBP2_ATTACH; + + sc->sc_scsidev = NULL; + LIST_INIT(&sc->sc_cmdorbs); + + sc->sc_cmds = extent_create("sbp2cmd", 0x4000000, 0x4004000, + M_1394DATA, NULL, 0, EX_NOWAIT|EX_NOCOALESCE); + if (sc->sc_cmds == NULL) + panic("%s: failed to allocated command extent", + SC_DEVNAME(sc)); + + sc->sc_datas = extent_create("sbp2data", 0x8000000, 0x8080000, + M_1394DATA, NULL, 0, EX_NOWAIT|EX_NOCOALESCE); + if (sc->sc_datas == NULL) + panic("%s: failed to allocated data extent", + SC_DEVNAME(sc)); + + sc->sc_reconnect_timeout = 0; + sc->sc_fw_ver = 0; + sc->sc_cmd_set = 0; /* SCSI2 == 0x104d8 */ + sc->sc_uniq_id = 0; + sc->sc_unit_char= 0; + + sc->sc_lun = 0; + sc->sc_mgt_addr = 0; + + sc->sc_cmd_addr = 0; + +#define SBP2_MATCH(d,key,var) \ + case SBP2_KEYVALUE_##key: sc->sc_##var = (d)->val ; break + + TAILQ_FOREACH(data, &fma->fwma_dir->data_root, data) { + switch(data->key_value) { + SBP2_MATCH(data, Reconnect_Timeout, reconnect_timeout); + SBP2_MATCH(data, Firmware_Revision, fw_ver); + SBP2_MATCH(data, Command_Set, cmd_set); + SBP2_MATCH(data, Unit_Unique_Id, uniq_id); + SBP2_MATCH(data, Unit_Characteristics, unit_char); + SBP2_MATCH(data, Command_Set_Revision, cmd_set_rev); + SBP2_MATCH(data, Command_Set_Spec_Id, cmd_set_spec_id); + + case P1212_KEYVALUE_Unit_Dependent_Info: + switch(data->key_type) { + case P1212_KEYTYPE_Immediate: + sc->sc_lun = data->val; + break; + case P1212_KEYTYPE_Offset: + sc->sc_mgt_addr = data->val; + break; + } + } + } + + printf(": SPB2"); + if (sc->sc_cmd_set == 0x104d8) { + printf(" SCSI2"); + } else { + printf(" %x", sc->sc_cmd_set); + sc->sc_state = SBP2_INVALID_DIR; + } + printf(" device\n"); + + printf("%s:", SC_DEVNAME(sc)); + if (fma->fwma_valid & FWMA_TEXT_DESC) + printf(" %s", fma->fwma_text_desc); + if (sc->sc_fw_ver) + printf(" fw rev: %x", sc->sc_fw_ver); + printf("\n"); + + if (sc->sc_mgt_addr == 0) + sc->sc_state = SBP2_INVALID_DIR; + + if (sc->sc_state == SBP2_INVALID_DIR) + printf("%s: doesn't attach due to invalid rom\n", + SC_DEVNAME(sc)); + else + sbp2_init(sc); } static int fwscsi_detach(struct device *self, int flags) { + + struct fwscsi_softc *sc = (struct fwscsi_softc *) self; + + sbp2_kill_orbs(sc); + + if (sc->sc_scsidev) + config_detach(sc->sc_scsidev, flags); + + if (sc->sc_cmds) + extent_destroy(sc->sc_cmds); + if (sc->sc_datas) + extent_destroy(sc->sc_datas); + return 0; +} + + +static void +sbp2_init(struct fwscsi_softc *sc) +{ + + struct ieee1394_abuf *ab, *ab2; + + sc->sc_state = SBP2_LOGIN; + + ab = malloc(sizeof(struct ieee1394_abuf), M_1394DATA, M_WAITOK); + memset(ab, 0, sizeof(struct ieee1394_abuf)); + ab->ab_data = malloc(8, M_1394DATA, M_WAITOK); + memset(ab->ab_data, 0, 8); + ab2 = malloc(sizeof(struct ieee1394_abuf), M_1394DATA, M_WAITOK); + memset(ab2, 0, sizeof(struct ieee1394_abuf)); + + ab->ab_length = 8; + ab->ab_req = (struct ieee1394_softc *)SC_FWNODE(sc); + ab->ab_retlen = 0; + ab->ab_cb = NULL; + ab->ab_cbarg = NULL; + ab->ab_csr = CSR_BASE + sc->sc_mgt_addr * 4; + ab->ab_data[0] = htonl(0x4000); + ab->ab_data[1] = 0; + ab->ab_tcode = IEEE1394_TCODE_WRITE_REQ_BLOCK; + + ab2->ab_length = 32; + ab2->ab_tcode = IEEE1394_TCODE_READ_REQ_BLOCK; + ab2->ab_retlen = 0; + ab2->ab_data = NULL; + ab2->ab_csr = 0x0000400000000000; + ab2->ab_cb = sbp2_login; + ab2->ab_cbarg = sc; + ab2->ab_req = (struct ieee1394_softc *)SC_FWNODE(sc); + + SC_INREG(sc)(ab2, 0); + SC_WRITE(sc)(ab); + + return; +} + +static void +sbp2_login(struct ieee1394_abuf *ab, int rcode) +{ + + struct fwscsi_softc *sc = ab->ab_cbarg; + struct ieee1394_abuf *statab, *respab; + + /* Got a read so allocate the buffer and write out the response. */ + + if (rcode) { + printf ("%s: sbp2_login: bad return code: %d\n", + SC_DEVNAME(sc), rcode); + sc->sc_state = SBP2_DETACHED; + if (ab->ab_data) + free (ab->ab_data, M_1394DATA); + free(ab, M_1394DATA); + } + + ab->ab_data = malloc(32, M_1394DATA, M_WAITOK); + respab = malloc(sizeof(struct ieee1394_abuf), M_1394DATA, M_WAITOK); + statab = malloc(sizeof(struct ieee1394_abuf), M_1394DATA, M_WAITOK); + memset(respab, 0, sizeof(struct ieee1394_abuf)); + memset(statab, 0, sizeof(struct ieee1394_abuf)); + + /* fifo */ + statab->ab_length = 32; + statab->ab_tcode = IEEE1394_TCODE_WRITE_REQ_BLOCK; + statab->ab_retlen = 0; + statab->ab_data = NULL; + statab->ab_csr = 0x0000400000000030; + statab->ab_cb = sbp2_fifo; + statab->ab_cbarg = ab->ab_cbarg; + statab->ab_req = ab->ab_req; + + SC_INREG(sc)(statab, 1); + + respab->ab_length = 16; + respab->ab_tcode = IEEE1394_TCODE_WRITE_REQ_BLOCK; + respab->ab_retlen = 0; + respab->ab_data = NULL; + respab->ab_csr = 0x0000400000000020; + respab->ab_cb = sbp2_login_resp; + respab->ab_cbarg = ab->ab_cbarg; + respab->ab_req = ab->ab_req; + + SC_INREG(sc)(respab, 1); + + memset(ab->ab_data, 0, 32); + ab->ab_data[2] = htonl(0x4000); /* login resp hi */ + ab->ab_data[3] = htonl(0x20); /* login resp lo */ + ab->ab_data[4] = htonl(0x90000000); /* notify + exclusive */ + ab->ab_data[5] = htonl(0x00000010); /* login resp length */ + ab->ab_data[6] = htonl(0x4000); /* status fifo hi */ + ab->ab_data[7] = htonl(0x30); /* status fifo lo */ + ab->ab_retlen = 0; + ab->ab_cb = NULL; + ab->ab_cbarg = NULL; + ab->ab_tcode = IEEE1394_TCODE_READ_RESP_BLOCK; + ab->ab_length = 32; + + SC_WRITE(sc)(ab); +} + +static void +sbp2_login_resp(struct ieee1394_abuf *ab, int rcode) +{ + + struct fwscsi_softc *sc = ab->ab_cbarg; + + if (rcode) { + printf("%s: bad login response: %d\n", + SC_DEVNAME(sc), rcode); + sc->sc_state = SBP2_DETACHED; + if (ab->ab_data) + free(ab->ab_data, M_1394DATA); + free(ab, M_1394DATA); + } + + printf("csr: 0x%016qx\n", ab->ab_csr); + + /* login response */ + if (ab->ab_csr == 0x0000400000000020) { + if (ab->ab_retlen < 3 * 4) { + sc->sc_state = SBP2_DETACHED; + goto done; + } + sc->sc_login_id = ntohl(ab->ab_data[0]) & 0xffff; + sc->sc_cmd_addr = + ((int64_t)(ntohl(ab->ab_data[1]) & 0xffff)) << 32 | + (ntohl(ab->ab_data[2]) & ~0x3); + DPRINTF(("login response\n")); + DPRINTF((" login id: 0x%04x\n", sc->sc_login_id)); + DPRINTF((" cmd addr: 0x%016qx\n", sc->sc_cmd_addr)); + + sbp2_target_reset(sc); + + DPRINTF(("%s: creating thread for scsi attach\n", + SC_DEVNAME(sc))); + + /* + * We can't run the scsi attach in the fw event thread + * since we need to handle fifo request to complete + * orbs. + */ + + kthread_create(sbp2_attach_thread, sc); + } +#ifdef FWSCSI_DEBUG + { + int i; + for (i = 0; i < (ab->ab_retlen / 4); i++) + printf("%d: 0x%08x\n", i, ntohl(ab->ab_data[i])); + } +#endif + + done: + free(ab->ab_data, M_1394DATA); + free(ab, M_1394DATA); +} + + +static void +sbp2_attach_thread(void *arg) +{ + struct fwscsi_softc *sc = arg; + + if (kthread_create1(sbp2_attach_scsi, sc, + &sc->sc_attach_thread, "%s-attach", SC_DEVNAME(sc))) { + printf("%s: unable to create attach thread", SC_DEVNAME(sc)); + panic("sbp2_attach_thread"); + } +} + + + +static void +sbp2_fifo(struct ieee1394_abuf *ab, int rcode) +{ + + struct fwscsi_softc *sc = ab->ab_cbarg; + struct sbp2_cmdorb *cmd; + struct scsipi_xfer *xs; + struct sbp2_status_block status; + + DPRINTF(("%s: sbp2_fifo\n", SC_DEVNAME(sc))); + if (rcode) { + printf("%s: bad fifo request: %d\n", SC_DEVNAME(sc), rcode); + goto done; + } + +#ifdef FWSCSI_DEBUG + printf("csr: 0x%016qx len: %d\n", ab->ab_csr, ab->ab_retlen); + { + int i; + for (i = 0; i < (ab->ab_retlen / 4); i++) + printf("%d: 0x%08x\n", i, ntohl(ab->ab_data[i])); + } +#endif + + if (ab->ab_retlen > sizeof(status)) { + printf("%s: got oversized fifo packet\n", + SC_DEVNAME(sc)); + goto done; + } + if (ab->ab_retlen < 8) { + printf("%s: got undersized fifo packet\n", + SC_DEVNAME(sc)); + goto done; + } + + memset(&status, 0, sizeof(status)); + memcpy(&status, ab->ab_data, ab->ab_retlen); + + /* find the request and mark it done */ + + LIST_FOREACH(cmd, &sc->sc_cmdorbs, sco_requests) { + if (cmd->sco_cmd_addr == + (((u_int64_t)(status.orb_offset_hi_misc & 0xffff)) << 32 | + status.orb_offset_lo)) { + break; + } + } + if (cmd == NULL) { + printf("%s: got unknown or unsolisited request\n", + SC_DEVNAME(sc)); + goto done; + } + xs = cmd->sco_xs; + + sbp2_free_orb(cmd); + scsipi_done(xs); + + done: + if (ab->ab_data) + free(ab->ab_data, M_1394DATA); + free(ab, M_1394DATA); +} + + +static void +sbp2_free_orb(struct sbp2_cmdorb *sco) +{ + + struct fwscsi_softc *sc = sco->sco_sc; + + DPRINTF(("%s: sbp2_free_orb: orb: %p\n", SC_DEVNAME(sc), sco)) + + LIST_REMOVE(sco, sco_requests); + +#ifdef DIAGNOSTIC + if ((sco->sco_flags & SCO_INUSE) == 0) + panic("sbp2_free_orb: orb already free"); +#endif + sco->sco_flags &= ~SCO_INUSE; + + callout_stop(&sco->sco_xs->xs_callout); + + /* deregister the area */ + sco->sco_ccb_req.ab_cb = NULL; + SC_INREG(sco->sco_sc)(&sco->sco_ccb_req, 0); + sco->sco_data_req.ab_cb = NULL; + SC_INREG(sco->sco_sc)(&sco->sco_data_req, 0); + + /* XXX */ + extent_free(sc->sc_cmds, sco->sco_cmd_addr, + 0x50, EX_NOWAIT); + extent_free(sc->sc_datas, sco->sco_data_addr, + SBP2_MAX_BUFSIZE, EX_NOWAIT); + + free(sco, M_1394DATA); +} + +static void +sbp2_cmd_req(struct ieee1394_abuf *ab, int rcode) +{ + + struct sbp2_cmdorb *sco = (void *)ab->ab_cbarg; + + DPRINTF(("%s: cmd_req rcode: %d\n", + SC_DEVNAME(sco->sco_sc), rcode)); + + if (rcode) + sbp2_free_orb(sco); + else + SC_WRITE(sco->sco_sc)(&sco->sco_ccb_resp); +} + +void +sbp2_data_req(struct ieee1394_abuf *ab, int rcode) +{ + + struct sbp2_cmdorb *sco = (void *)ab->ab_cbarg; + + DPRINTF(("%s: data_req rcode: %d\n", + SC_DEVNAME(sco->sco_sc), rcode)); + + if (rcode) + sbp2_free_orb(sco); + else + SC_WRITE(sco->sco_sc)(&sco->sco_data_resp); +} + +static void +sbp2_data_sent(struct ieee1394_abuf *ab, int rcode) +{ + DPRINTF(("%s: data_sent rcode: %d\n", + (char *)ab->ab_cbarg, rcode)); + if (ab->ab_data) + free(ab->ab_data, M_1394DATA); + free(ab, M_1394DATA); +} + +static void +sbp2_orb_sent(struct ieee1394_abuf *ab, int rcode) +{ + struct sbp2_cmdorb *sco = (void *)ab->ab_cbarg; + + DPRINTF(("%s: orb_sent rcode: %d\n", + SC_DEVNAME(sco->sco_sc), rcode)); + + /* XXX when to free data ? */ + if (rcode) + sbp2_free_orb(sco); + +} + +static struct sbp2_cmdorb * +sbp2_get_cmdorb(struct fwscsi_softc *sc) +{ + + struct sbp2_cmdorb *sco; + struct ieee1394_softc *pdev; + u_long cmd_addr, data_addr; + int error; + + DPRINTF(("%s: get_cmd_orb\n", SC_DEVNAME(sc))); + + /* XXX make it a pool */ + if ((sco = malloc(sizeof(*sco), M_1394DATA, M_WAITOK)) == NULL) + return NULL; + + DPRINTF(("%s: get_cmd_orb: %p\n", SC_DEVNAME(sc), sco)); + + error = extent_alloc(sc->sc_cmds, 0x50, /* XXX */ + 4, 0, EX_FAST, &cmd_addr); + KASSERT(error == 0); + error = extent_alloc(sc->sc_datas, SBP2_MAX_BUFSIZE, /* XXX */ + 4, 0, EX_FAST, &data_addr); + + memset(sco, 0, sizeof(*sco)); + + sco->sco_sc = sc; + + sco->sco_cmd_addr = cmd_addr; + sco->sco_data_addr = data_addr; + sco->sco_data_len = 0; + + sco->sco_orb.next_orb_hi = 0xffffffff; + sco->sco_orb.next_orb_lo = 0xffffffff; + + pdev = (void *)((struct device *)SC_FWNODE(sc))->dv_parent; + + sco->sco_orb.data_desc_hi = (ntohs(pdev->sc1394_node_id) & 0xffff) << 16; + sco->sco_orb.data_desc_hi = htonl(data_addr); + + sco->sco_ccb_req.ab_req = (struct ieee1394_softc *)SC_FWNODE(sc); + sco->sco_ccb_req.ab_data = NULL; + sco->sco_ccb_req.ab_length = 0; + sco->sco_ccb_req.ab_csr = cmd_addr; + sco->sco_ccb_req.ab_retlen = 0; + sco->sco_ccb_req.ab_cb = sbp2_cmd_req; + sco->sco_ccb_req.ab_cbarg = sco; + sco->sco_ccb_req.ab_tcode = IEEE1394_TCODE_READ_REQ_BLOCK; + + sco->sco_ccb_resp.ab_req = (struct ieee1394_softc *)SC_FWNODE(sc); + sco->sco_ccb_resp.ab_data = (void *)&sco->sco_orb; + sco->sco_ccb_resp.ab_length = sizeof(sco->sco_orb); + sco->sco_ccb_resp.ab_csr = cmd_addr; + sco->sco_ccb_resp.ab_retlen = 0; + sco->sco_ccb_resp.ab_cb = sbp2_orb_sent; + sco->sco_ccb_resp.ab_cbarg = sco; + sco->sco_ccb_resp.ab_tcode = IEEE1394_TCODE_READ_RESP_BLOCK; + + sco->sco_data_req.ab_req = (struct ieee1394_softc *)SC_FWNODE(sc); + sco->sco_data_req.ab_data = NULL; + sco->sco_data_req.ab_length = 0; + sco->sco_data_req.ab_csr = data_addr; + sco->sco_data_req.ab_retlen = 0; + sco->sco_data_req.ab_cb = sbp2_data_req; + sco->sco_data_req.ab_cbarg = sco; + + sco->sco_data_resp.ab_req = (struct ieee1394_softc *)SC_FWNODE(sc); + sco->sco_data_resp.ab_data = (void *)&sco->sco_orb; + sco->sco_data_resp.ab_length = sizeof(sco->sco_orb); + sco->sco_data_resp.ab_csr = data_addr; + sco->sco_data_resp.ab_retlen = 0; + sco->sco_data_resp.ab_cb = sbp2_orb_sent; + sco->sco_data_resp.ab_cbarg = sco; + + sco->sco_flags |= SCO_INUSE; + + SC_INREG(sc)(&sco->sco_ccb_req, 0); + SC_INREG(sc)(&sco->sco_data_req, 0); /* XXX move to later */ + + return sco; +} + + +static void +sbp2_scsipi_request(struct scsipi_channel *chan, + scsipi_adapter_req_t req, + void *arg) +{ + + struct scsipi_xfer *xs; + struct scsipi_periph *periph; + struct fwscsi_softc *sc = (void *)chan->chan_adapter->adapt_dev; + struct sbp2_cmdorb *sco; + u_int32_t misc; + int flags; + + switch (req) { + case ADAPTER_REQ_RUN_XFER: + xs = arg; + periph = xs->xs_periph; + flags = xs->xs_control; + + periph->periph_dbflags = SCSIPI_DEBUG_FLAGS; + + if (flags & XS_CTL_RESET) { + DPRINTF(("%s: scsipi req: reset\n", SC_DEVNAME(sc))); + + sbp2_target_reset(sc); + xs->error = XS_NOERROR; + scsipi_done(xs); + return; + } + + DPRINTF(("%s: scsipi req: data %d\n", + SC_DEVNAME(sc), xs->datalen)); + + misc = CMD_ORB_MISC_NOTIFY|CMD_ORB_MISC_SPEED_512; + + sco = sbp2_get_cmdorb(sc); + sco->sco_xs = xs; + + /* + * Put all the arguments for the xfer in the ccb + */ + memcpy(&sco->sco_orb.cmd_block, xs->cmd, + sco->sco_scsi_cmd_len = xs->cmdlen); + + if (xs->datalen) { + if (flags & XS_CTL_DATA_UIO) + panic("%s: no uio", SC_DEVNAME(sc)); + + if (flags & XS_CTL_DATA_IN) { + sco->sco_data_resp.ab_tcode = + IEEE1394_TCODE_WRITE_REQ_BLOCK; + sco->sco_data_resp.ab_data = (void *)xs->data; + sco->sco_data_resp.ab_length = xs->datalen; + misc |= CMD_ORB_MISC_DIR_WRITE; + } else { + sco->sco_data_resp.ab_tcode = + IEEE1394_TCODE_READ_RESP_BLOCK; + sco->sco_data_req.ab_data = (void *)xs->data; + sco->sco_data_req.ab_length = xs->datalen; + } + + misc |= xs->datalen & 0xffff; + KASSERT((xs->datalen & ~0xffff) == 0); + } else { + /* XXX don't register memory */ + sco->sco_data_resp.ab_length = 0; + sco->sco_data_req.ab_length = 0; + } + + sco->sco_orb.misc = htonl(misc); + + sbp2_send_orb(sco); + + /* command sent */ + if ((flags & XS_CTL_POLL) == 0) + return; + + /* wait for completion */ + return; + + case ADAPTER_REQ_GROW_RESOURCES: + case ADAPTER_REQ_SET_XFER_MODE: + DPRINTF(("%s: got a scsipi request\n", SC_DEVNAME(sc))); + return; + } +} + +static void +sbp2_attach_scsi(void *ptr) +{ + + struct fwscsi_softc *sc = ptr; + struct scsipi_adapter *adapt = &sc->sc_adapter; + struct scsipi_channel *chan = &sc->sc_channel; + + printf("%s: attaching scsi devices\n", SC_DEVNAME(sc)); + + memset(adapt, 0, sizeof(*adapt)); + adapt->adapt_dev = &sc->sc_node_dev.sc_device; + adapt->adapt_nchannels = 1; + adapt->adapt_openings = 1; + adapt->adapt_max_periph = 1; + adapt->adapt_request = sbp2_scsipi_request; + adapt->adapt_minphys = sbp2_minphys; + adapt->adapt_ioctl = sbp2_ioctl; + + /* + * Fill in the scsipi_channel. + */ + memset(chan, 0, sizeof(*chan)); + chan->chan_adapter = adapt; + chan->chan_bustype = &scsi_bustype; + chan->chan_channel = 0; + chan->chan_ntargets = 1; /* XXX */ + chan->chan_nluns = 8; /* XXX */ + chan->chan_id = 7; /* XXX */ + chan->chan_defquirks = PQUIRK_ONLYBIG; + + /* + * ask the adapter + */ + sc->sc_scsidev = + config_found(&sc->sc_node_dev.sc_device, + &sc->sc_channel, scsiprint); + + sc->sc_state = SBP2_ATTACHED; + + kthread_exit(0); +} + +static void +sbp2_kill_orbs(struct fwscsi_softc *sc) +{ + struct sbp2_cmdorb *sco; + struct scsipi_xfer *xs; + + DPRINTF(("%s: sbp2_kill_orbs\n", SC_DEVNAME(sc))); + + while (LIST_FIRST(&sc->sc_cmdorbs) != NULL) { + sco = LIST_FIRST(&sc->sc_cmdorbs); + xs = sco->sco_xs; + sbp2_free_orb(sco); + + xs->error = XS_SELTIMEOUT; + scsipi_done(xs); + } +} + +static void +sbp2_timeout(void *ptr) +{ + struct sbp2_cmdorb *sco = ptr; + struct scsipi_xfer *xs = sco->sco_xs; + + DPRINTF(("%s: timeout orb: %p\n", SC_DEVNAME(sco->sco_sc), sco)); + + xs->error = XS_TIMEOUT; + + sbp2_free_orb(sco); + scsipi_done(xs); +} + + +static void +sbp2_target_reset(struct fwscsi_softc *sc) +{ + struct ieee1394_abuf *ab; + + DPRINTF(("%s: resetting target\n", SC_DEVNAME(sc))); + + ab = malloc(sizeof(*ab), M_1394DATA, M_WAITOK); + memset(ab, 0, sizeof(*ab)); + ab->ab_data = malloc(4, M_1394DATA, M_WAITOK); + + ab->ab_length = 4; + ab->ab_data[0] = htonl(0xf); + ab->ab_tcode = IEEE1394_TCODE_WRITE_REQ_QUAD; + ab->ab_retlen = 0; + ab->ab_csr = sc->sc_cmd_addr + 0x4; /* reset offset */ + ab->ab_cb = sbp2_data_sent; + ab->ab_cbarg = "target reset"; + ab->ab_req = (struct ieee1394_softc *)SC_FWNODE(sc); + + SC_WRITE(sc)(ab); +} + + +static void +sbp2_send_orb(struct sbp2_cmdorb *sco) +{ + + struct fwscsi_softc *sc = sco->sco_sc; + struct scsipi_xfer *xs = sco->sco_xs; + struct ieee1394_softc *pdev; + struct ieee1394_abuf *ab; + + DPRINTF(("%s: sending orb: %p\n", SC_DEVNAME(sc), sco)); + + /* XXX verify correntness of the request */ + sco->sco_flags |= SCO_SENT; + + LIST_INSERT_HEAD(&sc->sc_cmdorbs, sco, sco_requests); + + if ((xs->xs_control & XS_CTL_POLL) == 0) + callout_reset(&xs->xs_callout, (xs->timeout * hz) / 10000, + sbp2_timeout, sco); + /* + * XXX + * + * write the orb to the orb csr, or + * hook in onto the orb chain, or + * wait until the older orbs are done and issue a orb csr req + */ + + pdev = (void *)((struct device *)SC_FWNODE(sc))->dv_parent; + + ab = malloc(sizeof(*ab), M_1394DATA, M_WAITOK); + memset(ab, 0, sizeof(*ab)); + ab->ab_data = malloc(8, M_1394DATA, M_WAITOK); + + ab->ab_length = 8; + ab->ab_data[0] = (ntohs(pdev->sc1394_node_id) & 0xffff) << 16; + ab->ab_data[0] |= (sco->sco_cmd_addr >> 32) & 0xffff; + ab->ab_data[0] = htonl(ab->ab_data[0]); + ab->ab_data[1] = htonl(sco->sco_cmd_addr & 0xffffffff); + ab->ab_tcode = IEEE1394_TCODE_WRITE_REQ_BLOCK; + ab->ab_retlen = 0; + ab->ab_csr = sc->sc_cmd_addr + 0x8; /* orb pointer offset */ + ab->ab_cb = sbp2_data_sent; + ab->ab_cbarg = "orb pointer"; + ab->ab_req = (struct ieee1394_softc *)SC_FWNODE(sc); + + SC_WRITE(sc)(ab); + + /* XXX wait here if polling */ +} + + +static void +sbp2_minphys(struct buf *bp) +{ + + if (bp->b_bcount > SBP2_MAX_BUFSIZE) /* XXX is this right ? */ + bp->b_bcount = SBP2_MAX_BUFSIZE; +} + +static int +sbp2_ioctl(struct scsipi_channel *channel, u_long cmd, caddr_t data, int flag, + struct proc *p) +{ + + /* XXX here for debugging */ + struct fwscsi_softc *sc = (void *)channel->chan_adapter->adapt_dev; + int ret = ENOTTY; + + switch (cmd) { + case SCBUSIORESET: + DPRINTF(("%s: SCBUSIORESET\n", SC_DEVNAME(sc))); + break; + case SCBUSIOLLSCAN: + DPRINTF(("%s: SCBUSIORESET\n", SC_DEVNAME(sc))); + break; + default: + DPRINTF(("%s: ioctl\n", SC_DEVNAME(sc))); + break; + } + + return ret; } Index: ieee1394/fwscsireg.h =================================================================== RCS file: fwscsireg.h diff -N fwscsireg.h --- /dev/null Sun May 20 17:40:04 2001 +++ fwscsireg.h Wed Jan 9 04:26:42 2002 @@ -0,0 +1,26 @@ + + +struct cmd_orb { + u_int32_t next_orb_hi; + u_int32_t next_orb_lo; + u_int32_t data_desc_hi; + u_int32_t data_desc_lo; + u_int32_t misc; + u_char cmd_block[12]; /* XXX */ +}; + +#define CMD_ORB_MISC_NOTIFY 0x80000000 +#define CMD_ORB_MISC_DIR_WRITE 0x08000000 /* target dir */ +#define CMD_ORB_MISC_SPEED(x) ((x & 0xf) << 20) +#define CMD_ORB_MISC_SPEED_512 CMD_ORB_MISC_SPEED(7) + +struct sbp2_pg { + u_int32_t seg_len_hi; + u_int32_t seg_lo; +}; + +struct sbp2_status_block { + u_int32_t orb_offset_hi_misc; + u_int32_t orb_offset_lo; + u_char cmd_set_dep[24]; +}; Index: ieee1394/ieee1394var.h =================================================================== RCS file: /cvsroot/syssrc/sys/dev/ieee1394/ieee1394var.h,v retrieving revision 1.13 diff -w -u -r1.13 ieee1394var.h --- ieee1394var.h 2001/07/18 02:59:54 1.13 +++ ieee1394var.h 2002/01/09 12:26:42 @@ -80,6 +80,7 @@ struct ieee1394_softc { struct device sc1394_dev; struct device *sc1394_if; /* Move to fwohci level. */ + struct device *sc1394_ctl; const struct ieee1394_callbacks sc1394_callback; /* Nuke probably. */ u_int32_t *sc1394_configrom;