static int qib_diag_open(struct inode *in, struct file *fp) { int unit = iminor(in) - QIB_DIAG_MINOR_BASE; struct qib_devdata *dd; struct qib_diag_client *dc; int ret; mutex_lock(&qib_mutex); dd = qib_lookup(unit); if (dd == NULL || !(dd->flags & QIB_PRESENT) || !dd->kregbase) { ret = -ENODEV; goto bail; } dc = get_client(dd); if (!dc) { ret = -ENOMEM; goto bail; } dc->next = dd->diag_client; dd->diag_client = dc; fp->private_data = dc; ret = 0; bail: mutex_unlock(&qib_mutex); return ret; }
/** * qib_get_eeprom_info- get the GUID et al. from the TSWI EEPROM device * @dd: the qlogic_ib device * * We have the capability to use the nguid field, and get * the guid from the first chip's flash, to use for all of them. */ void qib_get_eeprom_info(struct qib_devdata *dd) { void *buf; struct qib_flash *ifp; __be64 guid; int len, eep_stat; u8 csum, *bguid; int t = dd->unit; struct qib_devdata *dd0 = qib_lookup(0); if (t && dd0->nguid > 1 && t <= dd0->nguid) { u8 oguid; dd->base_guid = dd0->base_guid; bguid = (u8 *) &dd->base_guid; oguid = bguid[7]; bguid[7] += t; if (oguid > bguid[7]) { if (bguid[6] == 0xff) { if (bguid[5] == 0xff) { qib_dev_err(dd, "Can't set %s GUID" " from base, wraps to" " OUI!\n", qib_get_unit_name(t)); dd->base_guid = 0; goto bail; } bguid[5]++; } bguid[6]++; } dd->nguid = 1; goto bail; } /* * Read full flash, not just currently used part, since it may have * been written with a newer definition. * */ len = sizeof(struct qib_flash); buf = vmalloc(len); if (!buf) { qib_dev_err(dd, "Couldn't allocate memory to read %u " "bytes from eeprom for GUID\n", len); goto bail; } /* * Use "public" eeprom read function, which does locking and * figures out device. This will migrate to chip-specific. */ eep_stat = qib_eeprom_read(dd, 0, buf, len); if (eep_stat) { qib_dev_err(dd, "Failed reading GUID from eeprom\n"); goto done; } ifp = (struct qib_flash *)buf; csum = flash_csum(ifp, 0); if (csum != ifp->if_csum) { qib_devinfo(dd->pcidev, "Bad I2C flash checksum: " "0x%x, not 0x%x\n", csum, ifp->if_csum); goto done; } if (*(__be64 *) ifp->if_guid == cpu_to_be64(0) || *(__be64 *) ifp->if_guid == ~cpu_to_be64(0)) { qib_dev_err(dd, "Invalid GUID %llx from flash; ignoring\n", *(unsigned long long *) ifp->if_guid); /* don't allow GUID if all 0 or all 1's */ goto done; } /* complain, but allow it */ if (*(u64 *) ifp->if_guid == 0x100007511000000ULL) qib_devinfo(dd->pcidev, "Warning, GUID %llx is " "default, probably not correct!\n", *(unsigned long long *) ifp->if_guid); bguid = ifp->if_guid; if (!bguid[0] && !bguid[1] && !bguid[2]) { /* * Original incorrect GUID format in flash; fix in * core copy, by shifting up 2 octets; don't need to * change top octet, since both it and shifted are 0. */ bguid[1] = bguid[3]; bguid[2] = bguid[4]; bguid[3] = 0; bguid[4] = 0; guid = *(__be64 *) ifp->if_guid; } else guid = *(__be64 *) ifp->if_guid; dd->base_guid = guid; dd->nguid = ifp->if_numguid; /* * Things are slightly complicated by the desire to transparently * support both the Pathscale 10-digit serial number and the QLogic * 13-character version. */ if ((ifp->if_fversion > 1) && ifp->if_sprefix[0] && ((u8 *) ifp->if_sprefix)[0] != 0xFF) { char *snp = dd->serial; /* * This board has a Serial-prefix, which is stored * elsewhere for backward-compatibility. */ memcpy(snp, ifp->if_sprefix, sizeof ifp->if_sprefix); snp[sizeof ifp->if_sprefix] = '\0'; len = strlen(snp); snp += len; len = (sizeof dd->serial) - len; if (len > sizeof ifp->if_serial) len = sizeof ifp->if_serial; memcpy(snp, ifp->if_serial, len); } else memcpy(dd->serial, ifp->if_serial, sizeof ifp->if_serial); if (!strstr(ifp->if_comment, "Tested successfully")) qib_dev_err(dd, "Board SN %s did not pass functional " "test: %s\n", dd->serial, ifp->if_comment); memcpy(&dd->eep_st_errs, &ifp->if_errcntp, QIB_EEP_LOG_CNT); /* * Power-on (actually "active") hours are kept as little-endian value * in EEPROM, but as seconds in a (possibly as small as 24-bit) * atomic_t while running. */ atomic_set(&dd->active_time, 0); dd->eep_hrs = ifp->if_powerhour[0] | (ifp->if_powerhour[1] << 8); done: vfree(buf); bail:; }
/** * qib_diagpkt_write - write an IB packet * @fp: the diag data device file pointer * @data: qib_diag_pkt structure saying where to get the packet * @count: size of data to write * @off: unused by this code */ static ssize_t qib_diagpkt_write(struct file *fp, const char __user *data, size_t count, loff_t *off) { u32 __iomem *piobuf; u32 plen, pbufn, maxlen_reserve; struct qib_diag_xpkt dp; u32 *tmpbuf = NULL; struct qib_devdata *dd; struct qib_pportdata *ppd; ssize_t ret = 0; if (count != sizeof(dp)) { ret = -EINVAL; goto bail; } if (copy_from_user(&dp, data, sizeof(dp))) { ret = -EFAULT; goto bail; } dd = qib_lookup(dp.unit); if (!dd || !(dd->flags & QIB_PRESENT) || !dd->kregbase) { ret = -ENODEV; goto bail; } if (!(dd->flags & QIB_INITTED)) { /* no hardware, freeze, etc. */ ret = -ENODEV; goto bail; } if (dp.version != _DIAG_XPKT_VERS) { qib_dev_err(dd, "Invalid version %u for diagpkt_write\n", dp.version); ret = -EINVAL; goto bail; } /* send count must be an exact number of dwords */ if (dp.len & 3) { ret = -EINVAL; goto bail; } if (!dp.port || dp.port > dd->num_pports) { ret = -EINVAL; goto bail; } ppd = &dd->pport[dp.port - 1]; /* * need total length before first word written, plus 2 Dwords. One Dword * is for padding so we get the full user data when not aligned on * a word boundary. The other Dword is to make sure we have room for the * ICRC which gets tacked on later. */ maxlen_reserve = 2 * sizeof(u32); if (dp.len > ppd->ibmaxlen - maxlen_reserve) { ret = -EINVAL; goto bail; } plen = sizeof(u32) + dp.len; tmpbuf = vmalloc(plen); if (!tmpbuf) { ret = -ENOMEM; goto bail; } if (copy_from_user(tmpbuf, u64_to_user_ptr(dp.data), dp.len)) { ret = -EFAULT; goto bail; } plen >>= 2; /* in dwords */ if (dp.pbc_wd == 0) dp.pbc_wd = plen; piobuf = dd->f_getsendbuf(ppd, dp.pbc_wd, &pbufn); if (!piobuf) { ret = -EBUSY; goto bail; } /* disarm it just to be extra sure */ dd->f_sendctrl(dd->pport, QIB_SENDCTRL_DISARM_BUF(pbufn)); /* disable header check on pbufn for this packet */ dd->f_txchk_change(dd, pbufn, 1, TXCHK_CHG_TYPE_DIS1, NULL); writeq(dp.pbc_wd, piobuf); /* * Copy all but the trigger word, then flush, so it's written * to chip before trigger word, then write trigger word, then * flush again, so packet is sent. */ if (dd->flags & QIB_PIO_FLUSH_WC) { qib_flush_wc(); qib_pio_copy(piobuf + 2, tmpbuf, plen - 1); qib_flush_wc(); __raw_writel(tmpbuf[plen - 1], piobuf + plen + 1); } else qib_pio_copy(piobuf + 2, tmpbuf, plen); if (dd->flags & QIB_USE_SPCL_TRIG) { u32 spcl_off = (pbufn >= dd->piobcnt2k) ? 2047 : 1023; qib_flush_wc(); __raw_writel(0xaebecede, piobuf + spcl_off); } /* * Ensure buffer is written to the chip, then re-enable * header checks (if supported by chip). The txchk * code will ensure seen by chip before returning. */ qib_flush_wc(); qib_sendbuf_done(dd, pbufn); dd->f_txchk_change(dd, pbufn, 1, TXCHK_CHG_TYPE_ENAB1, NULL); ret = sizeof(dp); bail: vfree(tmpbuf); return ret; }