### BUGGY CODE ###

h, w = list(map(int, input().split()))
s = []
for i in range(h):
    s.append(input().strip())

# start, goal の候補
reps = []
for i in range(h):
    for j in range(w):
        if s[i][j] == ".":
            reps.append([i, j])
depths = []
for k in range(len(reps)):
    for l in range(k, len(reps), 1):
        # unvisited: -1, visited: 0, goal: 1
        start = reps[k]
        goal = reps[l]
        visits = [[-1 for i in range(w)] for j in range(h)]
        visits[goal[0]][goal[1]] = 1
        queue = [[reps[k]]]
        depth = 0

        while True:
            clear = False
            tmp_queue = []
            for now in queue.pop(0):
                # 1. まず、ゴールに到着しているか確認する
                # 2-1. していれば、その start, goal の組における最短経路が計算できたので、depths に追加する
                # 2-2. していなければ、自分のいるマスを訪問済みにし、次に進む道の候補を挙げて、それらを queue に突っ込む

                if visits[now[0]][now[1]] == 1:
                    clear = True
                    break
                else:
                    visits[now[0]][now[1]] = 0
                if (now[0] <= (h - 2)):
                    if (s[now[0] + 1][now[1]] == ".") and (visits[now[0] + 1][now[1]] != 0):
                        tmp_queue.append([(now[0] + 1), now[1]])
                if (now[1] <= (w - 2)):
                    if (s[now[0]][now[1] + 1] == ".") and (visits[now[0]][now[1] + 1] != 0):
                        tmp_queue.append([now[0], (now[1] + 1)])
                if (1 <= now[0]):
                    if (s[now[0] - 1][now[1]] == ".") and (visits[now[0] - 1][now[1]] != 0):
                        tmp_queue.append([(now[0] - 1), now[1]])
                if (1 <= now[1]):
                    if (s[now[0]][now[1] - 1] == ".") and (visits[now[0]][now[1] - 1] != 0):
                        tmp_queue.append([now[0], (now[1] - 1)])
            if clear:
                break
            else:
                depth += 1
                queue.append(tmp_queue)
        depths.append(depth)
print(max(depths))


### FIXED CODE ###

from queue import Queue

h, w = list(map(int, input().split()))
s = []
for i in range(h):
    s.append(input().strip())

ans = 0
for i in range(h):
    for j in range(w):
        start = s[i][j]
        if start == "#":
            continue
        else:
            visited = [[False for _ in range(w)] for _ in range(h)]
            visited[i][j] = True
            queue = Queue()
            queue.put((i, j, 0))

            while 0 < queue.qsize():
                now = queue.get()
                ans = max(ans, now[2])

                if (now[0] <= (h - 2)) and (s[now[0] + 1][now[1]] == ".") and not visited[now[0] + 1][now[1]]:
                    queue.put(((now[0] + 1), now[1], (now[2] + 1)))
                    visited[now[0] + 1][now[1]] = True
                if (now[1] <= (w - 2)) and (s[now[0]][now[1] + 1] == ".") and not visited[now[0]][now[1] + 1]:
                    queue.put((now[0], (now[1] + 1), (now[2] + 1)))
                    visited[now[0]][now[1] + 1] = True
                if (1 <= now[0]) and (s[now[0] - 1][now[1]] == ".") and not visited[now[0] - 1][now[1]]:
                    queue.put(((now[0] - 1), now[1], (now[2] + 1)))
                    visited[now[0] - 1][now[1]] = True
                if (1 <= now[1]) and (s[now[0]][now[1] - 1] == ".") and not visited[now[0]][now[1] - 1]:
                    queue.put((now[0], (now[1] - 1), (now[2] + 1)))
                    visited[now[0]][now[1] - 1] = True

print(ans)